MobyCore API

MobyCore is an API to execute BioMoby services. It supports both synchronous and asynchronous services. Library relies on JAX-WS 2.1 API that is a part of Java 6. It also works on JEE5 where JAX-WS is a part of the platform. In case of using Java 5, JAX-WS must be present in a classpath.

Some essencial classes and packages of the library are:
org.inb.biomoby.shared.datatypes.* This package contains BioMoby primitive classes (such as MobyString, MobyInteger...)
org.inb.biomoby.shared.message.* Package contains classes related to BioMoby message structure (MobyMessage, MobyData, MobySimple...)
org.inb.biomoby.shared.registry.* Classes in this package represent artifacts from BioMoby Registry (such as description of services or datatypes)
MobyMessageContext.class This is a JAXB Context cache. JAXB Context has all BioMoby artefacts to convert them into an XML.
MobyDispatch.class The class executes a BioMoby service.

Generating JAXB-annotated ontology classes

Even MobyCore may work without generated ontology classes, they facilitate a development. Generated by MobyGenerator classes are nothing more than JAXB annotated beans with properties.

Here is an example of generated datatype class:
@XmlRootElement(name="WeightedAminoAcidSequences") @XmlType(name="WeightedAminoAcidSequences") public class WeightedAminoAcidSequences extends AminoAcidSequence implements Serializable { public List<? extends AminoAcidSequence> getAminoAcidSequence() { return getAttributes("AminoAcidSequence"); } public void addAminoAcidSequence(AminoAcidSequence aminoAcidSequence) { putAttribute("AminoAcidSequence", aminoAcidSequence); } public WeightedObject getWeightedObject() { return getAttribute("WeightedObject"); } public void setWeightedObject(WeightedObject weightedObject) { putAttribute("WeightedObject", weightedObject); } }

Executing synchronous BioMoby services

To execute a BioMoby service, first we have to prepare a message. This is done by creating a MobyMessage object:

MobyObject object = new MobyObject("P00807", "UniProt"); MobySimple simple = new MobySimple(object, "id"); MobyData data = new MobyData(simple, "sip_1"); MobyMessage request = new MobyMessage(data);

Next step is to create a BioMoby service description. To execute a service we do not need a complete description.

Service service = new Service("getAminoAcidSequence", "");

Now we can create a MobyDispatch object and execute a service.

MobyDispatch dispatch = new MobyDispatch(service); MobyMessage response = dispatch.invoke(request);

The result of the execution is another MobyMessage that contains a response (or possibly MobyExceptions).

MobyCore supposed to work with generated JAXB-annotated ontology classes. In case when a class can not be found, it is substituted by a special object AnyMobyObject. This object facilitates property access through getAttribute() and getAttributes() methods. Consider that we execute a service that return an AminoAcidSequence object and we do not have AminoAcidSequence class generated. In this case we would have a AnyMobyObject instead of unknown to us AminoAcidSequence.

MobyString string = (MobyString) any.getAttribute("SequenceString");

Well, may be this is not the best example, because we still must know that service returns an AminoAcidSequence or its derivative. MobySimple may contain either a primitive type or a complex one, so we have to check. Here is a simple method that traverse a given element:

public void traverse(AbstractMobyObject object) throws JAXBException { System.out.println(MobyMessageContext.getMobyName(object) + " " + object.getArticleName()); if (object instanceof MobyObject) { MobyObject complex = (MobyObject)object; List<AbstractMobyObject> attributes = complex.getAttributes(); for (AbstractMobyObject o : attributes) { traverse(o); } } }

Here we used a MobyMessageContext to resolve a BioMoby name for a given object.

AnyMobyObject can also be used to setup a datatype dynamically.

AnyMobyObject any = new AnyMobyObject("AminoAcidSequece"); any.putAttribute("SequenceString", new MobyString("ATCG")); any.putAttribute("Length", new MobyInteger(4));

Even we can perfectly mix AnyMobyObject with ontology generated classes, it is better to use one way or another.

Here is an example of parsing a MobyMessage response:

MobyMessage response = dispatch.invoke(request); if (response.hasExceptions()) { throw response.getExceptions(); // MobyExceptions is a java Exception object! } ArrayList<MobyData> data_list = response.getMobyDataList(); if (data_list.isEmpty()) { throw new Exception("Empty response!"); } for (MobyData data : data_list) { List<MobyDataElement> elements = data.getMobyDataElements(); // for example a list of simples for (MobyDataElement element : elements) { if (element instanceof MobySimple) { MobySimple simple = (MobySimple)element; AbstractMobyObject object = simple.getObject(); if (object instanceof AminoAcidSequence) { AminoAcidSequence sequence = (AminoAcidSequence)object; MobyString str = sequence.getSequenceString(); System.out.println(str.getString()); } else if (object instanceof AnyMobyObject) { AnyMobyObject any = (AnyMobyObject)object; AbstractMobyObject attr = any.getAttribute("SequenceString"); if (attr != null && attr instanceof MobyString) { MobyString str = (MobyString)attr; System.out.println(str.getString()); } else { throw new Exception(); // object has no "SequenceString" property of type MobyString } } else { throw new Exception(); // expected AminoAcidSequence } } else { throw new Exception(); // expected MobySimple } } }

Executing asynchronous BioMoby services

BioMoby uses a subset of WSRF specification for the asynchrony. The main difference between asynchronous and synchronous services is in a way of obtaining a result. Note also that we set a service category to "moby-async". The rest of the things are pretty the same as for synchronous invocation:

// AminoAcidSequence sequence = new AminoAcidSequence(); // sequence.setSequenceString(new MobyString("ATCG")): // sequence.setLength(new MobyInteger(4)); AnyMobyObject sequence = new AnyMobyObject("AminoAcidSequence"); sequence.putAttribute("SequenceString", new MobyString("ATCG")); sequence.putAttribute("Length", new MobyInteger(4)); MobySimple simple = new MobySimple(sequence, "sequence"); MobyData data = new MobyData(simple, "sip_1"); MobyMessage request = new MobyMessage(data); Service service = new Service("runNCBIBlastp", null); service.setCategory(CATEGORY.moby_async); service.setUrl(""); MobyDispatch dispatch = new MobyDispatch(service); MobyWSRFResource wsrf = dispatch.invokeAsync(request);

The result object is an WSRF resource through which we can poll to check our execution status:

while(true) { AnalysisEvent lsae = wsrf.getResourcePropertyStatus("sip_1"); Event event = lsae.getEvent(); if (event instanceof StateChanged) { StateChanged stateChanged = (StateChanged)event; StateChanged.STATE state = stateChanged.getNewState(); if (state == StateChanged.STATE.completed) { // the resource (result) is ready MobyMessage response = wsrf.getResourcePropertyResult("sip_1"); wsrf.destroy(); // we can remove a resource if we do not need it anymore } else if (state == StateChanged.STATE.created || state == StateChanged.STATE.running) { // the result is not ready Thread.currentThread().sleep(2000); continue; } } // actually must be an error... break; }

An obtained MobyMessage parsed the same way as for synchronous service.

Dmitry Repchevsky