In this article, we will look at JAX-WS Technology and the use of XML Messaging and Asynchronous Invocations for sending and receiving XML messages. This is second part of articles on JAX-WS on the client side as part of a set of articles that focus on describing and publishing web services using WSDL and UDDI. This is part of a larger series of articles to help you prepare for the web service developer exam. You can review the first article on describing and publishing web services, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam” if needed.

As we mentioned in our previous article, JAX-WS 2.0 provides the Java Web Services standard for both deploying and invoking Web services. In the last article we focused on the use of JAX-WS proxies as a means of invoking a web service to send and receive messages via SOAP. JAX-WS proxies were designed for programmers to invoke a Web service in a manner that imitates Java Remote Method Invocation (Java RMI) by enabling the programmer to use local method calls to invoke a service on another host. In this article we will look at two other ways to use JAX-WS for XML Messages and Asynchronous messaging. You will see that these are also key functionalities used by developers to use JAX-WS.

XML Messaging for Invoking Web Services

The use of dynamic proxies for making Web services invocations may have many benefits like the use of standard Java method calls but it has a number of disadvantages as well. The first problem is the need to generate a service endpoint interface based on the Web service’s WSDL to provide standard JAX-WS WSDL to Java mapping. In addition, the parameters and return types of the methods on the generated SEI are classes that are created by the JAXB schema compiler from the wsdl:types section of the WSDL. These classes are not the conventional classes that you use in your normal business. An example of this is shown in our previous article, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam” where the RequestOrder web service rather than using the credit card class that your organization already uses in a Java-based system for order management, it is obliged to use the JAXB-generated BUSOBJCCARD class to represent a credit card. This class forces your organization to engage someone to write some custom middleware to translate between the existing credit card class and BUSOBJCCARD.

Next, there are many instances where it is preferable to work with XML messages directly, rather than with JAXB schema-generated classes. An example would be in the case of an SOA Integration service that obtains orders from one Web service and uses them to update a customer history system via another Web service. You use XSLT to transform the XML for the orders Web service to the format compatible with the customer history Web service. In this case, there was no need to bind the XML to a Java class as it would introduce a performance penalty as well as potential errors. Instead, for this SOA Integration via the chaining together multiple Web services, it is logical to work with XML directly rather than a Java binding. See the figure below for example of this configuration

Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam II-b6-soacompapplication.jpg
Figure: SOA Composite Application and XLST Transformation for Customer History

Finally you may also want to write code to dynamically invoke a Web service without having to generate and compile a SEI prior to runtime. This approach is used when the WSDL is not known prior to runtime. This can happen when the targeted Web service is looked up, using a registry, at runtime. In this case, it is not possible to invoke such “late binding” Web services using the SEI approach. JAX-WS provides the javax.xml.ws.Dispatch<T> interface to handle these scenarios. As well it provides support for XML messaging interactions with Web services. The Dispatch interface provides support for the dynamic invocation of Web services.

XML Messaging using Raw XML

Next let’s look at an example of how to dynamically invoke a Web service using an XML message and the Dispatch<T> interface. The listing for the XML message used to invoke a Web Service is shown below:


XML Code: Example of RequestOrder Document
<requestOrder xmlns="http://www.acme.com/req"
  xmlns:ns2="http://www.acme.com/oms">
  <CUST_NO>ENT0072123</CUST_NO>
  <ccard>
    <ns2:CC_TYPE>VISA</ns2:CC_TYPE>
    <ns2:CC_NUMBER>112445678902323456789</ns2:CC_NUMBER>
    <ns2:CC_EXPIRE_DATE>2014-02-28</ns2:CC_EXPIRE_DATE>
    <ns2:CC_NAME>James Murphy</ns2:CC_NAME>
  </ccard>
  <item>
    <ns2:ITM_NUMBER>012345</ns2:ITM_NUMBER>
    <ns2:STORAGE_LOC>NE02</ns2:STORAGE_LOC>
    <ns2:TARGET_QTY>50</ns2:TARGET_QTY>
    <ns2:TARGET_UOM>CNT</ns2:TARGET_UOM>
    <ns2:PRICE_PER_UOM>97.95</ns2:PRICE_PER_UOM>
    <ns2:SHORT_TEXT>Adidas Predator Mens Sz 12</ns2:SHORT_TEXT>
  </item>
  <item>
    <ns2:ITM_NUMBER>543210</ns2:ITM_NUMBER>
    <ns2:TARGET_QTY>50</ns2:TARGET_QTY>
    <ns2:TARGET_UOM>KG</ns2:TARGET_UOM>
    <ns2:PRICE_PER_UOM>52.58</ns2:PRICE_PER_UOM>
    <ns2:SHORT_TEXT>Tottenham FC Home Kit</ns2:SHORT_TEXT>
  </item>
