Using Schema-Defined Types to Represent XML Documents in a Service Interface

Sean Brydon, Smitha Kangath, Sameer Tyagi

Problem Description

When designing a web service interaction where a client and service exchange an XML document, developers need to choose a type to represent the XML document in the service interface. This decision on the type chosen to represent the XML document in a service interface has many impacts. The type chosen will be reflected in the WSDL file describing the service and also in the code of the service implementation. In J2EE 1.4 applications, XML documents, such as purchase orders or invoices, are exchanged using JAX-RPC. There are many strategies to consider for choosing a type to represent an XML document when designing the service interface: For a description of all these strategies, see the catalog entry on Designing Document Oriented Services.

This solution focuses on the design considerations when choosing to use a type you define in a schema file to represent XML documents. In this case, these schema may be application-specific or defined by vertical industry standards bodies. For example, an application may need to use a purchaseorder.xml document which has a corresponding purchaseorder.xsd schema file. The important thing in this case is that the WSDL file will expose as part of its service, this type which is defined in the schema file, and it is not a type that is defined by standard schema. Usually this type is defined as a complex type using the standard schema types.

Solution

Lets consider some of the issues when using a schema-defined type to represent the XML document being exchanged between a client and service.

In describing this strategy, we will use an example of passing a PurchaseOrder XML document from a client to a service which receives the purchase order. The purchase order document being exchanged is a typical purchase order which includes data such as the order id, the contact information, and the line items for the goods being purchased.

Strategy: Using a Type Defined in Schema to Represent the XML Document

In this strategy the service interface artifacts (WSDL file, Java interface and implementation) would contain all the details of the PurchaseOrder structure since it would be exposed as part of the interface. A Web Service such as this when deployed with a document-literal formatting passes the XML document in the body of the SOAP message. For the WSDL file this means that all the elements of the schema would be embedded in the WSDL file or alternatively the schema of the document can be defined in a separate schema file and imported into the WSDL file. For the corresponding Java interface this means that all PurchaseOrder schema elements would need corresponding Java types to represent the PurchaseOrder. From the WSDL point of view, there is a coupling of WSDL to the schema for the document being exchanged for this operation.

For the choice of embedding the schema defenition directly into the WSDL file, this means that your interface would contain all the details of the fields and types for the structure of the document. The snippet of the WSDL in Code Example 1 below, the interface and implementation class below illustrate the purchase order details being embedded in the interface. This can be tricky to maintain since the purchase order type is actually part of the WSDL.

<?xml version="1.0" encoding="UTF-8" ?>
<definitions xmlns="http://schema.xmlsoap.org/wsdl/" xmlns:tns="urn:ObjectPurchaseOrderService" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schema.xmlsoap.org/wsdl/soap/" name="ObjectPurchaseOrderService" targetNamespace="urn:ObjectPurchaseOrderService">
<types>
<schema xmlns:soap11-enc="http://schema.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schema.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:ObjectPurchaseOrderService">
     <xsd:complexType name="Address">
        <xsd:sequence>
            <xsd:element name="street" type="xsd:string" nillable="false"/>
            <xsd:element name="city" type="xsd:string" nillable="false"/>
            <xsd:element name="state" type="xsd:string" nillable="false"/>
            <xsd:element name="postalCode" type="xsd:string" nillable="false"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="LineItem">
        <xsd:sequence>
            <xsd:element name="itemId" type="xsd:string" nillable="false"/>
            <xsd:element name="price" type="xsd:float" nillable="false"/>
            <xsd:element name="quantity" type="xsd:int" nillable="false"/>
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name="PurchaseOrder">
        <xsd:sequence>
            <xsd:element name="poId" type="xsd:string" nillable="false"/>
            <xsd:element name="createDate" type="xsd:date" nillable="false"/>
            <xsd:element name="shipTo" type="Address" nillable="false"/>
            <xsd:element name="billTo" type="Address" nillable="false"/>
            <xsd:element name="items" type="LineItem" nillable="false" minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence>
    </xsd:complexType>

</schema>
</types>
<message name="PurchaseOrderServiceSEI_submitPO">
  <part name="PurchaseOrder_1" type="tns:PurchaseOrder" />
</message>
   ...
</definitions>

Code Example 1: WSDL File Snippet Showing a Purchase Order Schema Definition as a Parameter Type Definition Embedded in the WSDL

