In this article, we will look at JAX-WS Technology on the server side including the use of WSDL, integration with legacy system and XML processing. This is third article on JAX-WS. This is part of a larger series of articles to help you prepare for the web service developer exam. You can review the first two articles on JAX-WS, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam” and “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam II” if needed.

Looking at JAX-WS on the Server-Side

To publish Web services endpoints and other run-time services that are capable of handling Web services requests, responses and faults requires a Java EE 5 container that conforms with the run-time services architecture specified primarily by JAX-WS [JSR 224] as well as by WSEE [JSR 109]. We will cover the deployment of security services and the run-time implementation of security in the last of three articles on JAX-WS. The figure below provides an illustration of the run-time architecture using SOAP protocol binding for the deployment of a service endpoint interface:

Tutorial:Review of JAX-WS Server Side for the Web Services Developer Exam-b7-jax-wsserversideinvoc.jpg
Figure: JAX-WS Invocation on Server-Side

The figure shows a high level view of the runtime components of a deployed Web service. We have labelled the steps of an invocation of the deployed Web service in order to help your understanding. The left side shows the Endpoint Listener and Dispatcher components that are described by WS-Metadata and WSEE. These components are platform specific and depending on whether the Web service is deployed as a servlet endpoint or an EJB (specifically a stateless session bean) will differ from one platform to another. As we previously mentioned we will go into more detail of the different deployment options available in the next article. Here we will focus on the components and behaviour common to both types of deployment.

To the right of the Endpoint Listender and Dispatcher, we have the “SOAP Protocol Binding”, “JAX-WS and JAXB Java/XML Binding” components. These are described in detail by the JAX-WS specification. Next is the Web Service which contains a number of subcomponents that are described in the various specifications. The @WebServiceProvider annotation is specified in JAX-WS, the @WebService annotation is specified in WS-Metadata and the metadata or deployment descriptors which are packaged in a WAR or EJB-JAR is specified predominately in the WSEE.