</requestOrder>
We have used this message indirectly via JAXB in the previous article dealing with service endpoint interfaces. This is an instance of the req:request- Order element defined by the wsdl:types section of the RequestOrder WSDL. This wrapper element holds the parameters required by the Web service. Note that the parameters are: customer number, credit card, and a list of items to be purchased. This is not a SOAP message but is the payload for a SOAP message that needs to be carried as the child of the SOAP Body element. In the listing below, we show how to create an instance of Dispatch<T> and then use it to invoke a Web service with the message in the previous listing. We are still working with the RequestOrder Web service:

Java Code: Dispatch Object Used for XML Messaging
StreamSource xmlSource = 
      new StreamSource(new StringReader(xmlByteArray.toString()));
// create Service
URL wsdlURL = new URL("http://"+host+":"+port+
      "/retail-endpoint-endpoint-1.0/requestOrder?wsdl");
QName serviceQName =
      new QName("http://www.acme.com/req", "RequestOrderService");
Service service = Service.create(wsdlURL, serviceQName);
// create Dispatch<Source>
QName portQName = 
      new QName("http://www.acme.com/req", "RequestOrderPort");
Dispatch<Source> dispatch = service.createDispatch(portQName, 
        Source.class, Service.Mode.PAYLOAD);
Source orderSource = dispatch.invoke(xmlSource);
JAXBContext jc = JAXBContext.newInstance(RequestOrderResponse.class);
Unmarshaller u = jc.createUnmarshaller();
RequestOrderResponse response = 
      (RequestOrderResponse) u.unmarshal(orderSource);
In this listing, the XML message is being used to invoke the service. It is encapsulated in a StreamSource variable called xmlSource. The javax.xml.ws.Service class acts as a factory for creating Dispatch instances. In order to create a Dispatch, you need to first create a Service instance. The Service is created dynamically using the WSDL’s URL and the QName of the wsdl:service (i.e req:RequestOrderService).
In the next part of the listing, the Dispatch<T> is created using the Service.createDispatch() method. It takes three parameters: the QName of the wsdl:portType, the Class of the type parameter T, and the service mode. We use the type parameter T to specify the Class that is used to encapsulate the XML message being sent. Here we use Dispatch<T> to support a javax.xml.transform.Source in order to encapsulate the XML. It also has support for Object with JAXB annotated classes, javax.xml.soap.SOAPMessage and javax.activation.DataSource for MIME-typed messages.

We have the option of the service mode parameter being either javax.xml.ws.Service.Mode.MESSAGE or javax.xml.ws.Service.Mode.PAYLOAD. If it is of type MESSAGE, you can work with the entire SOAP message. If it is PAYLOAD, you can use the Dispatch<T>.invoke() method with only the XML message involving only the payload that is within the SOAP Body element. In our example, we used the PAYLOAD service mode where the Dispatch instance is responsible for creating the SOAP message that contains the payload. The final part of the listing shows that the Dispatch<T>.invoke() is called and returns the response XML message as a Source instance.

XML Messaging using Custom Annotated JAXB Classes

A second approach to using XML messaging is to write your own JAXB annotated classes to represent the XML messages that are being sent and received from a Web service. This allows you to use JAXB without having to tie yourself to a JAX-WS-generated SEI. You then use JAXB annotations to map existing Java classes to the message payloads that you send and receive from the target Web service. This is demonstrated in the listing shown below where the Dispatch<Object> instance is setup and used with custom JAXB classes:

Java Code: Dispatch Object with JAXB for XML Messaging
JAXBContext ctxt = JAXBContext.
    newInstance(MyRequestOrder.class, MyRequestOrderResponse.class);
QName portQName = 
      new QName("http://www.acme.com/req", "RequestOrderPort");
Dispatch<Object> dispatchJAXB = service.createDispatch(portQName, 
        ctxt, Service.Mode.PAYLOAD);
// create the custom request order object
MyRequestOrder myReq = new MyRequestOrder();
myReq.ccard = createMyCreditCard();
myReq.item = createMyItemList();
myReq.CUST_NO = "ENT0035432";
myReq.PURCH_ORD_NO = "";
MyRequestOrderResponse resp =
      (MyRequestOrderResponse) dispatchJAXB.invoke(myReq);