An alternative to embedding the document schema definition inside the WSDL is to define a type in a separate file and import it into the WSDL file. This makes it easier to maintain. In this strategy a purchaseorder.xsd schema file would be created. And then the WSDL file would import this type into the WSDL. Then just use it for the input parameter to service operations. Code Example 2 illustrates this strategy.

<types>
   <schema targetNamespace="urn:SchemaDefinedPurchaseOrderService"
   xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> 
    <xsd:import namespace="http://java.sun.com/blueprints/ns/po" schemaLocation="PurchaseOrder.xsd"/>
    <element name="submitPO">
        <complexType>
            <sequence>
            <element name="inputDoc" type="pons:PurchaseOrder" nillable="true"/>                       
      </sequence>
    </complexType>
      </element>  
    ...                  
  </schema>
</types>
<message name="SchemaDefinedPurchaseOrderServiceSEI_submitPO">
    <part name="parameters" element="tns:submitPO"/>
</message>
  ...
<portType name="SchemaDefinedPurchaseOrderServiceSEI">
    <operation name="submitPO">
      <input message="tns:SchemaDefinedPurchaseOrderServiceSEI_submitPO"/>
       ...
    </operation>
</portType>
Code Example 2:  Snippet from the WSDL Showing a Purchase Order Schema Being Imported

Now lets consider the Java files that would be generated from these types of WSDL files. Just as the WSDL file must have all the details specified for the purchase order, the Java Interface would also need to reflect the types to represent a purchase order.

//The service endpoint java interface(either generated or hand rolled)
package com.sun.j2ee.blueprints.objectposervice;
import java.rmi.*;
public interface PurchaseOrderServiceSEI extends Remote {
    public String submitPO(PurchaseOrder inputDoc) throws
        InvalidPOException, RemoteException;
}

Code Example 3: PurchaseOrderServiceSEI Java Interface Corresponding to WSDL File of Service

Note that the PurchaseOrder.java would be defined in a class, as would any class types that it references such as Address.java or LineItem.java

public class PurchaseOrder{
   private String poId;
   private Calendar createDate;
   private Address shipTo;
   private Address billTo;
   private LineItem[] items;
   ...

}
Code Example 4: Purchase Order Java Class Corresponding to the Type Definition in the WSDL File of Service

Similarly the endpoint implementation, an EJB in this example, also uses the PurchaseOrder.java in its method signature. Note that this component could be a web component instead of an EJB and the same issues would apply. Choosing either a web component or EJB component to implement the service interface makes no difference in terms of the choice of type for the XML document.

public class PurchaseOrderServiceBean implements SessionBean {
  ...
  public String submitPO(PurchaseOrder po) throws
InvalidPOException, RemoteException {
    //see code for details
  }
  ...

}
Code Example 5: Purchase Order Service Endpoint Implementation Class

So the endpoint will need a WSDL file, a Java interface, a Java implementation class with a submitPO method that accepts the PurchaseOrder with the structure and types defined in the PurchaseOrder schema, and also possibly some helper Java classes to represent the PurchaseOrder. This seems like a natural interface for many Java programmers since it is similar to passing objects, which makes it a comfortable strategy for many developers. This strategy applies well for scenarios where there is a well defined schema for a document and a service needs to be built based on that schema. For example, building a service around a vertical industry standard Invoice document. This strategy benefits from being able to leverage the automatic schema validation of JAX-RPC. For example, when a PurchaseOrder document is received, the JAX-RPC runtime automatically validates an incoming PurchaseOrder against the PurchaseOrder schema before dispatching to the service implementation class, which can save the developer some coding. Also, this strategy can benefit form the automatic binding to Java objects provided by JAX-RPC. For instance, in the purchase order example above, the XML PurchaseOrder document is automatically bound to PurchaseOrder.java objects which are available in the signature of the submitPO method. This can save a developer from writing code to create Java objects from a received XML document.

Note that the description of the document is tightly coupled to the service interface. So if you try to change the document definition, then you may need to change the interface or the WSDL. This can impact the evolution of the interface. With this strategy, it can be difficult to build a more generic service with a method that accepts many different types of documents since the service operation is tightly bound to the schema of a single document. In cases where the type of the document being exchanged is known, for example a vertical industry-defined schema, then this solution of using a schema defined type in the interface works very well. This also is a commonly used solution.

References

The following resources are recommended for further information on this topic

© Sun Microsystems 2005. All of the material in The Java BluePrints Solutions Catalog is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.