If we step through an invocation by a client, we will have a clear idea of how these components are used. Remember that client invocations can be done by a component written in any of the languages that support web services (i.e. Java, .NET C# , VB, PHP as well as other languages). The steps for the invocation are the following:
  1. Before the client can do an invocation, it must first obtain the WSDL for the Web service that has been deployed. A JAX-WS provider must support URL publication in order to conform to WSEE standards. We will use the WSDL that JBoss publishes to the URL of the form http://<endpoint-address>?wsdl. The common convention across Web Services providers is to publish the WSDL at a URL although it is not mandated by any standard.
  2. The client takes the URL specified by the location attribute of the soap:address to compose a SOAP request and do a HTTP POST to that URL.
  3. The Endpoint Listener receives the HTTP request with the SOAP message. As the Endpoint Listener is a servlet, it is deployed and registered depending upon the implementation of the vendor of the Java EE container. It is also dependent on the type of deployment being done. The listener servlet passes the HTTP request on to the Dispatcher. The Dispatcher can be implemented as a separate class from the Endpoint Listener, or in some cases, the two components will be combined, although the functionality is logically distinct. The Dispatcher’s responsibility is to look up the correct Web service endpoint implementation and dispatch the HTTP request to that endpoint.
  4. Now the request processing transitions to the JAX-WS run-time system. The JAX-WS receives the request from the Dispatcher along with a description of the correct endpoint. The contents of the HTTP request include the necessary information to build the javax.xml.ws.handler.MessageContext. In this case of a SOAP based invocation, the message context is an instance of javax.xml.ws.handler.soap.SOAPMessageContext and contains the SOAP request as a SAAJ SOAPMessage. The SOAP protocol binding will process the SOAPMessageContext before the actual Web service endpoint will be invoked. This protocol binding is one of a number of JAX-WS protocol bindings. The primary responsibilities of any JAX-WS protocol binding is to extract the message context from the transport protocol (be it SOAP/HTTP or XML/HTTP), process the message context using the handlers configured for the Web service endpoint and then configure the result in the form of a response or an exception to be sent back to the client using the appropriate transport. In our case, because we are using a SOAP protocol binding, there is the additional task of doing the mustUnderstand processing required by SOAP. If there are any “must understand” headers that cannot be understood, either a SOAP fault is dispatched or for one-way service, the processing stops.
  5. In the next phase, the SOAP protocol binding invokes each handler in the associated handler chain. All of the handlers associated with the endpoint are defined by a deployment descriptor file specified by the @HandlerChain annotation on the service implementation bean. Handlers provide developers with the capability of preprocessing a message context before the endpoint gets invoked. The types of processing done by server-side handlers include persisting a message or providing recovery in the event of a server crash, encryption/decryption, examining message header sequence IDs to ensure that messages are delivered in order (i.e. sequencing), etc. All of SOAP header processing is done primarily by handlers, but there are also handlers provided by the JAX-WS framework that have access to the SOAP body as well.
  6. After the inbound handlers are finished, the SOAP message is unmarshalled into instances of the Java objects that are used to invoke the endpoint method. This unmarshalling process is governed by the JAX-WS WSDL to Java mapping and the JAXB 2.0 XML to Java mapping. The WSDL to Java mapping determines (from the wsdl:operation) which endpoint method to invoke based on the structure of the SOAP message and the JAXB runtime serializes the SOAP message into the parameters required to invoke that method. If the deployed service implementation bean is an implementation of javax.xml.ws.Dispatch<T>, then the process is much simpler since the message payload is simply passed to the Dispatch.invoke() method and the implementation processes the XML directly.
  7. The final part of inbound request processing is the invocation of the appropriate method on the deployed service implementation bean. After completion of the invocation, the process is reversed and the return value from the invocation as well as any parameters that have been declared OUT or IN/OUT will be marshaled to a SOAP response message of the appropriate form based on the JAX-WS WSDL to Java mapping and the JAXB 2.0 XML to Java mapping.
  8. The processing of the outbound response invokes the handlers in reverse order. If at any point in the processing or invocation of the endpoint, an unhandled exception is thrown, the SOAP Fault Processing component will map the exception to a SOAP fault message. The SOAP protocol binding formats either the SOAP fault or SOAP response message, for the appropriate transport (e.g., SOAP/HTTP).
  9. Finally, the Endpoint Listener servlet completes its processing and returns the result received to the client in the form of a HTTP response from the Dispatcher.

These are the high level steps configured within a Java EE 5 container for the JAX-WS runtime. As we mentioned previously these steps will vary slightly from one Java EE provider to another, but the overall steps will be the same since they are dictated by the Java Web Service specifications.

The area where you might find a significant level of variation is in the implementation of the Endpoint Listener and Dispatcher components as well as in the assumption of the use of SOAP/HTTP protocol binding. If we were using a process for a RESTful endpoint that has an XML/HTTP protocol binding, this would differ in that the handlers would not implement the SOAPHandler<T> interface as well as the simplification of marshaling and unmarshaling since the endpoint is processing XML directly. The JAX-WS runtime does not need to worry about the JAXWS WSDL to Java mapping and the JAXB 2.0 XML to Java mapping for a RESTful service. Likewise, you can imagine that a SOAP/JMS deployment would also be different. Such a thing is not specified by JWS, but it is not hard to conceive of how it would work. To implement a SOAP/JMS protocol binding, you would need an Endpoint Listener on a JMS endpoint—that could be an instance of javax.jms.MessageListener. You would also have differences in the implementation if you chose to use a SOAP/ JMS protocol binding because we would read and write the SOAPMessageContext both from and to a javax.jms.Message.

This is one of the benefits of the JAX-WS run-time architecture. It is very flexible through the use of modularization so that you can adapt it to your needs through the numerous types of transports available for use. For this article though, we will focus on JAX-WS server-side processing of SOAP/HTTP. Let’s now dive down into the details of how to create, deploy, and invoke a JAX-WS endpoint using an existing WSDL contract and a service endpoint interface (SEI).

Using WSDL for a Service Endpoint Interface

When you have an existing WSDL document in JAX-WS as a starting point for implementing a web service, the most direct way to implement a Web service conforming to the WSDL contract is to use a service endpoint interface (SEI). As you know from our previous article, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam”, a SEI is a Java interface mapped from a wsdl:portType using the JAX-WS WSDL to Java mapping and JAXB XML to Java mapping. The SEI is specified using the @WebSevice.endpointInterface attribute. The listing below demonstrates how this is done using the @WebService annotation:

Java Code: Web Service Defined by @WebService Annotation
@WebService(targetNamespace = "http://www.acme.com/req", 
    endpointInterface="com.acme.req.RequestOrderPort")
public class RequestOrder implements RequestOrderPort {
  
  @Resource
  WebServiceContext wscontext;

  public OrderType requestOrder(String custNum, String poNum, BUSOBJCCARD ccard,
      List<BUSOBJITEM> itemList) throws InputFault {
In the listing above, we use the class RequestOrder to implement the SEI com.example.req.RequestOrderPort. The RequestOrder is a service implementation bean (SIB) WS-Metadata terminology. The SIB holds the business logic of a Web service and must be annotated with either @WebService or @WebServiceProvider. It doesn’t need to reference a SEI.

In our case, the SEI that is implemented by RequestOrder has a single method called requestOrder. This method is the same as the one that we developed in our previous article, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam” for JAX-WS client development except that for client development we used dynamic proxy implementations of the service endpoint interface, but for the server side, we are required to provide the actual implementation of the service endpoint interface.

Also similar to our client side development, we are using dependency injection defined by the @Resource annotation in our listing. The javax.xml.ws.WebServiceContext interface allows for a SIB to access contextual information pertaining to the request being served. The WebServiceContext can be used to access the javax.xml.soap.SOAPMessageContext which enables the SIB to access the results of processing that took place in the handler chain such as the security profile for the user who sent the message. Next we will look at the SEI that is generated from the WSDL that is implemented by RequestOrder. This is shown in the listing below:

Java Code: The SEI with Required @WebService Annotation
@WebService(name = "RequestOrderPort", 
    targetNamespace = "http://www.acme.com/req", 
    wsdlLocation = "WEB-INF/wsdl/RequestOrder.wsdl")
public interface RequestOrderPort {

    @WebMethod
    @WebResult(name = "Order", targetNamespace = "http://www.acme.com/oms")
    @RequestWrapper(localName = "requestOrder", 
        targetNamespace = "http://www.acme.com/req", 
        className = "com.acme.req.RequestOrder")
    @ResponseWrapper(localName = "requestOrderResponse", 
        targetNamespace = "http://www.acme.com/req", 
        className = "com.acme.req.RequestOrderResponse")
    public OrderType requestOrder(
        @WebParam(name = "CUST_NO", 
            targetNamespace = "http://www.acme.com/req")
        String custNO,
        @WebParam(name = "PURCH_ORD_NO", 
            targetNamespace = "http://www.acme.com/req")
        String purchORDNO,
        @WebParam(name = "ccard", 
            targetNamespace = "http://www.acme.com/req")
        BUSOBJCCARD ccard,
        @WebParam(name = "item", targetNamespace = "http://www.acme.com/req")
        List<BUSOBJITEM> item)
        throws InputFault;
}
The listing shows the SEI generated from the WSDL, RequestOrderPort. We discussed this SEI, its mapping to a SOAP message, and a detailed description of its annotations in depth in our previous article, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam” so we won’t go into detail about all of the annotations.

Note though that the SEI is also annotated with @WebService just like the service implementation bean. Any SEI is required by JAX-WS to have an @WebService annotation. The difference between this SEI and the SEI that was generated for JAX-WS client side is that the wsdlLocation attribute’s value is different for the server side. The wsdlLocation attribute on the server side can be used to specify the location of a WSDL file deployed with the WAR or EJB-JAR containing the SIB. If you choose to do that, the container will then use the specified WSDL rather than generating a WSDL. Otherwise if @WebService.wsdlLocation is not specified, a WSDL file is generated based on the annotations in the service implementation bean implementing the SEI. A key reason to supply the WSDL inside the packaging like we have in this example is that it preserves all the detail. For example, there are some of the facets for XML Schema simple types such as the xs:maxLength restriction for xs:string that are not captured by the standard JAXB mapping. So, if your WSDL started with such restrictions when you try to recreate it from the annotated SEI, the resulting WSDL will lose these restrictions. The WSDL for generating the RequestOrderPort SEI is shown below:

XML Code: Existing WSDL Used As Metadata for Endpoint
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:oms="http://www.acme.com/oms" xmlns:req="http://www.acme.com/req"
  xmlns:faults="http://www.acme.com/faults"
  targetNamespace="http://www.acme.com/req">
  <wsdl:types>
    <xs:schema targetNamespace="http://www.acme.com/oms">
      <xs:include schemaLocation="http://soabook.com/acme/oms/orders.xsd"/>
    </xs:schema>
    <xs:schema targetNamespace="http://www.acme.com/faults">
      <xs:include schemaLocation="http://soabook.com/acme/faults/faults.xsd"
      />
    </xs:schema>
    <xs:schema targetNamespace="http://www.acme.com/req"
      elementFormDefault="qualified">
      <xs:element name="requestOrder">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="CUST_NO">
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="10"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element minOccurs="0" name="PURCH_ORD_NO">
              <xs:simpleType>
                <xs:restriction base="xs:string">
                  <xs:maxLength value="35"/>
                </xs:restriction>
              </xs:simpleType>
            </xs:element>
            <xs:element type="oms:BUSOBJ_CCARD" minOccurs="0" name="ccard"/>
            <xs:element type="oms:BUSOBJ_ITEM" name="item" maxOccurs="unbounded"
            />
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="requestOrderResponse">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="oms:Order"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="request">
    <wsdl:part element="req:requestOrder" name="parameters"/>
  </wsdl:message>
  <wsdl:message name="response">
    <wsdl:part element="req:requestOrderResponse" name="parameters"/>
  </wsdl:message>
  <wsdl:message name="inputFault">
    <wsdl:part element="faults:inputMessageValidationFault" name="parameters"/>
  </wsdl:message>
  <wsdl:portType name="RequestOrderPort">
    <wsdl:operation name="requestOrder">
      <wsdl:input message="req:request"/>
      <wsdl:output message="req:response"/>
      <wsdl:fault message="req:inputFault" name="requestOrderInputFault"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding type="req:RequestOrderPort" name="RequestOrderSOAPBinding">
    <soap:binding style="document"
      transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="requestOrder">
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="requestOrderInputFault">
        <soap:fault name="requestOrderInputFault"/>
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="RequestOrderService">
    <wsdl:port binding="req:RequestOrderSOAPBinding" name="RequestOrderPort">
      <soap:address location="http://localhost:8680/oms/requestOrder"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>
In the listing, we can see that the WSDL contains the restrictions mentioned. Also another benefit of using the wsdlLocation attribute in this manner is that it provides access to the original WSDL from within the service implementation bean or its handlers. This is now available as part of a mechanism to validate the incoming SOAP messages against the WSDL and reject badly formed messages.

By using a SEI to implement a Web service, requires working with the JAXB-generated classes generated by the mapping of the corresponding wsdl:portType. The listing below shows an example of the type of business logic implemented with such JAXB-generated classes:

Java Code: Implement Web Service Processing with JAXB
//  generate a unique 10 digit order ID
String orderId = Long.toString((new Date()).getTime());
orderId = orderId.substring(orderId.length()-10);
OrderType response = new OrderType();
response.setOrderKey(orderId);
//  create OrderHeader
BUSOBJHEADER hdr = new BUSOBJHEADER();
response.setOrderHeader(hdr);
hdr.setCUSTNO(custNum);
GregorianCalendar cal = new GregorianCalendar();
hdr.setPURCHDATE(dateAsString(cal));
cal.add(Calendar.DAY_OF_MONTH, 14);
hdr.setWARDELDATE(dateAsString(cal));
if ( poNum != null && poNum.length()>0 ) {
   hdr.setPYMTMETH("PO");
   hdr.setPURCHORDNO(poNum);
} else {
   hdr.setPYMTMETH("CC");
    // OrderType.OrderCcard
    OrderType.OrderCcard ordCcard = new OrderType.OrderCcard();
    ordCcard.setCcard(ccard);
    response.setOrderCcard(ordCcard);

Here the business logic for processing a order is implemented in the requestOrder method. If the order processing is successful, the method will return a completed purchase order implemented using the class OrderType. This listing above shows this processing including the creation of an order ID, setting the order date, defining the warrantee expiration date, and adding the payment information to the purchase order. As we previously mentioned it also constructs an instance of the JAXB-generated class, OrderType and then the setOrderKey method sets the order’s ID. After this, an instance of the JAXB-generated class BUSOBJHEADER is created for holding the header information such as the customer number and purchase date. There is nothing complex about the processing of the order shown here.

There are times where you might choose to not work with JAXB-generated classes but instead to implement the business logic directly against the XML. Doing XML processing can improve performance if you choose to implement the business logic using an XSLT stylesheet. It also insulates you to a certain degree from changes in the WSDL. In our case where we use a SEI, changes to the WSDL require that the SEI be regenerated and all code affected be updated to accommodate the resulting changes to the JAXB-generated object. This is the case for even minor changes to the WSDL that have nothing to do with your business logic. For example, this can be the case when another schema that you are using for addresses is modified. Although this is doesn’t affect directly the business logic since all that happens is for the address to be copied but in fact all code must be updated and rebuilt.

Working with Providers and XML Processing without JAXB

There are times when you prefer to deploy a Web service that enables you to work with XML messages directly without the use of JAXB binding. In this case you can use the javax.xml.ws.Provider<T> interface. The Provider<T> interface defines a single method:

Java Code: Syntax for Provider&lt;T&gt; Interface
T invoke(T request)
The T of the Provider<T> interface is the type parameter. This is the class used to represent the message or message payload. There are two usage modes for Provider. These are:
  • Message - the service implementation bean works directly with protocol-specific message structures. An example would be when this is used with a SOAP protocol binding, the invoke method receives and returns SOAP messages as instance of T, the type parameter.
  • Message Payload - the service implementation bean works with the payload of messages rather than the messages themselves. An example would be when this mode is used with a SOAP protocol binding and the invoke method receives and returns the contents of the SOAP body instead of the entire SOAP message.

There are classes that JAX-WS specifies must be supported as type parameters for Provider<T>. These are all implementations that support javax.xml.transform.Source in payload mode with all the predefined bindings such as SOAP/HTTP or XML/HTTP. Similarly, the JAX-WS implementations must also support Provider<SOAPMessage> in message mode in conjunction with the predefined SOAP bindings. The listing below shows a class declaration for RequestOrderEndpoint that implements Provider<Source>:


Java Code: Web Service Implementing Provider&lt;T&gt;
@WebServiceProvider(serviceName = "RequestOrderService",
    portName="RequestOrderPort",
    targetNamespace = "http://www.acme.com/req", 
    wsdlLocation="WEB-INF/wsdl/RequestOrder.wsdl")
@ServiceMode(Service.Mode.PAYLOAD)
public class RequestOrderEndpoint implements Provider<Source> {
  
  @Resource
  WebServiceContext webServiceContext;
  
  private static final String REQ_NS = "http://www.acme.com/req";
  private static final String OMS_NS = "http://www.acme.com/oms";
  
    public Source invoke(Source payload) {

In this listing, the RequestOrderEndpoint uses the @WebServiceProvider annotation. Any web service implementing Provider<T> must carry an @WebServiceProvider annotation so that the container knows that it is a service implementation bean because a Provider implementation is not mapped to a WSDL interface by the JAX-WS to Java Mapping unlike with @WebService annotated endpoint. Therefore you must package a WSDL file with the Provider implementation. This is shown in the above listing by the location of the WSDL file. Also note through the use of the @ServiceMode annotation to indicate whether the service should be deployed in Message mode or Message Payload mode. The table below provides a summary of the roles of the annotations used in the above listing:

Tutorial:Review of JAX-WS Server Side for the Web Services Developer Exam-b7-requestorderendpointannotations.jpg
Table: Java Annotation Descriptions for RequestOrderEndpoint

It may not be clear but the main reason for supplying a WSDL file for a Provider implementation when there is no binding for the incoming message provided by the JAX-WS runtime is that all clients using the deployed service need a WSDL. By publishing a WSDL, you provide the structure of the XML messages that your Web service can process.

Also note from the listing that it you are responsible to do all the validation of the form of the incoming messages ensuring that they are compliant enough with the WSDL for the business logic you have implemented to successfully process them. This is different from the case of when you use the @WebService annotation instead of @WebServiceProvider.
The last part of the listing shows the javax.xml.transform.Source being used as the type parameter for Provider<T>. It implements a method of the following form:

Java Code: Form of Source.invoke Method
public Source invoke(Source payload)
Any request received by the JAX-WS runtime is dispatched to this Web service by calling the Source’s invoke method and providing the message payload as the input parameter. It is left to you to process the raw XML in order to implement the business logic. You can do this using the Document Object Model (DOM) APIs for processing. This is shown in the listing below:

Java Code: Web Service Processing using DOM
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document respDoc = docBuilder.newDocument();
Document payloadDoc = docBuilder.newDocument();
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(payload, new DOMResult(payloadDoc));
Element responseElt = 
  respDoc.createElementNS(REQ_NS, "requestOrderResponse");
Element orderElt = respDoc.createElementNS(OMS_NS, "Order");
responseElt.appendChild(orderElt);
Element orderKeyElt = respDoc.createElementNS(OMS_NS, "OrderKey");
orderElt.appendChild(orderKeyElt);
//  generate a psuedo-unique 10 digit order ID
String orderId = Long.toString((new Date()).getTime());
orderId = orderId.substring(orderId.length()-10);
orderKeyElt.appendChild(respDoc.createTextNode(orderId));
Element orderHeaderElt =  respDoc.createElementNS(OMS_NS, "OrderHeader");
orderElt.appendChild(orderHeaderElt);
// items wrapper comes after header
Element orderItemsElt = respDoc.createElementNS(OMS_NS, "OrderItems");
orderElt.appendChild(orderItemsElt);
Element salesOrgElt =  respDoc.createElementNS(OMS_NS, "SALES_ORG");
orderHeaderElt.appendChild(salesOrgElt);
salesOrgElt.appendChild(respDoc.createTextNode("WEB"));
Element purchDateElt = respDoc.createElementNS(OMS_NS, "PURCH_DATE");
orderHeaderElt.appendChild(purchDateElt);
purchDateElt.appendChild(
    respDoc.createTextNode(dateAsString(new GregorianCalendar())));
Element custNoElt = respDoc.createElementNS(OMS_NS, "CUST_NO");
orderHeaderElt.appendChild(custNoElt);
// get CUST_NO from payload
NodeList nl = payloadDoc.getElementsByTagNameNS(REQ_NS, "CUST_NO");
custNoElt.appendChild(respDoc.createTextNode(
    ((Text)((Element) nl.item(0)).getFirstChild()).getNodeValue()));
The DOM processing in this listing starts with the creation of a document to hold the payload request. This is because the Source form of the payload is not accessible using the DOM APIs. It has to be transformed into a DOM representation, payloadDoc which is an instance of org.w3c.dom.Document. We then create another Document instance, called respDoc, to hold the response message we will construct. Next, we create an instance of javax.xml.transform.Transformer, xformer that is used to load the payload Source into the payloadDoc Document. Below we show a small section of the WSDL listed before for this service that indicates that the response message must have the following form:

XML Code: Response Message Form
<xs:element name="requestOrderResponse"> <xs:complexType>
   <xs:sequence> 
      <xs:element ref="oms:Order"/>
   </xs:sequence> 
   </xs:complexType>
</xs:element>
We can then use the DOM to construct the response message in the following manner:

Java Code: DOM Constructed Response Message
Element responseElt = respDoc.createElementNS(REQ_NS, "requestOrderResponse");
We have used the Document.createElementNS method to create an element with the local name requestOrderResponse in the namespace defined by the String constant REQ_NS (the target namespace). We continue in the listing for the business logic for Web Service using the DOM APIs to build the response message tree. The Document.createElementNS() method is used to create elements, and the method Node.appendChild() is used to add them into the DOM tree.

Although this type of programming could be useful, in general programming with the DOM API is tedious and error prone. Contrast this with the JAXB code implementing the same functionality requires only 20 lines. There are other means to program with XML that don’t require using the DOM APIs. The key thing to understand is that it is significantly easier and less error prone to work with JAXB-generated classes than to implement business logic by directly manipulating XML.

On the other hand, if you want to avoid both XML programming techniques using DOM or JAXB because you have existing Java classes that implement your business logic in the form of a PurchaseOrder class that has a method named processOrder that already implements the business process for receiving an order, processing it, and returning a PO? In this case, you may want to consider writing a JAX-WS service implementation bean that uses a custom Java/XML mapping to bind the WSDL types to your existing Java classes.

Web Services Deployment With Custom Java/XML Mappings

In the previous article, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam II”, we introduced Castor a Java/XML mapping tool for binding an existing Java class to an existing XML schema. We will again use Castor, this time on the server side to illustrate the techniques for using custom Java/XML mappings in a JAX-WS context.

The first problem is how to locate the Castor mapping file at runtime. The answer is to package the mapping file inside the WAR at the location /WEB-INF/castor/mapping.xml. We can then apply the method illustrated in our earlier listing of using an instance of WebServiceContext that has been injected using the @Resource annotation. The injection of the context, takes place at the time the endpoint is initialized. As it is a live reference to the context, any changes the handlers made before the endpoint is invoked will be reflected. Here we are using the context to get to the ServletContext via the MessageContext. Once we have the ServletContext, we can use the getResourceAsStream method to access the mapping file. This is shown in the listing below:

Java Code: Binding Payload to Custom Classes with Castor
if ( webServiceContext == null ) {
  throw new RuntimeException("WebServiceContext not injected.");
}
MessageContext mc = webServiceContext.getMessageContext();
ServletContext sc = 
  (ServletContext) mc.get(MessageContext.SERVLET_CONTEXT);
if ( sc == null ) {
  throw new RuntimeException("ServletContext is null.");
}
InputStream castorMappingFile = 
  sc.getResourceAsStream("/WEB-INF/castor/mapping.xml");
if ( castorMappingFile == null ) {
  throw new IOException("Castor mapping file not found."); 
}
Mapping castorMapping = new Mapping();
castorMapping.loadMapping(new InputSource(castorMappingFile));
Unmarshaller u = new Unmarshaller(castorMapping);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document payloadDOM = db.newDocument();
Transformer xf = TransformerFactory.newInstance().newTransformer();
xf.transform(payload, new DOMResult(payloadDOM));
MyRequestOrder reqOrder = (MyRequestOrder) u.unmarshal(payloadDOM);
Once we have the Castor mapping file, we can instantiate our Java classes from XML with the Castor Unmarshaller. In the listing for DOM Processing, we used a Transformer to move the payload from a Source instance into a DOM Document. We use the Transformer because the Castor Unmarshaller cannot process a Source directly. Once completed, we instantiate the custom class MyRequestOrder from the payload:

Java Code: Instantiation of MyRequestOrder using Castor
MyRequestOrder reqOrder = (MyRequestOrder) u.unmarshal(payloadDOM);
The Castor mapping file directs the Unmarshaller in how to map the XML into the MyRequestOrder instance. In the previous article, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam II” we demonstrated how the mapping files work as well as providing an example of a mapping file. Now that we have use the Castor mapping, we are now free to use the custom classes to implement the business logic. The listing below demonstrates this:

Java Code: Web Service Implementation with Custom Classes
MyRequestOrderResponse response;
try {
  response = reqOrder.processOrder();
} catch (PaymentException pe) {
  SOAPFactory fac = SOAPFactory.newInstance(); 
  SOAPFault sf = fac.createFault(pe.getMessage(),
new QName("http://schemas.xmlsoap.org/soap/envelope/", "Client"));
  throw new SOAPFaultException(sf);
}

Note how we have reduced the 80 lines of DOM processing or 20 lines of JAXB processing to one line of code through the use of existing classes in conjunction with Castor:

Java Code: Business Logic
response = reqOrder.processOrder();
This is the benefit of reusing existing code, instead of being obliged to recreate business logic using the JAXB-generated classes. That is the advantage of using your existing classes and a custom mapping tool like Castor. The majority of the work to be done is in the creation of the Castor mapping file. If you have large amounts of stable and well tested business logic code, it would makes sense to use something like Castor instead of rewriting your business logic with the JAXB-generated classes.

Finally to return the result value as a SOAP message we use the custom class, MyRequestOrderResponse containing the result since it is referenced by the variable response. The Castor mapping is used to marshal the MyRequestOrderResponse to XML in order that it can be returned. This is shown below:

Java Code: SOAP Response Payload with Custom Classes
ByteArrayOutputStream ba = new ByteArrayOutputStream();
Marshaller m = new Marshaller(new OutputStreamWriter(ba));
m.setMapping(castorMapping);
m.marshal(response);
return new StreamSource(new StringReader(ba.toString()));
Here the Castor Marshaller uses the mapping file (i.e. castorMapping) to write XML into a ByteArrayOutputStream. These bytes are then wrapped in a StreamSource that is returned as the response message payload.

OK. That’s it. In the next article, we will continue with JAX-WS on the server side looking at techniques for validation and fault processing in detail as well as Server Side Handlers and deployment with javax.xml.ws.Endpoint.