Client and services in caBIG communicate through the grid using respectively Globus grid clients and service infrastructure. The grid communication protocol is XML, and thus the client and service APIs must transform the transferred objects to and from XML. This XML serialization of caBIG objects is restricted in that each object that travels on the grid must do so as XML which adheres to an XML schema registered in the Global Model Exchange (GME). As the caDSR and EVS define the properties, relationships, and semantics of caBIG data types, the GME defines the syntax of the XML serialization of them. Furthermore, Globus services are defined by the Web Service Description Language (WSDL). The WSDL describes the various operations the service provides to the grid. The inputs and outputs of the operations, among other things, in WSDL are defined by XML schemas. As caBIG requires that the inputs and outputs of service operations use only registered objects, these input and output data types are defined by the XSDs which are registered in GME. In this way, the XSDs are used both to describe the contract of the service and to validate the XML serialization of the objects which it uses.
As mentioned in a preceding section, objects must serialize to and from XML as they traverse the grid. This section details the alternative approaches for said process. Standard Globus Serialization caGrid is built using the Globus 4 toolkit. The Globus toolkit has a complete set of tools for automatic generation of serializable objects using models defined in XSDs. Using this mechanism, Globus has the ability to automatically create a set of Java Beans which represent this model which will be able to be serialized and deserialized automatically at client and service runtime via the Globus toolkit with no extra configuration. In order to use these types in a grid service the developer must describe the types that they will be using in the WSDL file. This will enable Globus to locate the types, and generate the required beans during stub generation time. For more information on this process please see the Globus documentation. Using this approach, the object-oriented client and service APIs are written using the Globus generated Java Objects. The toolkit will automatically serialize and deserialize the Objects as they travel to and from the grid.
Here are some useful links:
- Globus 4.0 Java WS Core developer's documentation that describes how Globus uses the Apache Axis toolkit to serialize types: Globus 4.0 Java WS Core developers documentation
- Apache Axis type mappings page for various XML schema types: Apache Axis type mappings
If a developer already has a java object model that they are already using which is either not serializable or uses a custom serialize the developer will need to configure the Globus service and client to be able to use the custom serialize. This can be done by using the Globus type mapping configuration xml in the services WSDD and in the client's configuration WSDD. This type mapping paradigm is document in the Globus documentation but we will cover the basics in this document. If a user has an object called MyObject which has its own serializer then the following configuration must be placed in the service WSDD and in the client configuration WSDD:
This configuration will now allow the service to use the MySerializerFactory and MyDeserializerFactory to marshal its object back and forth across the grid. The typeMapping element must be in the server and client wsdd and in order for the custom serializer and deserializer to be invoked.
De-serializing an object is easy if you use provided caGrid utility classes.
If you have the Java classes for these objects, you can use caGrid's Utils class from the Core project to deserialize the XML:
If your objects require custom deserialization, there's a similar method which takes an InputStream to the client-config.wsdd file which configures that serialization:
|Credential Delegation Service (CDS)|
caGrid provides an implementation of the previously mentioned custom serialization process for objects generated with the caCORE SDK version 3.1. This feature takes advantage of the fact that the caCORE SDK generates a "XML mapping" file which specifies the mapping between every Class and attribute to a corresponding XML entity. This mapping file is of the format specified by Castor, and can be used by the Castor Marshalling framework to marshall between an XML document meeting the corresponding XML schema, and the corresponding Java objects. Similar to the process used in the Globus generated Java Beans, this provides sufficient functionality to use these Java classes in the service and client code, and have them automatically serialized and deserialized to and from the grid. Castor provides the additional functionality, however, to separate the Java Beans themselves from the serialization process. In this way, Castor can be used to serialize and deserialize between arbitrary Beans and XML, given an appropriately defined XML mapping. caCORE SDK creates such a file for each model it creates Java Beans and XML Schemas. The caGrid SDK Serializer and Deserializer make use of this functionality by providing the necessary hooks to automatically invoke Castor, using the appropriate mapping, from the Globus infrastructure.
The components used to support this functionality are shown in the "SDK (Castor) Serialization Framework" Image. The Factory classes sole responsibility is to be hooked into the underlying Axis framework, and return an appropriate instance of the Serializer and Deserializer classes as needed. Both of these classes internally utilize the Castor APIs to marshall and unmarshall the Java Beans as needed. They leverage the EncodingUtils to access the appropriate Castor mapping. This utility first attempts to read a configuration parameter "castorMapping" from the current Axis context. This property can be specified in the client and service WSDD file, as shown in the highlighted section of the example mapping image. The value of this parameter is expected to be a classpath reference to the Castor XML mapping file which should be used. This parameter allows multiple services or clients running in the same environment, to use different mappings. If this parameter is not set, the mapping is expected to be loaded from the default location (/xml-mapping.xml). This location will work for SDK generated Java Beans, as it is included in their jar files under said location. However, as mentioned, the preferred approach is to explicitly specify a unique location, because if two SDK generated systems were used in the same environment (or the caCORE standard client.jar is used), only one of the mappings would be loadable (determine by the classpath settings).
Introduce supports automatically specifying SDK Serialization, and the appropriate WSDD configurations are made automatically. The service's serialization behavior is controlled by the server-config.wsdd file in the root directory of the service, and the client behavior is controlled by the client-config.wsdd file in the "client" package of the service (in the src folder). Introduce clients overload the default Axis behavior of looking for client-config.wsdd in the working directory, and load the file as a resource from the service's jars. As the file is placed in a service-specific package, this behavior allows multiple (potentially conflicting) client APIs to be used in the same context.
By default, when you add a schema (data type) to Introduce, Java Beans will automatically be created for these types and they will automatically be serialized and deserialized.
However, if you use custom serialization as cagrid:described above, these will not be generated, as it is expected you have your own classes on the classpath. Shown below is an example of using custom serialization in Introduce; this will prevent these classes from being generated.
If you want to use default serialization, but don't want Introduce to generate you beans, you can specify this in your introduce.xml. If you find the section which defines the Namespaces, and locate the definition of the schema of interest and add an attribute as follows:
then open your service and resave it. Your service's build process will no longer generate beans for this
schema, so you should be sure to have these classes on your classpath. An example is shown below (note the highlighted section):
One example use case for doing this is if you want to add specific business logic to the generated beans. You can initially generate them, copy the generated beans into your source tree, then configure them to not be regenerated.
Previously, a user has needed to pass some optional "Double" values in a service. When the "Double" attribute is defined, it is converted to type "xs:double". In the Introduce generated framework (Java stub code), this attribute is declared as primitive java type (instead of java.land.Double). This prevents the user from detecting null values in the Java code.
The explanation is that when Introduce writes the schema for the service interface, it does not set the minOccurs maxOccurs as it is intended to use the defaults. When using a primitive, if you want it to be optional, then you would need to set the minOccurs to 0. This will tell axis to map it to the Double and not the double. However, you can still achieve this by creating your own type in a schema that sets the minOccurs to 0 and import it into Introduce and use that type.