Marvin Services provides you seamless integration of third-party calculations into MarvinSketch, cxcalc, and via Chemical Terms into Instant JChem or JChem for Excel. Industrial standard solutions like SOAP with WSDL are supported along with the more lightweight XML-RPC or JSON-RPC protocols. Java based calculations can be called without server, directly from the jar file.
Easy to use graphical interface for convenient usage in MarvinSketch, a single configuration file for easy maintenance, and automatic integration to other products mentioned above.
Configure services in MarvinSketch preferences with provided graphical user interface.
The preferences tab offers all available service implementation with editor support.
For custom service implementations or alternative editors, user-defined mapping can be used
by placing a file named servicedescriptoreditormapping.xml
to the user's ChemAxon
directory - usually located in user home as .chemaxon or ChemAxon, depending on operating
system. The file should be valid to the following XSD schema:
<?xml version="1.0" encoding="utf-8"?> <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:attribute name="class" type="xs:string" /> <xs:attribute name="editor" type="xs:string" /> <xs:complexType name="descriptorType"> <xs:attribute ref="class" /> <xs:attribute ref="editor" /> </xs:complexType> <xs:element name="DescriptorEditorMapping"> <xs:complexType> <xs:sequence> <xs:element name="Descriptor" type="descriptorType" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
The code
attribute is the class name of the ServiceDescriptor
implementation,
and the editor
attribute is the class name of the ServiceDescriptorEditor
implementation.
Services saved by MarvinSketch are available by their names in cxcalc and as Chemical Terms function.
Arguments also can be referred by their names set at the editor. Please note that the built-in editor has
type restrictions that can be avoided by direct access of the Marvin Services API. The most important
types such as MDocument
, Molecule
, String
, Integer
,
Long
, Double
, Float
and Boolean
are available.
Although the most common services are already implemented, Marvin Services provides an extensible API to implement custom services. Please note that some implementations has type restrictions handled by the built-in editor. The supported service protocols listed below:
Local service is for accessing third party java functions. It does not require server or network connection. Java Archive (JAR) file acts as "server", any public class with default constructor acts as "service", and all the public method can be called. Please mind that the build-in editor may hide methods that requires unsupported argument type. Direct access of the Marvin Services API does not have this restriction, any type can be used.
Local Service is the most easy way to embed third-party calculation to MarvinSketch application, cxcalc or Chemical Terms, however java coding is required to assemble the jar files. Also note that these services can not be accessed in non-java environment such as Marvin .NET or JChem for Excel.
Keep in mind that classes used via service call should be stateless, as each service call will create a new instance of the class by the default constructor before calling the function.
Local Service makes good use of the Alias
and Description
annotations. Any methods annotated can
provide default names and description for services and arguments. Also, these aliases are available from cxcalc
as well - so a default service and argument name can be guaranteed by the class author.
The following code snippet calls the Integer countAtoms(Molecule)
function of
example.services.SampleService
class located in localserviceexample.jar.
// input molecule Molecule input = MolImporter.importMol("c1ccncc1"); // initialize descriptor LocalServiceDescriptor descriptor = new LocalServiceDescriptor(); descriptor.setURL("/path/to/localserviceexample.jar"); descriptor.setClassName("example.services.SampleService"); descriptor.setMethodName("countAtoms"); descriptor.addArgument(ServiceArgument.createArgument(new Molecule())); // asynchronous call descriptor.getServiceHandler().callService(descriptor, new AsyncCallback<Integer>() { @Override public void onSuccess(Integer result) { System.out.println("Asynchronous call returned " + result); } @Override public void onFailure(ServiceException caught) { System.err.println("Asynchronous call failed."); } }, input); // synchronized call Object result = null; try { result = descriptor.getServiceHandler().callService(descriptor, input); } catch (ServiceException e) { System.err.println("Service call failed."); } System.out.println("Synchronized call returned " + result);
Local Service can look up default service and argument names, as well as description information from annotations. These values used in MarvinSketch when adding the Local Service to the services list by automatically completing the form. The values can be edited manually, but the defaults are always available from Chemical Terms or cxcalc - as well as the optionally overwritten ones. You can find a sample class can be used as a Local Service below. To download the sample service jar file with source, click here.
/* * Copyright (c) 1998-2012 ChemAxon Ltd. All Rights Reserved. * * This software is the confidential and proprietary information of * ChemAxon. You shall not disclose such Confidential Information * and shall use it only in accordance with the terms of the agreements * you entered into with ChemAxon. * */ package example.services; import chemaxon.formats.MolFormatException; import chemaxon.formats.MolImporter; import chemaxon.marvin.services.localservice.Alias; import chemaxon.marvin.services.localservice.Description; import chemaxon.struc.Molecule; /** * This is a sample class to demonstrate how to write * classes for Marvin Services Local Service implementation. * @author Istvan Rabel */ public class SampleService { /** * Returns the number of atoms in the specified molecule * @param molecule the molecule being checked * @return the number of atoms in the molecule */ /* * (non-javadoc) * This method can be called as a LocalService from * Marvin Sketch, cxcalc and Chemical Terms. * Annotations are used to provide default names * for Service and arguments, as well as a description. */ @Alias(name="AtomCount", params={"Structure"}) @Description("Returns the number of atoms in the structure") public Integer countAtoms(Molecule molecule) { return molecule.getAtomCount(); } /** * Returns a formatted (HTML) message with the number of * atoms in the molecule imported from argument. * @param moleculeString a string representation of a molecule * @return a formatted (HTML) message with the number of atoms */ /* * (non-javadoc) * This method can be called as a LocalService from * Marvin Sketch, cxcalc and Chemical Terms. * Annotations are used to provide default names * for Service and arguments, as well as a description. */ @Alias(name="AtomCountText", params={"Molecule"}) @Description("Returns a formatted text message containing the number of atoms in the structure.") public String countAtomsHTML(String moleculeString) { // import the molecule Molecule molecule = null; try { molecule = MolImporter.importMol(moleculeString); } catch (MolFormatException e) { // invalid molecule string molecule = new Molecule(); } // get the atom count int value = countAtoms(molecule); // build and return the result string StringBuilder builder = new StringBuilder("<html><body>"); if(value > 1) { builder.append("The structure has <font color='blue'><b>"); builder.append(value); builder.append("</b></font> atoms."); } else { builder.append("The structure has <font color='red'><i>" + (value == 0 ? "no atoms" : "only one atom") + "</i></font>."); } builder.append("</body></html>"); return builder.toString(); } }
SOAP Services defined by WSDL can be accessed via Marvin Services. The user interface supports automatic discovery of various options from local file system, or any available URL.
SOAP | Java |
xs:string | java.lang.String |
xs:int | java.lang.Integer |
xs:double | java.lang.Double |
xs:float | java.lang.Float* |
xs:boolean | java.lang.Boolean |
xs:anytype | java.lang.Object |
* Please note that WSDL Float support is not complete.
XML-RPC Service uses the standard XML-RPC protocol to access remote calculations. The XML for the request is automatically generated from the provided attributes and arguments, and the response is parsed to unwrap the result of service call.
XMLRPCServiceDescriptor descriptor = new XMLRPCServiceDescriptor(); descriptor.setURL("http://sample.server.net/xmlrpc"); descriptor.setMethodName("SampleService.countAtoms"); descriptor.addArgument(ServiceArgument.createArgument("")); descriptor.addArgument(ServiceArgument.createArgument("")); Object result = null; try { result = descriptor.getServiceHandler().callService(descriptor, "C1CCNCCC1", "C"); } catch (ServiceException e) { System.err.println("Service call failed."); } System.out.println("Synchronized call returned: " + String.valueOf(result)); descriptor.getServiceHandler().callService(descriptor, new AsyncCallback<Integer>() { @Override public void onSuccess(Integer result) { System.out.println("Asynchronous call returned: " + result); } @Override public void onFailure(ServiceException caught) { System.err.println("Asynchronous call failed."); } }, "C1CCNCCC1", "C");
Marvin supports protocol versions 1.0 and 1.1. JSON Schema Service Descriptor can also be used
for runtime parameter discovery. The response MUST be a textual representation of any finite combinations
of java.lang.Boolean
, java.lang.Number
, java.lang.String
, java.lang.Object[]
,
java.util.Map<java.lang.String, java.lang.Object>
, and null
JsonServiceDescriptor descriptor = new JsonServiceDescriptor(); descriptor.setURL("http://api.geonames.org/"); descriptor.setMethodName("citiesJSON"); descriptor.addArgument(ServiceArgument.createArgument("north", new Double(0))); descriptor.addArgument(ServiceArgument.createArgument("south", new Double(0))); descriptor.addArgument(ServiceArgument.createArgument("east", new Double(0))); descriptor.addArgument(ServiceArgument.createArgument("west", new Double(0))); descriptor.addArgument(ServiceArgument.createArgument("language", "")); descriptor.addArgument(ServiceArgument.createArgument("username", "")); Object result = null; try { result = descriptor.getServiceHandler().callService(descriptor, 44.1, -9.9, 22.4, 55.2, "en", "demo"); } catch (ServiceException e) { System.err.println("Service call failed."); } StringBuilder builder = new StringBuilder(); Object[] array = (Object[]) ((Map<String, Object>)result).get("geonames"); for(Object obj : array) { builder.append("Synchronized call returned: " + ((Map<String, Object>)obj).get("name") + "\n"); } System.out.println(builder.toString()); descriptor.getServiceHandler().callService(descriptor, new AsyncCallback<Map<String, Object>>() { @Override public void onSuccess(Map<String, Object> result) { StringBuilder builder = new StringBuilder(); Object[] array = (Object[]) result.get("geonames"); for(Object obj : array) { builder.append("Asynchronous call returned: " + ((Map<String, Object>)obj).get("name") + "\n"); } System.out.println(builder.toString()); } @Override public void onFailure(ServiceException caught) { System.err.println("Asynchronous call failed."); } }, 44.1, -9.9, 22.4, 55.2, "en", "demo");
HTTP Service is the most lightweight and unrestricted remote service: it supports POST
and GET
requests to a predefined URL. Result is retrieved as is.
HTTPServiceDescriptor descriptor = new HTTPServiceDescriptor(); descriptor.setURL("http://chemicalize.org/tomcat-files/datapage.jsp"); descriptor.addArgument(ServiceArgument.createArgument("mol", "")); descriptor.addArgument(ServiceArgument.createArgument("special", "")); descriptor.addArgument(ServiceArgument.createArgument("pka_width", 0)); Object result = null; try { result = descriptor.getServiceHandler().callService(descriptor, "c1ccnccc1", "pka", 300); } catch (ServiceException e) { System.err.println("Service call failed."); } System.out.println("Synchronized call returned: " + String.valueOf(result)); descriptor.getServiceHandler().callService(descriptor, new AsyncCallback<String>() { @Override public void onSuccess(String result) { System.out.println("Aynchronous call returned: " + result); } @Override public void onFailure(ServiceException caught) { System.err.println("Asynchronous call failed."); } }, "c1ccnccc1", "pka", 300);
The location of service configuration file is provided by the servicesConfigURL
User Setting, and defaults to servicesconfig.xml
in the users's ChemAxon folder - located
in user home as .chemaxon or ChemAxon, depending on operating system. The file should be valid for
the following XSD schema:
<?xml version="1.0" encoding="utf-8"?> <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- definition of attributes --> <xs:attribute name="alias" type="xs:string" /> <xs:attribute name="name" type="xs:string" /> <xs:attribute name="class" type="xs:string" /> <xs:attribute name="url" type="xs:string" /> <xs:attribute name="method" type="xs:string" /> <xs:attribute name="descriptor" type="xs:string" default="chemaxon.marvin.services.descriptors.LocalServiceDescriptor"/> <xs:attribute name="value" type="xs:string" /> <xs:attribute name="expression" type="xs:string" /> <!-- definition of complex types --> <xs:complexType name="evaluationType"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute ref="class" use="optional" default="chemaxon.marvin.services.ChemicalTermsArgument" /> <xs:attribute ref="expression" use="optional" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:complexType name="argumentType"> <xs:all> <xs:element name="Evaluate" type="evaluationType" minOccurs="0" maxOccurs="1" /> </xs:all> <xs:attribute name="class" use="optional" default="java.lang.String"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="java.lang.Integer" /> <xs:enumeration value="java.lang.Float" /> <xs:enumeration value="java.lang.Double" /> <xs:enumeration value="java.lang.String" /> <xs:enumeration value="java.lang.Long" /> <xs:enumeration value="java.lang.Boolean" /> <xs:enumeration value="chemaxon.struc.Molecule" /> <xs:enumeration value="chemaxon.struc.MDocument" /> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute ref="value" use="optional" /> <xs:attribute ref="name" use="optional" default="Unnamed" /> <xs:attribute ref="alias" use="optional" /> </xs:complexType> <xs:complexType name="serviceType"> <xs:all> <xs:element name="Arguments" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:element name="Argument" type="argumentType" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> </xs:element> </xs:all> <xs:attribute ref="name" use="required" /> <xs:attribute ref="url" use="required" /> <xs:attribute ref="method" use="required" /> <xs:attribute ref="class" use="optional" /> <xs:attribute ref="descriptor" use="optional" /> <xs:attribute ref="alias" use="optional" /> <xs:anyAttribute processContents="skip" /> </xs:complexType> <xs:element name="Services"> <xs:complexType> <xs:sequence> <xs:element name="Service" type="serviceType" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
Configured services are accessible via MarvinSketch Tools/Services menu. A disabled entry indicates that the protocols for the service are not available - due to missing libraries. Calling a service from MarvinSketch will pop-up a dialog with the input data, the attributes and the results. Outside MarvinSketch such as cxcalc or Chemical Terms, the services are available by their names or aliases.
In MarvinSketch the result is recognized automatically: if a Molecule or MDocument is returned, it is rendered. All other typed are displayed in a HTML view. Please note that returning partial HTML documents can provide nice looking results - with images as well.