Note here first we have created a JAXBContext using the custom classes MyRequestOrder and MyRequestOrderResponse. Then the Dispatch<Object> instance is created using the Service factory method except the JAXBContext is used in the factory method instead of a type parameter. The context is used by the underlying Dispatch implementation to marshal/unmarshal the Java objects to/from the message payloads.
Once the Dispatch<Object> instance is created, we configure an instance of the MyRequestOrder class which is our custom JAXB annotated class mapping to the required SOAP request payload. Finally the Dispatch<Object>.invoke() method is used to contact the target Web service. The response message payload is marshaled into an instance of MyRequestOrderResponse, our custom JAXB annotated class for the response.

Java Code: MyRequestOrder Custom JAXB Annotated Class
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(namespace = "http://www.acme.com/req")
@XmlRootElement(name = "requestOrder", 
    namespace = "http://www.acme.com/req")
public class MyRequestOrder {

    protected String CUST_NO;
    protected String PURCH_ORD_NO;
    protected MyCreditCard ccard;
    protected List<MyItem> item;

}
It is easy and straightforward to create a JAXB annotated object that maps to the XML message payload request wrapper. The MyRequestOrder class serves as a container for the four parameters contained as children in req:requestOrder. Another custom JAXB annotated class that we have created is one that maps to the credit card XML Schema type oms:BUSOBJ_CCARD. It is shown in the listing below:

Java Code: MyCreditCard Custom JAXB Annotated Class
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BUSOBJ_CCARD", 
    namespace = "http://www.acme.com/oms")
public class MyCreditCard {

    protected String CC_TYPE;
    protected String CC_NUMBER;
    protected String CC_EXPIRE_DATE;
    protected String CC_NAME;
    protected BigDecimal BILLAMOUNT;
    protected String CHARGE_DATE;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "")
    public static class OrderCcard {
      
      @XmlElement(namespace = "http://www.acme.com/oms")
      protected MyCreditCard ccard;
      
    }
}
OK. We have demonstrated how to use Dispatch<T> to invoke a target Web service working directly with the XML messages that are sent and received by the client. As well we have shown he ease with which you can create custom JAXB annotated classes that map to the messages sent and received by a Web service. Next let’s show how to bypass JAXB entirely and use another Java/XML mapping tool to mediate between your existing Java classes and the target Web service.

Web Service Invocations using Custom Java/XML Mappings

Castor (The Castor Project) is a Java/ XML mapping tool that enables you to map existing Java classes to XML. Rather than add JAXB annotations to your Java classes, you can use Castor that leverages an external mapping file to map your classes to XML. There are a number of other Java/XML mapping tools that provides this functionality. We will use Castor to just demonstrate that it is possible.

When you need to work with existing Java classes and you don’t want to add JAXB annotations to them then Castor can be a good fit for your web service mappings. This is because sometimes, the classes that you have targeted are already in production and cannot be modified or may require a lengthy iteration of changes and testing before annotated versions of these classes can be put into production.

We will demonstrate the functionality of Castor by using it on the CreditCard class. It is shown in the listing below. It has a simple structure containing the properties of a credit card and is very similar to the custom JAXB credit card class shown in Example 6–16, except that the field names and types are different and there are no annotations.

Java Code: Credit Card Class
public class CreditCard {

    public String type;
    public String num;
    public String expireDate;
    public String name;
    public float amount;
    public String chargeDate;
Similarly we also have a MyRequestOrder class that is used to hold the request message parameters that are to be sent to the target Web service. This class is also similar to the JAXB version shown in the previous section but without the annotations.

Java Code: Wrapper for Request Parameters, MyRequestOrder Class
public class MyRequestOrder {

