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

The strategy for using document schema as the document type when designing a document centric interface and endpoint are illustrated by the document oriented application available under the bpcatalog project hosted at java.net. This application has a service endpoint designed to use an XML document as a schema-defined type. The XML document is represented by a purchase order sent by the client. This application demonstrates the strategy where a purchase order service is designed to accept the purchase order document where the schema of the purchase order is part of the service interface.

The application consists of these major entities:

The WSDL File for the Service

The WSDL file describes the Web service. The development style we chose was to start with WSDL and generate the necessary Java classes from it. So choosing the proper types for the message parts in the WSDL is very important, since these types will result in the types of the parameters in the generated Java code. Please note the purchase order schema is in a separate file and is imported from within the WSDL. Also note an application defined service exception declared in the WSDL file. Code example 1 contains a  snippet from the WSDL for this service:

<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>
   <element name="submitPOResponse">
    <complexType>
      <sequence>
            <element name="result" type="string" nillable="true"/>                       
      </sequence>
    </complexType>
   </element>
   <element name="InvalidPOException">
    <complexType>
      <sequence>
        <element name="message" type="string" nillable="true"/>                   
      </sequence>
    </complexType>
   </element>                             
   </schema>
   </types>
  <message name="SchemaDefinedPurchaseOrderServiceSEI_submitPO">
    <part name="parameters" element="tns:submitPO"/>
 </message>
  <message name="SchemaDefinedPurchaseOrderServiceSEI_submitPOResponse">
    <part name="result" element="tns:submitPOResponse"/>
 </message>
  <message name="InvalidPOException">
   <part name="InvalidPOException" element="tns:InvalidPOException"/>
  </message>
  <portType name="SchemaDefinedPurchaseOrderServiceSEI">
    <operation name="submitPO">
      <input message="tns:SchemaDefinedPurchaseOrderServiceSEI_submitPO"/>
      <output message="tns:SchemaDefinedPurchaseOrderServiceSEI_submitPOResponse"/>
      <fault name="InvalidPOException" message="tns:InvalidPOException"/>
    </operation>
  </portType>
Code Example 1:  Snippet from the WSDL for the service

Now lets look at the purchase order document that is part of the service interface. Code Example 2 shows the purchase order schema. This file is imported into the WSDL file in code example 1 with the statement <xsd:import namespace="http://java.sun.com/blueprints/ns/po" schemaLocation="PurchaseOrder.xsd"/>
By importing the purchase order schema, the WSDL file can use this type in the service interface to represent documents being exchanged.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://java.sun.com/blueprints/ns/po" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://java.sun.com/blueprints/ns/po" elementFormDefault="qualified">
  <xsd:element name="PurchaseOrder" type="PurchaseOrder"/>
    <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>
</xsd:schema>
Code Example 2:  Purchase Order Schema

The Service Endpoint Interface

Since the development of this example application starts with the WSDL, the service endpoint interface gets generated based on the information contained in the WSDL. The service endpoint interface has a submitPO() method that accepts a PurchaseOrderobject. The PurchaseOrder class gets generated and matches the purchase order schema that is imported in the WSDL file. Also, the  application defined exception InvalidPOException is generated from the WSDL.

public interface SchemaDefinedPurchaseOrderServiceSEI extends Remote {
    public String submitPO(PurchaseOrder inputDoc) throws
        InvalidPOException, RemoteException;
}

Code Example 3:  The service endpoint interface

The Java Endpoint Implementation

For this application we chose to use an EJB component to implement the service interface. We could instead have used a Web component to implement the endpoint. Either choice would have worked. Please note that the method getPoId() just returns the purchase order ID to the client. In a real world scenario, there will be some work that needs to be done before returning the result to the client. Also, to demonstrate throwing an application specific exception, the endpoint checks if the purchase order ID is a specific number and throws the exception if the condition is met.The endpoint implementation class would look like this:

public class SchemaDefinedPurchaseOrderServiceBean implements SessionBean {  
    private SessionContext sc;  
    public SchemaDefinedPurchaseOrderServiceBean(){}  

    public String submitPO(PurchaseOrder po) throws InvalidPOException, RemoteException {      
        //this is done just to illustrate throwing an application specific exception
        if(po.getPoId().equals("100"))
            throw new InvalidPOException("Invalid ID for the purchase order!!! " +
                    "For demo purposes, we throw " +
                    "an application defined exception for the ID value of 100.");      
        //extract the PO ID and return to the client
        return po.getPoId();
    }  

    //life cycle methods
    public void ejbCreate() throws CreateException {}  
    public void setSessionContext(SessionContext sc) {
        this.sc = sc;
    }  
    public void ejbRemove(){}  
    public void ejbActivate() {}  
    public void ejbPassivate() {}
}
Code Example 4:  The endpoint implementation

The Deployment Descriptors

A Web service in J2EE is packaged into a deployment module such as a war or an ear file. In this application we packaged it as an ear file. The portable packaging of a web service endpoint requires several deployment descriptors as well as the Java classes. Here are some snippets from the endpoint deployment descriptors:

<enterprise-beans>
  <session>
    <ejb-name>SchemaDefinedPurchaseOrderServiceBean</ejb-name>
    <service-endpoint>com.sun.j2ee.blueprints.objectposervice.SchemaDefinedPurchaseOrderServiceSEI</service-endpoint>
    <ejb-class>com.sun.j2ee.blueprints.objectposervice.SchemaDefinedPurchaseOrderServiceBean</ejb-class>
    <session-type>Stateless</session-type>
    <transaction-type>Container</transaction-type>
  </session>
</enterprise-beans>
Code Example 5:  Snippet from ejb-jar.xml Deployment Descriptor

Please note the service endpoint interface defined as the <service-endpoint> in ejb-jar.xml.
The endpoint also needs a Web services deployment descriptor file webservices.xml that looks like this:

<webservice-description>   
  <webservice-description-name>SchemaDefinedPurchaseOrderService</webservice-description-name>   
  <wsdl-file>META-INF/wsdl/SchemaDefinedPurchaseOrderService.wsdl</wsdl-file>   
  <jaxrpc-mapping-file>META-INF/schemadefinedpurchaseorderservice-mapping.xml</jaxrpc-mapping-file>
  <port-component>
    <description>port component description</description>     
    <port-component-name>SchemaDefinedPurchaseOrderService</port-component-name>
    <wsdl-port xmlns:PurchaseOrderns="urn:SchemaDefinedPurchaseOrderService">
      PurchaseOrderns:SchemaDefinedPurchaseOrderServiceSEIPort
    </wsdl-port>
    <service-endpoint-interface>     
      com.sun.j2ee.blueprints.objectposervice.SchemaDefinedPurchaseOrderServiceSEI
    </service-endpoint-interface>
    <service-impl-bean>     
      <ejb-link>SchemaDefinedPurchaseOrderServiceBean</ejb-link>
    </service-impl-bean>
  </port-component>
</webservice-description>
Code Example 6:  Snippet from webservice.xml Deployment Descriptor

The Web services deployment descriptor file contains information about the service such as the names of the WSDL file, JAX-RPC mapping file and also the service endpoint interface and the service implementation class names.
© 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.