Do you have a MOBY XML document and don't know how to make Java objects out of it? Do you want to programmatically create a MOBY XML document without writing the text yourself? Then this page should get you started. Once you've mastered this, you may want to check out how to invoke a service.
There are two main ways to create Java objects out of XML in jMOBY: as described here (generic),
and using classes generated from the Moby Central ontologies by MoSeS.
If you are a service provider, you can use MoSeS because your datatypes are known
and can be checked at compile time, or the simple servlet mechanism
built on the org.biomoby.shared.data
package.
But if you want to deploy an applet or application for end users,
you'll probably want to use the generic classes described here.
For example, the Seahawk applet uses the generic classes described below,
so it never needs to be rebuilt manually as the ontology changes. Nota bene: This package require Java 1.5
You could get the whole jMOBY CVS source, including its library dependencies, or you can simply use the JAR file (~4MB) for the Seahawk client. It is self-contained, and sufficient to do any processing you will require to call MOBY services and MOBY Central.
The 5 main classes in org.biomoby.shared.package
correspond to various parts of the
MOBY's XML representation for service-call XML.
The document as a whole is represented by a MobyContentInstance
, which can come from a variety of sources:
MobyContentInstance contents = MobyDataUtils.fromXMLDocument(new StringBufferInputStream(xmlString));
MobyContentInstance contents = MobyDataUtils.fromXMLDocument(file.toURL().openStream());
MobyContentInstance contents = MobyDataUtils.fromXMLDocument(w3cDocument.getDocumentElement());
The contents may have one or more jobs in it. For a quick way to get all the data instances out in one big bag:
MobyDataObjectSet objects = contents.retrieveObjects();
If you want know what objects corresponded to what requests, you'll need to break down the contents into
its constituent jobs. MobyContentInstance
is a java.util.Map
, with job (a.k.a.
query) IDs as keys, and MobyDataJob
s as values:
Iterator jobIDs = contents.keySet().iterator();
while(jobIDs.hasNext()){
MobyDataJob job = (MobyDataJob) contents.get(jobIDs.next());
}
Once you've got a job object, you can use it two different ways. It is a java.util.Map
, therefore
you can grab named members of the output you're expecting by its "articleName":
MobyDataObject thingIWant = (MobyDataObject) job.get("seq");
Beware though that if the XML isn't as you expected (e.g. member "seq" is a collection (MobyDataObjectSet), not a simple object), you'll
get a ClassCastException here! You may want to enclose this statement in a try block, and give some type of warning.
The second way to get the data from the job is to use one of the convenience methods in the job class that returns all of the members of a certain type (all Collections, all Simples, all primary (Collections + Simples), all secondary parameters, all of the above), e.g.:
// Get all Simples and Collections
MobyDataInstance[] data = job.getPrimaryData();
System.out.println("Job " + job.getID() + " has " + data.length + " data members");
for(int i = 0; i < data.length; i++){
if(data[i] instanceof MobyDataObjectSet){
System.out.println("Member " + data[i].getName() + " is an object set of class " +
((MobyDataObjectSet) data[i]).getDataType().getName());
}
// Otherwise its guaranteed to be a MobyDataObject
else{
System.out.println("Member " + data[i].getName() + " is an object of class " +
((MobyDataObject) data[i]).getDataType().getName());
}
}
You can find out more about the primitive data objects here. An easy way to create primitive object (i.e. Object, Integer, Float, String, DateTime, Boolean) is with the convenience method provided in MobyDataObject:
MobyDataObject primitive = MobyDataObject.createInstanceFromString("Boolean", "true");
MobyDataObject primitive = MobyDataObject.createInstanceFromString("DateTime", "2006-04-20");
MobyDataObject primitive = MobyDataObject.createInstanceFromString("Integer", "234555");
MobyDataObject primitive = MobyDataObject.createInstanceFromString("Float", "2.0e-7");
MobyDataObject primitive = MobyDataObject.createInstanceFromString("Object", "GO:0002183");
MobyDataObject primitive = MobyDataObject.createInstanceFromString("String", "The quick brown fox jumps over the lazy dog.");
Creating complex (i.e. anything other than primitive) objects can be most easily done with the variable-argument
constructor for MobyDataComposite
:
MobyDataType dnaType = DataTypeParser.getDataType("DNASequence");
MobyNamespace giNS = NamespaceParser.getNamespace("NCBI_gi");
MobyDataComposite dnaSeqObj = new MobyDataComposite(dnaType, //type
giNS, // namespace
"123456", //id
"SequenceString", "ATG", //begin (articleName, value) pairs
"Length", "3");
Note that the constructor will automatically turn the value argument into a java.lang.String
if it isn't already, then call the MobyDataObject.createInstanceFromString
shown earlier with the
datatype specified in the ontology (moby:String for SequenceString and moby:Integer for Length).
If the value argument was already a MobyDataObject
this process is avoided,
and the value is used directly or rejected because it is not of the MobyDataType
the ontology
specifies for the named member. You can mix and match java.lang.String
s and MobyDataObject
s
as values in the same constructor:
MobyDataString seqString = new MobyDataString("ATG");
MobyDataComposite dnaSeqObj = new MobyDataComposite(dnaType, giNS, "123456",
"SequenceString", seqString,
"Length", "3");
If a MOBY object has only one member (e.g. FASTA has only one member, "contents"), you can specify a one argument to the constructor (it can fill in the member's name and data type automatically):
MobyDataType fastaType = DataTypeParser.getDataType("FASTA");
MobyNamespace giNS = NamespaceParser.getNamespace("NCBI_gi");
MobyDataComposite fastaObj = new MobyDataComposite(fastaType, giNS, "123456", ">gi|123456 my favorite sequence\nATG\n");
If the object's datatype specifies a HAS (i.e. one or more) relationship for a member, the value list is
terminated by a null
argument:
MobyDataType identType = DataTypeParser.getDataType("Identification");
// ...define MobyDataComposites "taxon1", "taxon2"
MobyDataComposite complex = new MobyDataComposite(identType, myNS, "N/A",
// HAS (0 or more) TaxonIdentified (TaxonName)
"TaxonIdentified", taxon1, taxon2, null, // 2 values for TaxonIdentified
// HASA (1) IdentificationDate (DateTime)
"IdentificationDate", "2006-04-20");
// or when the last member, null can be omitted...
MobyDataComposite complex = new MobyDataComposite(identType, myNS, "N/A",
"IdentificationDate", "2006-04-20",
// HAS (0 or more) TaxonIdentified (TaxonName)
"TaxonIdentified", taxon1, taxon2); // 2 values for TaxonIdentified
You can serialize just one single data object with the convenience constructor for MobyContentInstance
:
MobyDataUtils.toXMLDocument(System.out, new MobyContentInstance(fastaObj, "paramNameRequiredByService"));
Otherwise you'll need to create a MobyDataJob
, and put it in a MobyContentInstance
to create a full document:
MobyContentInstance contents = new MobyContentInstance();
MobyDataJob job = new MobyDataJob();
job.put("paramNameRequiredByService", fastaObj);
contents.put(job);
Once you have a MobyContentInstance
, it's easy:
StringBufferOutputStream stringOut = new StringBufferOutputStream();
MobyDataUtils.toXMLDocument(stringOut, contents);
// or
MobyDataUtils.toXMLDocument(System.out, contents);
// or
MobyDataUtils.toXMLDocument(new FileOutputStream("contents.txt"), contents);