When first introduced as a way to do application development, Web services implementations supported only synchronous invocations for request-response interactions (synchronous in this article implies processing both request and response in the same thread of execution). But when more and more applications adopted Web services to expose functionalities and client applications were designed to interact with Web services, mere synchronous invocations were seen as bottlenecks. This is because some Web services implementations take a considerable amount of time to respond to requests due to various reasons inside the service implementation. For example, if a Web service requires human intervention or batch processing at some point, the Web service might take days to reach an outcome. These delays also caused some of the transport mechanisms to time out.
With the evolution of Web services development, eventually some SOAP stacks tried to emulate asynchronous invocations on top of synchronous capabilities. Even though those efforts gave a sense of asynchronous invocations, they couldn't provide full and real functionality. Apache Axis2, the open source Web services engine from Apache Software Foundation, provides first-class support for asynchronous Web services invocations and implementation. Axis2 has two mechanisms to provide asynchronicity in the client side and one mechanism in the server side. Let's look at how these can be used for asynchronous communications in more detail.
Client-side asynchrony enables the request and response messages to be processed in two different threads. There are two ways to implement this on the client side, described in the following sections.
You can provide a nonblocking API to the client so it can hand over the request to the SOAP engine and continue with the other work. There's a callback object the client provides that's notified by the SOAP engine after the engine receives the response from the server. This approach is especially useful for interactive applications with GUIs.
The Axis2 client API provides methods to be used for commonly used Message Exchange Patterns (MEPs). Let's use the IN-OUT interaction to illustrate asynchronous support.
When you use the ServiceClient API, you use sendReceive(OMElement) or a variant of that method for synchronous invocations. However, sendReceiveNonBlocking(OMElement, Callback)
provides the first level of asynchronicity of the Axis2 client API, as shown in Listing 1.
Listing 1. Invoking an IN-OUT Web service without blocking the client
// First create the payload of the message.
OMElement payload = getPayload(); // add your payload here
// Create an instance of service client.
ServiceClient serviceClient = new ServiceClient();
// Create an options object to pass parameters to service client.
Options options = new Options();
// Set the location of the Web service.
options.setTo(new EndpointReference
("http://www.sample-web-service.com/StockQuote/getQuote"));
serviceClient.setOptions(options);
// Create a callback object.
Callback callback = new MyCallback();
// Do an async invocation.
serviceClient.sendReceiveNonBlocking(payload, callback);
// Continue doing other work without waiting until the response comes.
|
When the client invokes the Web service using the nonblocking API, it needs to pass a
callback object to the Axis2 ServiceClient API. Upon the
arrival of the response message, the Axis2 engine hands over this response message to the callback object. This callback object can then process this response on behalf of the client or hand it over to the client.
Now take a look at how the Callback should be implemented. The callback interface has
two methods:
- The
onComplete(AsyncResult)method, which is invoked after the response is received - The
AsyncResultobject method, which encapsulates the resulting SOAP envelope and the message context
Clients can extend the Callback interface to handle the
response within this method. On the other hand, the onError(Exception) method is invoked in case of an error during the
invocation. Look at this in detail in Listing 2.
Listing 2. Implementing the Callback interface
class MyCallback extends Callback {
public void onComplete(AsyncResult result) {
// Get the response SOAP envelope from the result.
SOAPEnvelope envelope = result.getResponseEnvelope();
// Process SOAP envelope.
}
public void onError(Exception e) {
// Write here what you want to do in case of an error.
}
}
|
The Callback class can also be used as a polling mechanism.
Clients can continuously poll for a response by calling the Callback.isComplete() method. This is handy when there are multiple
Callback instances waiting for responses or if there's a
central controller that monitors for responses and updates the running application. So
the Callback class can be used both as a callback mechanism or as a polling mechanism during an asynchronous invocation.
The second approach is to use transport-level asynchrony. All the transports that can be used in a Web services invocation can be broadly categorized into two types of invocations:
- One-way transports provide a channel to either send or receive a message.
- Two-way transports can send and receive messages using the same channel.
Simple Mail Transfer Protocol (SMTP) is an example of one-way transport, and HTTP is a two-way transport. You can do request-response interaction with a Web service using a single HTTP channel, but you need two channels if you're using SMTP.
A client has different options to use for a request-response interaction. The easiest way is to use a two-way transport like HTTP. But this approach doesn't use transport-level asynchrony. Clients can also use two one-way transports or two two-way transports. For example, you can use an SMTP channel to send the message and another SMTP channel to receive the response message. At the same time, you can use an HTTP channel to send the request, close it after the message has been sent, and use a different HTTP channel to receive the response. But for this approach to work, there should be a message correlation mechanism. Apache Axis2 uses the WS-Addressing specification for message correlation. Here's how you can work with different transports.
First, send the request using any transport channel, and receive the response using a
different channel but with the same type of transport. The Axis2 client can use the
useSeparateListener flag to notify its intention to use a
separate listener to receive the response message. In other words, after this flag is
enabled, you're asking the Axis2 engine to use two different transport channels for this
invocation. The ServiceClient API, the easiest-to-use client
API within Axis2, has the method setUseSeparateListener(boolean) to set this value. Listing 3
demonstrates the use of the useSeparateListener API to invoke a Web service.
Listing 3. Using the useSeparateListener variable
try {
// first create the payload of the message
OMElement payload = getPayload(); // add your payload here
// create an instance of service client
ServiceClient serviceClient = new ServiceClient();
// create an options object to pass parameters to service client
Options options = new Options();
// set the location of the web service
options.setTo(new EndpointReference
("http://www.sample-web-service.com/StockQuote/getQuote"));
// inform Axis2 engine that you need to use a different channel for the response
options.setUseSeparateListener(true);
serviceClient.setOptions(options);
// invoke the service
serviceClient.sendReceive(getPayload());
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
}
|
At this point, you ask the Axis2 engine to prepare a transport listener from the same
type of transport that's used to send the request; you also ask it to receive the
response. The proper transport being used is inferred by the endpoint reference value.
This example is trying to send the message to
http://www.sample-web-service.com/StockQuote/getQuote, and two HTTP transports are used
during this invocation. You can use either the sendReceive or sendReceiveNonBlocking method to invoke the Web service.
Now find out how to achieve server-side asynchrony using Axis2.
When a SOAP engine receives a SOAP request, the usual way is to process the request and send the message in the same thread. But this might not always be useful. For example, when it takes a considerable amount of time to process the request, the transport channel might time out. Or sometimes holding resources for that duration might not be a good option for a system that handles a lot of traffic. So the ideal option is to notify the client that the server received the message and send the reply later using a different transport channel.
Axis2 employs a message receiver that takes care of the MEP and hands over the message to the request processing logic or the service implementation. During a synchronous invocation, the message receiver invokes the proper method in the service implementation class (assuming the service implementation is written in the Java™ language) and then sends the response in the same thread. But during an asynchronous invocation, this message receiver starts a new thread to invoke the service and send the notification to the client. The new thread is responsible for sending the response to the client and taking the response from the service implementation class. That's how server-side asynchrony works in Axis2. Now check out how you can use it for your Web services.
There are two basic ways that you create your services:
- Write the Web Services Description Language (WSDL), then generate the code for the service implementation class and fill it up.
- Write the service implementation class, write the services.xml, and deploy it within Axis2.
Services.xml contains metadata about the Web service you're deploying. It lists the service implementation classes, the methods exposed, and any parameters that should be passed to the Web service.
If you're starting with the WSDL-code-generation method described above, you can ask
the code generator to enable asynchronous invocations to your service. The code
generator then generates an asynchronous message receiver to invoke your service. When
you run a WSDL2Java script to generate Java code from a given WSDL file, use the -a option also to instruct the script to generate async code. If
you're using the second method, which is the code-first approach, then associate org.apache.axis2.async.AsyncMessageReceiver
for IN-OUT invocations within the services.xml. You have to associate the IN-OUT MEP to
org.apache.axis2.async.AsyncMessageReceiver,
as shown in Listing 4.
Listing 4. Associating message receivers with the IN-OUT MEP variable
<messageReceivers>
// other message receivers
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class=
"org.apache.axis2.async.AsyncMessageReceiver"/>
</messageReceivers>
|
For the server-side asynchrony to work, you must use WS-Addressing, because you spawn a new thread to send the response, promising the client that the server will send the response later. But if request processing takes some time, then the transport that the client used might time out. So it might not be prudent to try to do asynchronous invocations in the same channel. When the client sends a request to an asynchronous Web service, it must also mention a valid replyTo endpoint for the server to send the response back.
From the client point of view, when it invokes this asynchronous
service—say using HTTP—it receives HTTP 202 in the same
transport channel. HTTP 202 tells the client that the request is accepted by the Web
service but that the processing has not been completed yet. Then the client receives the
response via the replyTo path put in the request message.
Asynchronous invocations provide a great deal of flexibility for Web services users and for the people who write and host Web services. With more Web services becoming generally available and getting more complex at the same time, more applications are able to integrate those Web services into their applications. Because most of the final applications ultimately interact with users, the challenge is to provide a better user experience. Asynchronous Web services invocations provided in different levels, in both the client and server sides, can help realize some of these modern challenges.
Learn
- Read Holt Adams' seminal piece on asynchronous Web
services, Asynchronous operations and Web services, Part 1: A
primer on asynchronous transactions (developerWorks, Apr 2002).
- Learn more about Apache Axis2.
- Check out the W3C recommendation for Web Services Addressing 1.0 - Core.
- Get more information about Message Exchange Patterns (MEPs).
- The SOA and Web services zone on IBM developerWorks hosts hundreds of informative articles and introductory, intermediate, and advanced tutorials on how to develop Web services
applications.
- The IBM SOA Web site offers an overview of SOA and how IBM can help you get there.
- Stay current with developerWorks technical events and webcasts. Check out the following SOA and Web services tech briefings in particular:
- Get started on SOA with WebSphere's proven, flexible entry points
- Building SOA solutions and managing the service lifecycle
- SCA/SDO: To drive the next generation of SOA
- SOA reuse and connectivity
- Browse for books on these and other technical topics at the
Safari bookstore.
- Check out a quick Web services on demand demo.
Get products and technologies
- Innovate your next development project with
IBM trial software, available for download or on DVD.
Discuss
- Participate in the discussion forum.
- Get involved in the developerWorks community
by participating in developerWorks blogs, including the following SOA
and Web services-related blogs:
- Service Oriented Architecture -- Off the Record with Sandy Carter
- Best Practices in Service-Oriented Architecture with Ali Arsanjani
- WebSphere SOA and J2EE in Practice with Bobby Woolf
- Building SOA applications with patterns with Dr. Eoin Lane
- Client Insights, Concerns and Perspectives on SOA with Kerrie Holley
- Service-Oriented Architecture and Business-Level Tooling with Simon Johnston
- SOA, ESB and Beyond with Sanjay Bose
- SOA, Innovations, Technologies, Trends...and a little fun with Mark Colan



