2 Invoking a Web Service Using Asynchronous Request-Response

The following sections describe how to invoke a Web Service using asynchronous request-response:

Overview of the Asynchronous Request-Response Feature

When you invoke a Web Service synchronously, the invoking client application waits for the response to return before it can continue with its work. In cases where the response returns immediately, this method of invoking the Web Service is common. However, because request processing can be delayed, it is often useful for the client application to continue its work and handle the response later on, or in other words, use the asynchronous request-response feature of WebLogic Web Services.

When implementing asynchronous request-response in your client, rather than invoking the operation directly, you invoke an asynchronous flavor of the same operation. (This asynchronous flavor of the operation is automatically generated by the clientgen Ant task.) For example, rather than invoking an operation called addNumbers directly, you would invoke addNumbersAsync instead. The asynchronous flavor of the operation always returns void, even if the original operation returns a value. You then include methods in your client that handle the asynchronous response or failures when it returns later on. You put any business logic that processes the return value of the Web Service operation invoke or a potential failure in these methods.

Using Asynchronous Request-Response: Main Steps

The following procedure describes how to create a client that asynchronously invokes an operation in a Web Service. For clarity, it is assumed in the procedure that:

  • The client Web Service is called AsyncClient.

  • The AsyncClientService service is going to invoke the testEcho() operation of the already deployed AddNumbersService service whose WSDL is found at the following URL:

    http://localhost:7001/async/AddNumbers?WSDL
    

It is further assumed that you have set up an Ant-based development environment and that you have a working build.xml file to which you can add targets for running the jwsc Ant task and deploying the generated service. For more information, see the following sections in Oracle Fusion Middleware Getting Started With JAX-WS Web Services for Oracle WebLogic Server.

Table 2-1 Steps to Use Asynchronous Request-Response

#
Step Description

1

Create an external binding declaration file to enable the creation of the asynchronous methods.

See Applying Asynchronous Binding Declaration to WSDL.

2

Update your build.xml file to compile the asynchronous client.

You pass the external binding declaration file to the clientgen task to automatically generate the asynchronous flavor of the Web Service operations. See Updating the build.xml File When Using Asynchronous Request-Response.

3

Create the asynchronous client.

Within the client, you define an asynchronous callback handler to receive the callback notification and invoke the asynchronous flavor of the Web Service method passing a handle to the asynchronous callback handler. Use your favorite IDE or text editor. See Creating the Asynchronous Client.

3

Run the Ant target to build the AsyncClient.

For example:

prompt> ant build-client

Applying Asynchronous Binding Declaration to WSDL

To generate asynchronous polling and callback methods in the service endpoint interface when the WSDL is compiled, enable the jaxws:enableAsyncMapping binding declaration in the WSDL file.

You can create an external binding declarations file that contains all binding declarations for a specific WSDL or XML Schema document. Then, pass the binding declarations file to the <binding> child element of the wsdlc, jwsc, or clientgen Ant task.

The following provides an example of a binding declarations file that enables the jaxws:enableAsyncMapping binding declaration:

<bindings
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    wsdlLocation="AddNumbers.wsdl"
    xmlns="http://java.sun.com/xml/ns/jaxws">
    <bindings node="wsdl:definitions">
        <package name="examples.webservices.async"/>
        <enableAsyncMapping>true</enableAsyncMapping>
    </bindings>
</bindings>

For more information, see "Creating an External Binding Declarations File Using JAX-WS Binding Declarations" in Oracle Fusion Middleware Getting Started With JAX-WS Web Services for Oracle WebLogic Server.

Updating the build.xml File When Using Asynchronous Request-Response

To update a build.xml file to generate client artifacts and compile the client that invokes a Web Service operation asynchronously, add taskdefs and a build-client target that includes a reference to the external binding declarations file containing the asynchronous binding declaration. See the description following the example for details.

<taskdef name="clientgen"
    classname="weblogic.wsee.tools.anttasks.ClientGenTask" />

<target name="build_client">

<clientgen
      type="JAXWS"
      wsdl="AddNumbers.wsdl"
      destDir="${clientclasses.dir}"
      packageName="examples.webservices.async.client">
      <binding file="jaxws-binding.xml" />
    </clientgen>
    <javac
      srcdir="${clientclass-dir}" destdir="${clientclass-dir}"
      includes="**/*.java"/>
    <javac
      srcdir="src" destdir="${clientclass-dir}"
      includes="examples/webservices/hello_world/client/**/*.java"/>