  protected String custno;
  protected String purchordno;
  protected CreditCard ccard;
  protected List<MyItem> itemList;
Next we show the Castor mapping file for the CreditCard and the MyRequestOrder. The top-level mapping element is the mapping relationships between classes and the XML. We also define the namespaces that are used in the target XML for the mapping element. These are req and oms. This is done so that we can use their prefixes throughout the file.
The children of the mapping element are class elements that define the mappings from each Java class to their corresponding XML representations. For example, the first class element maps the MyRequestOrder class to the req:requestOrder element. The Castor Mapping file is shown below:
XML Code: Castor Mapping File
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Object Mapping DTD Version 1.0//EN"
                         "http://castor.org/mapping.dtd">
<mapping xmlns:req="http://www.acme.com/req"
  xmlns:oms="http://www.acme.com/oms">
  <class name="com.acme.domain.MyRequestOrder">
    <map-to xml="requestOrder" ns-uri="http://www.acme.com/req"/>
    <field name="custno" type="java.lang.String">
      <bind-xml name="req:CUST_NO" node="element"/>
    </field>
    <field name="purchordno" type="java.lang.String">
      <bind-xml name="req:PURCH_ORD_NO" node="element"/>
    </field>
    <field name="ccard" type="com.acme.domain.CreditCard">
      <bind-xml name="req:ccard" node="element"/>
    </field>
    <field name="itemList" type="com.acme.domain.MyItem" collection="collection">
      <bind-xml name="req:item"/>
    </field>
  </class>
  <class name="com.acme.domain.CreditCard">
    <map-to xml="BUSOBJ_CCARD" ns-uri="http://www.acme.com/oms"/>
    <field name="type" type="java.lang.String" direct="true">
      <bind-xml name="oms:CC_TYPE" node="element"/>
    </field>
    <field name="num" type="java.lang.String" direct="true">
      <bind-xml name="oms:CC_NUMBER" node="element"/>
    </field>
    <field name="expireDate" type="java.lang.String" direct="true">
      <bind-xml name="oms:CC_EXPIRE_DATE" node="element"/>
    </field>
    <field name="name" type="java.lang.String" direct="true">
      <bind-xml name="oms:CC_NAME" node="element"/>
    </field>
    <field name="amount" type="float" direct="true">
      <bind-xml name="oms:BILLAMOUNT" node="element"/>
    </field>
    <field name="chargeDate" type="java.lang.String" direct="true">
      <bind-xml name="oms:CHARGE_DATE" node="element"/>
    </field>
  </class>
In the listing, note that the children of the class element are field elements. They are used to map the properties of the Java class to XML elements or attributes. So we have the class element for MyRequestOrder that has the field elements for custno, purchordno,etc. The other thing of note is that the field element contains a child named bind-xml that specifies the XML the Java property gets mapped to. In the above listing, the field element for custno contains a bind-xml child that maps to the req:CUST_NO element.

You use this mapping file with JAX- WS to invoke a Web service. This is shown in the below listing that shows how to invoke the target Web service.

Java Code: Invoke Web Service using Castor Java to XML Mapping
public static void main(String[] args) throws Exception {
    
    String host = args[1];
    String port = args[2];
    // load Castor Mapping File
    FileInputStream castorMappingFile = new FileInputStream(args[0]);
    Mapping castorMapping = new Mapping();
    castorMapping.loadMapping(new InputSource(castorMappingFile));
    // Use Castor to marshal MyRequestOrder to XML
    MyRequestOrder requestOrder = createRequestOrder();
    ByteArrayOutputStream ba = new ByteArrayOutputStream();
    Marshaller m = new Marshaller(new OutputStreamWriter(ba));
    m.setMapping(castorMapping);
    m.marshal(requestOrder);
    Source xmlSource = new StreamSource(new StringReader(ba.toString()));
    // create Dispatch<Source>
    URL wsdlURL = new URL("http://"+host+":"+port+
      "/retail-endpoint-endpoint-1.0/requestOrder?wsdl");
    QName serviceQName =
      new QName("http://www.acme.com/req", "RequestOrderService");
    Service service = Service.create(wsdlURL, serviceQName);
    QName portQName = 
      new QName("http://www.acme.com/req", "RequestOrderPort");
    Dispatch<Source> dispatch = service.createDispatch(portQName, 
        Source.class, Service.Mode.PAYLOAD);
    // invoke web service with Castor generated XML
    Source orderSource = dispatch.invoke(xmlSource);

In the beginning of the listing, the mapping file is loaded into an instance of org.exolab.castor.mapping.Mapping which plays a similar role to the JAXBContext class of configuring the marshallers and unmarshallers. Next, we create an instance of MyRequestOrder and a ByteArrayOutputStream to be used for marshaling. We then create an instance of org.exolab.castor.xml.Marshaller as a wrapper around the ByteArrayOutputStream. Then we configure the Marshaller by using the setMapping method to load the Mapping instance. Finally the method invocation, m.marshal(requestOrder) is used to marshal the MyRequestOrder instance to an XML document within the ByteArrayOutputStream according to the rules specified in the loaded Castor mapping file. Once this is done, the Dispatch<Source> instance is created and then invoked. The difference here is that this is a Castor made XML message being used for this invocation. We have only been discussing synchronous invocation of Web services up until now, but JAX-WS also supports asynchronous invocation. Let’s look at this in the next section.

Asynchronous Web Service Invocations

JAX-WS also supports asynchronous invocation through easy-to-use APIs. These APIs, in conjunction with the interface java.util.concurrent.Future<T>, shield you from concerns about thread use and other low-level concurrency issues and allow you to just invoke Web services asynchronously. The ability to do asynchronous invocation is a powerful tool for SOA programming since it is one of the ways to manage the “impedance mismatch” between local execution and remote processing being handled by Web services. Generally, Web services invocation tend to execute slower than the local processes. Handling processes in any asynchronous manner will allow you to speed up your processing dramatically since you can have numerous Web services invocations in separate threads running in parallel while the locally executing code is handling other matters waiting for these invocations to complete.

The JAX-WS API provides two approaches to asynchronous processing. These are:
  • polling - in this form of asynchronous invocation, it is your code that is responsible for polling an instance of java.xml.ws.Response<T> to determine when a Web service invocation has completed.
  • callback - in this form of asynchronous invocation, it is your code that supplies an instance of javax.xml.ws.AsyncHandler for processing the results of the Web service invocation. When the Web service returns its results, they are automatically processed by the AsyncHandler instance you provided.


Asynchronous Processing using Polling

Asynchronous processing using polling involve creating an instance of java.xml.ws.Response<T> to determine when a Web service invocation is completed. In the listing below, we provide an example of how to use this form of asynchronous invocation with a Dispatch<T> interface. As in previous manners, the Dispatch<Source> instance is configured similarly.

Java Code: Asynchronous Invocation with Polling
URL wsdlURL = new URL("http://"+host+":"+port+
      "/retail-endpoint-endpoint-1.0/requestOrder?wsdl");
QName serviceQName =
      new QName("http://www.acme.com/req", "RequestOrderService");
Service service = Service.create(wsdlURL, serviceQName);
QName portQName = 
      new QName("http://www.acme.com/req", "RequestOrderPort");
Dispatch<Source> dispatch = service.createDispatch(portQName, 
        Source.class, Service.Mode.PAYLOAD);
Response<Source> responseSource = dispatch.invokeAsync(xmlSource);
long startTime = (new Date()).getTime();
while (!responseSource.isDone()) {
   Thread.sleep(10);
}
long elapsed = (new Date()).getTime() - startTime;
Source orderSource = responseSource.get();
In this listing the Web service is invoked using the Dispatch<T>.invokeAsync(T msg) method. This method uses the java.util.concurrent.Executor that is associated with the Service instance that creates the Dispatch<T> to invoke the Web service with a separate thread. The asynchronous invocation returns an instance of Response<Source>. The javax.xml.ws.Response<T> interface is a wrapper around Future<T> that provides an additional method, getContext(), to retrieve the response message context.

Here we use the get() method from Future<T> to retrieve the response message payload as an instance of Source. Note that the polling is shown in the while loop that polls the isDone() method to determine whether the asynchronous invocation has completed. The variable elapsed captures the milliseconds required to complete the asynchronous invocation.

Asynchronous Processing using Callbacks

In the callback form of asynchronous invocation, we supply an instance of javax.xml.ws.AsyncHandler for processing the results of the Web service invocation. When the Web service returns its results, they are automatically processed by the AsyncHandler instance provided. In the listing shown below, we provide an example that shows how to implement an asynchronous callback using a service endpoint interface (SEI). We create Service instance in the same our previous article, “Tutorial:Review of JAX-WS Client Side for the Web Service Developer Exam I”. The Service instance’s getPort() method is used to create a proxy instance of the SEI RequestOrderPort. The listing is shown below:

Java Code: Asynchronous Invocation with Callback
URL wsdlURL = new URL("http://"+host+":"+portVal+
      "/retail-endpoint-endpoint-1.0/requestOrder?wsdl");
QName serviceQName =
      new QName("http://www.acme.com/req", "RequestOrderService");
Service service = Service.create(wsdlURL, serviceQName);
QName portQName = 
      new QName("http://www.acme.com/req", "RequestOrderPort");
RequestOrderPort port = service.getPort(portQName, RequestOrderPort.class);
RequestOrderCallbackHandler cbh = new RequestOrderCallbackHandler();
cbh.setStartTime((new Date()).getTime());
Future<?> response1 = port.requestOrderAsync(
        "ENT0072123", "", createCreditCard(), createItemList(), cbh);
Future<?> response2 = port.requestOrderAsync(
        "ENT0072123", "", createExpiredCreditCard(), createItemList(), cbh);
try {
    response1.get(2000, TimeUnit.MILLISECONDS);
} catch (TimeoutException te) {
      response1.cancel(true);
}
Here the RequestOrderCallbackHandler is used to handle the response to the Web service invocation. It is invoked by the thread handling the Web services call whenever a response message is received. Note that the invocations themselves using port.requestOrderAsync() both contain the same four parameters as the synchronous versions in addition to a fifth parameter, theAsyncHandler<T> instance. Each asynchronous invocation returns an instance of Future<T> . The Future<T> instance returned can then be polled to determine whether the operation has completed. But as the response message is processed by the AsynchHandler<T> in a separate thread, this is not necessary. Note in the listing the expression response1.get(2000, TimeUnit.MILLISECONDS) to poll the Future<T> instance that has been returned. This version of the Future<T>.get() method waits for, at most, 2,000 milliseconds for the operation to complete. Otherwise it throws a TimeoutException. We catch the TimeoutException and cancel the Web service invocation. This gives you the flexibility to use an asynchronous approach but to place limits on the amount of time that you allow the asynchronous invocation run.

As we need to provide an implementation of AsyncHandler<T> to process the callback, in the listing below, we show the RequestOrderCallbackHandler. The listing is shown below:

Java Code: Implementation of AsyncHandler
private static class RequestOrderCallbackHandler 
  implements AsyncHandler<RequestOrderResponse> {
    
    private long startTime;
    
    public void handleResponse (Response<RequestOrderResponse> response) {
      
      long elapsed = (new Date()).getTime() - startTime;
      Marshaller m;
      try {
        JAXBContext jc = JAXBContext.newInstance(RequestOrderResponse.class);
        m = jc.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        System.out.println();
        System.out.println("================================================");
        System.out.println("Asynchronous Proxy Test");
        System.out.println("using Callbacks and Dynamic Service");
        System.out.println("Elapsed waiting time for web service response:");
        System.out.println(elapsed + " milliseconds.");
        System.out.println("================================================");
        System.out.println();
        System.out.println();
        System.out.println("Response Message ===============================");
        if ( response != null ) {
          RequestOrderResponse orderResponse = response.get();
          m.marshal(orderResponse, System.out);
        }
      } catch (ExecutionException e) {
        Throwable t = e.getCause();
        if ( t instanceof SOAPFaultException ) {
          processSOAPFault((SOAPFaultException) t);
          return;
        }
        e.printStackTrace();
      } catch (Exception e) {
        e.printStackTrace();
      }
      
    }
    
    public void setStartTime(long t) { startTime = t; }
There is a single method for the AsyncHandler<T> interface called handleResponse. This method implements the action to be taken when the response message is received from a Web service invocation. Our RequestOrderCallbackHandler implementation does two things. First, it calculates the elapsed time used by the asynchronous invocation, and second it prints out the response message to the console. Note also how our handler also does exception processing. It is essential that you build in fault handling into your Web services invocations. In this case, we have implemented fault handling in a callback scenario, within an AsyncHandler<T> implementation. According to the JAX-WS specification, if a wsdl:operation asynchronous invocation fails, it throws a java.util.concurrent.ExecutionException instance is returned from the Response.get() method. The cause of the ExecutionException can be retrieved using the getCause() method. This will contain either the SEI-specific exception such as InputFault or a protocol-specific exception such as SOAPFaultException. Next we handle the SOAPFaultException by invoking the processSOAPFault method to print out the contents of the SOAP fault message.

Asynchronous Processing using Proxies

JAX-WS includes in it’s specification that all implementations must make it possible to generate service endpoint interfaces (SEIs) that have client-side asynchronous methods. This is in addition to the asynchronous invocation methods on the Dispatch<T> interface. It is optional for the user whether they want to generate a SEI that includes asynchronous methods. In the case that the user wants to have asynchronous methods, the JAX-WS also declares that the user must be able to specify the generation of these asynchronous methods using binding language declarations. The asynchronous methods are generated in a manner similar to the synchronous methods. For example for a synchronous mapping of the target wsdl:operation of the following:

XML Code: Synchronous Mapping of wsdl:operation
Xxx port.yyyZzz()
where Xxx is the return type and yyyZzz is the property name. The asynchronous mapping of the same wsdl:operation using polling would be:

XML Code: Polling Form of Asynchronous Mapping of wsdl:operation
 Response<Xxx> port.yyyZzzAsync()
As well the callback form would be:

XML Code: Callback Form of Asynchronous Mapping of wsdl:operation
 Future<?> port.yyyZzzAsync(..., AsyncHandler<Xxx> asyncHandler)
You can specify either inline with the WSDL or in a separate file the binding language declarations needed to generate these interfaces. As the Web service is deployed with its WSDL which generally don’t contain custom binding language declarations that are used only by Java clients, it is not practical to declare them inline. In the listing below, we show an external file with the required binding language specifications:

XML Code: Binding Declarations Enabling Asynchronous Methods
<bindings xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  wsdlLocation="http://localhost:8080/retail-endpoint-endpoint-1.0/requestOrder?wsdl"
  xmlns="http://java.sun.com/xml/ns/jaxws">
  <bindings node="//wsdl:portType[@name='RequestOrderPort']">
    <bindings node="wsdl:operation[@name='requestOrder']">
      <enableAsyncMapping>true</enableAsyncMapping>
    </bindings>
  </bindings>
</bindings>
In this listing, the enableAsyncMapping element is set to true indicating that the WSDL to Java compiler that creates the SEI should enable the generation of the asynchronous methods. These bindings elements surrounding this declaration use the node attribute to specify the part of the target WSDL being modified by the enclosed binding declaration. There is an XPath expression that is set for the node attribute to indicate the target location. Note that the bindings elements can be nested as we have the outer bindings element specifying the RequestOrderPort wsld:portType of the target WSDL and the second bindings element specifying the requestOrder wsdl:operation.

SOAP Message Handlers for Extended Processing

The JAX-WS handler framework allows you to define message handlers that can be used to process XML messages before and after a Web service invocation. This can be done on both the client or server side. Handlers enable you to do both pre and post-processing of the messages used to invoke Web services. They can be used while doing SEI proxy style invocation or Dispatch<T> style XML messaging. We will focus on client-side handlers here but look at the server side in a later article. These handlers are commonly used to implement messaging functionality not specific to a particular Web service. One primary use of the JAX-WS handler framework is to be used as a means of implementing Web Services standards like WS-Security 1.1 using a handler to add a wsse:Security header or for WS-ReliableMessaging on top of the base invocation implementation.

The best way to understand client-side message handles is to look at an example. We will create a handler that is used for implementing message persistence by saving a message to some form of storage. Message persistence is often used to provide the type of delivery assurance specified in WS-ReliableMessaging.

There are two approaches available to us with JAX-WS for configuring a message handler on a client. One is to implement it programmatically, the other is to implement it using the @javax.jws.HandlerChain annotation. Let’s first look at implementing it using the programmatic configuration of handlers. The listing for this is shown below:

Java Code: Adding Handlers Programmatically for Web Service
private static void runPersistenceHandlerTest(File persistenceDir)
  throws Exception {
    
    RequestOrderService service = new RequestOrderService();
    // add the handler to the service
    service.setHandlerResolver(new RequestOrderHandlerResolver());
    RequestOrderPort port = service.getRequestOrderPort();
    // configure message request context
    Map<String, Object> reqCtxt = ((BindingProvider) port).getRequestContext();
    reqCtxt.put(PersistMessageHandler.PERSISTENCE_DIR_PROP, persistenceDir);
    reqCtxt.put(AddMessageIdHandler.MSGID_PROP, "msg0001");
    // add the callback handler
    RequestOrderCallbackHandler cbh = new RequestOrderCallbackHandler();
    cbh.setStartTime((new Date()).getTime());
    Future<?> response = port.requestOrderAsync(
        "ENT0072123", "", createCreditCard(), createItemList(), cbh);
    response.get(2000, TimeUnit.MILLISECONDS);
   
  }

In this listing we setup the handlers by configuring an instance of javax.xml.ws.handler.HandlerResolver on a Service instance. This will allow any SEI proxy or Dispatch<T> created from such a Service instance to use the specified HandlerResolver to determine the handler chain defined for the particular wsdl:portType it implements. In this case, the Service.setHandlerResolver() method is used to set up an instance of the RequestOrderHandlerResolver. This is the class that that implements HandlerResolver. Note that the SEI proxy or Dispatch<T> also known as the BindingProvider can be instantiated after the Service has been configured with the HandlerResolver. As the BindingProvider inherits the HandlerResolver that is being configured when it gets instantiated, it is instantiated as well. Therefore later on, any new HandlerResolver, BindingProvider instances created afterwards will use the new HandlerResolver but not those previously created.

The last part of the listing shows the configuration of the request context of the RequestOrderPort SEI proxy. Although not required for handler configuration, we have created here for the simple persistence handler we have implemented for the operation. We set a property called PERSISTENCE_DIR_PROP that specifies the directory where messages will be stored. At runtime, a handler can access this request context in order to configure itself. In the listing below, we show the implementation of the HandlerResolver interface:

Java Code: Message Handler for Client-Side Persistence
private static class RequestOrderHandlerResolver implements HandlerResolver {

    public List<Handler> getHandlerChain(PortInfo arg0) {

      List<Handler> handlerChain = new ArrayList<Handler>();
      handlerChain.add(new AddMessageIdHandler());
      handlerChain.add(new PersistMessageHandler());
      return handlerChain;

    }
    
  }
The HandlerResolver interface has a single method—getHandlerChain(PortInfo p) returning a list of handlers. This is what gets implemented in the RequestOrderHandlerResolver. At runtime, the BindingProvider uses this implementation of the interface to get a list of handlers. Outbound messages can then be processed by the handlers in the order in which they appear in this list. Note that the handler processes inbound messages in the reverse order.

The List<Handler> returned by RequestOrderHandlerResolver contains two handlers:
  • AddMessageIdHandler - this adds a unique identifier in the form of a message ID header to the outgoing SOAP message. This ID is used by the subsequent handler, PersistMessageHandler.
  • PersistMessageHandler - this is used to create a unique filename under which the message gets persisted.


Both handlers implement the javax.xml.ws.handler.soap.SOAPHandler<T extends SOAPMessageContext> interface. They are referred to in the JAX-WS specification refers as Protocol Handlers. They operate on protocol-specific messages and message contexts. We have been using SOAP protocol for these handlers operate on SOAP messages. In JAX-WS you can also define Logical Handlers that operate only on the generic message payloads and contexts. These type of Handlers implement javax.xml.ws.handler.LogicalHandler and are not able to manipulate protocol-specific parts of a message such as a SOAP header block. The listing below shows a Protocol Handler for SOAP used to persist messages to the file:

Java Code: Message Handler for Persistence
public class PersistMessageHandler implements SOAPHandler<SOAPMessageContext> {

  public static final String PERSISTENCE_DIR_PROP = 
    "com.acme.handler.persistence.directory";
  
  public Set<QName> getHeaders() {
    return null;
  }

  public boolean handleMessage(SOAPMessageContext ctxt) {
    
    System.out.println("Entered PersistMessageHandler.handleMessage");
    //  return if inbound message
    if ( !((Boolean)ctxt.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)).
        booleanValue()) { return true; }
    SOAPMessage msg = ctxt.getMessage();
    File persistenceDir = (File) ctxt.get(PERSISTENCE_DIR_PROP);
    Iterator itr;
    try {
      itr = msg.getSOAPHeader().examineAllHeaderElements();
      String msgId = null;
      while (itr.hasNext() && msgId == null) {
        SOAPHeaderElement headerElt = (SOAPHeaderElement) itr.next();
        QName headerQName = headerElt.getElementQName();
        if (headerQName.equals(AddMessageIdHandler.MSGID_HEADER)) {
          msgId = headerElt.getAttribute("id");
        }
      }
      if ( msgId == null ) {
        System.out.println("No message ID header.");
        return false;
      }
      File msgFile = new File(persistenceDir, msgId+".xml");
      msgFile.createNewFile();
      msg.writeTo(new FileOutputStream(msgFile));
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    } 
    return true;
    
  }

  public boolean handleFault(SOAPMessageContext ctxt) {
    return false;
  }

  public void close(MessageContext ctxt) {}
}

In this listing the handleMessage() method receives an instance of the SOAPMessageContext. The handleMessage() method then examines the context to determine the value of MessageContext.MESSAGE_OUTPUT_PROPERTY. This handler is design specifically to persists outgoing messages, so determining the direction of the message is the first thing that is required.

If it has an outgoing message, the handler examines the PERSISTENCE_DIR_PROP to determine the directory into to save the outgoing message. It then processes the SOAP header to locate where the message’s unique ID is contained. This is typical processing for a SOAP handler. An authentication handler might have looked for a header containing an encrypted password to authenticate the user before sending his message over the wire. Once the message ID is found the Handler saves the message to a file using the SOAPMessage.writeTo() method. Note that both SOAPMessage and SOAPHeader are part of the SOAP with Attachments API for Java version 1.3 API for manipulating SOAP messages. This API is typically used inside a handler to get access to the parts of a SOAP message. See documentation for JSR-67 for more details on SAAJ.

Summary

We have completed our articles on creating JAX-WS clients. In the first article, we focused on explaining the JAX-WS WSDL to Java mapping. It is very important to understand JAXB XML Schema to Java mapping as well as mapping generally in order to effectively use JAX-WS. In the second article we covered JAX-WS on the client side using XML Message and Asynchronous Processing of Web Service Invocations. Next we will look at JAX-WS on the server side.