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:
- Using String to represent the XML document .
- Using a schema-defined type to represent the
XML document
- Using an XML fragment to represent the XML document (using
xsd:anyType)
- Using an XML fragment to represent the XML document (using
xsd:any)
- Using attachments to package the XML document
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.