</target>

Use the taskdef Ant task to define the full classname of the clientgen Ant tasks. Apply the asynchronous binding declaration by specifying an external binding declarations file, as described in Applying Asynchronous Binding Declaration to WSDL. In this case, the clientgen Ant task generates both synchronous and asynchronous flavors of the Web Service operations in the JAX-WS stubs.

Creating the Asynchronous Client

The following example shows a simple client file, AsyncClient, that has a single method, AddNumbersTestDrive, that asynchronously invokes the AddNumbersAsync method of the AddNumbersService service. The Java code in bold is described following the code sample.

package examples.webservices.async.client;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import javax.xml.ws.BindingProvider;

import java.util.concurrent.Future;
import javax.xml.ws.AsyncHandler; 
import javax.xml.ws.Response;

public class AsyncClient  {

   private AddNumbersPortType port = null;
   protected void setUp() throws Exception {
      AddNumbersService service = new AddNumbersService();
      port = service.getAddNumbersPort(); 
      String serverURI = System.getProperty("wls-server");
      ((BindingProvider) port).getRequestContext().put(
            BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
             "http://" + serverURI + "/JAXWS_ASYNC/AddNumbersService");
   }

/**
* 
* Asynchronous callback handler
*/
   class AddNumbersCallbackHandler implements AsyncHandler<AddNumbersResponse> {
      private AddNumbersResponse output;
      public void handleResponse(Response<AddNumbersResponse> response) {
         try {
            output = response.get();
         } catch (ExecutionException e) {
             e.printStackTrace();
         } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
      AddNumbersResponse getResponse() {
         return output;
      }
   }

   public void AddNumbersTestDrive() throws Exception {
      int number1 = 10;
      int number2 = 20;
      AddNumbersCallbackHandler callbackHandler = 
         new AddNumbersCallbackHandler();
      Future<?> resp = port.addNumbersAsync(number1, number2,
         callbackHandler);
      // For the purposes of a test, block until the async call completes
      resp.get(5L, TimeUnit.MINUTES); 
int result = callbackHandler.getResponse().getReturn(); 
   }
}

When creating the asynchronous client file, you need to perform the following tasks:

  1. Create an asynchronous handler that implements the javax.xml.ws.AsyncHandler<T> interface (see http://java.sun.com/javase/6/docs/api/javax/xml/ws/AsyncHandler.html). The asynchronous handler defines one method, handleResponse, that enables clients to receive callback notifications at the completion of service endpoint operations that are invoked asynchronously. The type should be set to AddNumberResponse.

    class AddNumbersCallbackHandler implements AsyncHandler<AddNumbersResponse> {
       private AddNumbersResponse output;
    
       public void handleResponse(Response<AddNumbersResponse> response) {
          try {
             output = response.get();
             } catch (ExecutionException e) {
               e.printStackTrace();
             } catch (InterruptedException e) {
               e.printStackTrace();
    
             }
          }
    
          AddNumbersResponse getResponse() {
             return output;
       }
    }
    
  2. Instantiate the asynchronous callback handler.

    AddNumbersCallbackHandler callbackHandler = 
       new AddNumbersCallbackHandler();
    
  3. Instantiate the AddNumbersService Web Service and call the asynchronous version of the Web Service method, addNumbersAsync, passing a handle to the asynchronous callback handler.

    AddNumbersService service = new AddNumbersService();
    port = service.getAddNumbersPort();
    ...
    
    Future<?> resp = port.addNumbersAsync(number1, number2,
       callbackHandler);
    

    java.util.concurrent.Future (see http://java.sun.com/javase/6/docs/api/java/util/concurrent/Future.html) represents the result of an asynchronous computation and provides methods for checking the status of the asynchronous task, getting the result, or canceling the task execution.

  4. Get the result of the asynchronous computation. In this example, a timeout value is specified to wait for the computation to complete.

    resp.get(5L, TimeUnit.MINUTES);
    
  5. Use the callback handler to access the response message.

    int result = callbackHandler.getResponse().getReturn();