Introduction

Invocation of web service will lead to an exchange of messages between two or more parties.  If we consider the general scenario where a client invokes a single service, the communication between them can be either one way or two-way. Depending on the way the client handles the invocation at the API level, whether the transport protocol used is unidirectional or bi-directional and the type of the service method, one can derive many interaction patterns between client and the service. Rest of the document will focus on identifying these possible break ups and on how they are supported in Apache Axis 2.

Note: Please note that through out the tutorial the words "Client" and the "Service" are used to represent "Web Service Client" and the "Web Service" respectively.

Axis 2 Client API

Followings will decide the interaction patterns between client and the service.

  • Client API
  • The Protocol used to send the SOAP Message
  • The type of the service method

Client API

Clients can consume services which take almost no time to complete and the services take considerable amount of time to complete. So it?s important that the SOAP engine provides both blocking and non-blocking APIs for the client. This can be easily done in the API level.

With a blocking API client will hang till the operation completes. In other words once invoked, the client will keep blocking till it gets the response (if any) from the service. This is very useful method when invoking web services that do not take long time to complete and the hanging in the client side is negligible. This will be a huge drawback in the client side performance, if the operation takes considerable amount of time.

A non blocking API will provide the client to use a Callback mechanism (or polling mechanism) to get the responses (if any) for a service invocation. Client gets this response it two ways. Both ways client has to register a call back with the SOAP engine.

  • Client keep on polling the call back object it registers with the SOAP engine, using the isComplete(). If isComplete() returns true, client get the result, if any, through getResult() which returns an AsyncResult object.
  • Upon receipt of the response, if any, SOAPEngine calls the onComplete(AsyncResult) of the call back object.

Note that client can adopt any one of the above two methods, independent of the way service has been implemented.

The Protocol Use to Send the SOAP Message

The protocol used to send the SOAP message can be categorized mainly in to two types.

  1. Unidirectional
  2. Bi-Directional

With a unidirectional protocol (e.g. SMTP), client can simply invoke a service which has no response(s) to be sent in the same connection. But if the service is request/response in nature, it is required to use two separate connections of unidirectional protocol. However if the client needs only to send information, unidirectional is useful for that.

With a bidirectional protocol the client can retrieve the service response (if any) using the same connection. In this context HTTP is the most common bidirectional transport protocol. However the main drawback is the possibility of the timeouts that can happen. If the service takes some time to complete then there is a possibility of time out in the connection.

Bi-directional transport can be used to invoke one-way services as well. In this case the return path of the communication channel is not used. However since we are using a bi-directional protocol the return path can be used to carry the acceptance state or a fault (if any). With reference to HTTP the "HTTP 202 Ok" header status will act as the acceptance state. The faults (if any) is also sent using the response path of the HTTP connection.

Type of the Service Method

According to the WSDL definitions, there can be various Message Exchange Patterns defined for web services. These require the client to use possible invocation mechanism to handle the service invocations. For example if the client is invoking a service method which is defined as IN-ONLY operation, then the client should be able to use a method in the client API which is capable of handling this type of requests.

All these variations give rise to several Client API methods which will ultimately ease the service invocation for a web service client. For Axis 2, currently we are providing following methods in the Call API provided

  1. Robust Invocation
  2. Fire and Forget invocation
  3. Blocking Invocation of type In-Out
  4. Non Blocking Invocation of type In-Out
    •  Method 1: Without a Client Side Listener
    •  Method 2: With a Client Side Listener

Architecture

Following architecture was derived for the Axis 2 client side, to support the above patterns the. A description of each component is given below.

Figure 1 ? Axis Client Architecture

Client

This is the web service client that actually utilizes the service.

Call

This is the API that the Axis client should use to invoke the web services. Followings are the methods that the client can use in this API.

public void setTo(EndpointReference EPR)
public void getTO() 
public void setTransportType(String transport) 
public void setListenerTransport(String Listenertransport, boolean useSeparateListener) 
public void setAction(String action)
public void sendAsync(SOAPEnvelope envelope) throws AxisFault 
 public void send(SOAPEnvelope envelope) throws AxisFault 
 public SOAPEnvelope sendReceive(SOAPEnvelope envelope) throws AxisFault 
 public void sendReceiveAsync(SOAPEnvelope envelope,final Callback callback) throws AxisFault 
 

Engine

This is Axis 2 engine and it does not make any difference whether the engine is used in the client side or the server side. 

Correlator

Correlator is required when client uses the non-blocking API to invoke a web service. Its stores callback object with a key field as messageID. This is a singleton class which consists of following two methods.

                
   public Callback getCorrelationInfo(String MessageID) 

Listener

A separate listener is required to provide the asynchronous communication between the client and the service. That is, when the client retrieves the response (if any) using a separate transport connection, listener will act as an addressable end point to the service so that it can send the service responses directly to the listener.

ClientProvider

This is provider used in the client side.(The name should be changed later). This is only used when the client uses asynchronous web service invocation pattern, that is when a separate listener is used to retrieve the response. The service response is received using the same way that the axis engine receives a request. So the ProviderX will represent the end of the execution chain of the engine and it will set the response to the callback object.

 

How Axis 2 Architecture Supports the above Message Patterns

Robust Invocation

This invocation is mainly a one way operation. However it supports the returning faults from the service. The transport protocol used in this message pattern should be bi-directional.  The following code snippet shows how the client can use above method of invocation and the sequence diagram shows the complete message.

Code Snippet

call.setTo(EPR)
 call.setAction(String)
call.setTransportType(String)
call.send(SOAPEnvelope)  
 

Message Path and Sequence Diagram

a -> call.send(SOAPEnvelope)
b -> engine.send( ..) 
c -> Send the SOAP message 
 
 

Figure 2- Sequence diagram corresponding to send ()

Fire and Forget Invocation

This method of invocation does not wait for any kind of response, not even for a fault. Once the request is written to the wire the method immediately returns to the client. Transport can be either unidirectional or bi-directional. Following code snippet shows how the client can use above API method and the sequence diagram shows the complete message.

Code Snippet

call.setTo(EPR)
call.setAction(String)
call.setTransportType(String)
call.sendAsync(SOAPEnvelope) 

Message Path and Sequence Diagram

a -> call.send(SOAPEnvelope) 
b -> engine.send( ..) 
c -> Send the SOAP message 

Figure 3 ? Sequence diagram corresponds to sendAsync()

Blocking Invocation of type In-Out

This invocation pattern lets the client to invoke a web service and wait till the response is received before proceeding to the next line of invocation. This is very much similar to the Call.invoke() with response types in Axis 1.1. In this approach, the transport specified should be a bi-directional transport and the response is retrieved using the same transport connection. The client will hang till the entire communication completes.

Code Snippet 

 call.setAction(String)
call.setTransportType(String)
SOAPEnvelope env=call.sendReceive(SOAPEnvelope) 

Message Path and Sequence Diagram

a -> call.sendReceive(SOAPEnvelope)
b- > engine.send (..) 
c -> Send the SOAP message 
d -> Receive the response over the synchronous transport 
w -> ProviderX will be called as the last step in engine.receive(..) 
e -> provider returns      
f -> Call hand over the response to the client 

Figure 4 ? Sequence diagram corresponds to sendRecieve()

Non Blocking Invocation of type In-Out

Using this method client can access In-Out type web service operations. There are two ways that the client can use this invocation pattern.

Method 1: Without a Client Side Listener

The communication happens using a single transport connection. With respect to the transport protocol used, the web service response is received using the same connection. However the client will not block till it receive the response. Instead it can proceed to the next line of execution by registering a Callback object.  The following code snippet shows how the client can use above API method and the sequence diagram shows the complete message. To use this pattern client should use the value ?true? for the parameter ?useSeparateListener? in the setListenerTransport(..) method.

Code Snippet

call.setTO(EPR)
call.setAction(String)          
call.setTransportType(String)
call.setListenerTransport(String transportType,boolean useSeparateListener)
call.sendReceiveAsync (SOAPEnvelope, Callback) 

Message Path and Sequence Diagram

a -> call.sendReceiveAsync (SOAPEnvelope, callbackObj) 
p -> correlator.addCorrelationInfor(msgID,allbackObjRef) 
b- > engine.send (..) 
c -> Send the SOAP message 
d -> Receive the response over the synchronous transport 
w -> ProviderX will be called as the last step in engine.receive(..) 
q -> correlator.getCorrelationInfo(msgID) 
g -> callbackObj.onComplete() 

Figure 5 ? Sequence diagram corresponds to sendRecieveAysn with two way transport

Method 2: With a Client Side Listener

In this method client will have the usage of non-blocking API with a separate listener to accept the service response asynchronously. Outgoing transport does not wait for the response. Instead corresponding incoming message is processed by different transport, which is created by call object while it is sending the request. The correlation between the request and the response messages is achieved using a similar message ID mechanism as in WS-Addressing. Once the WS-Addressing support is implemented the client will only use <wsa:MessageID> and the <was:RelatesTo> headers to achieve the correlation.

The following code snippet shows how the client can use that above API method and the sequence diagram shows the complete message. To use this pattern client should use the value ?false? for the parameter ?useSeparateListener? in the setListenerTransport(..) method.

Code Snippet

call.setTO(EPR) 
call.setAction(String) 
call.setTransportType(String)
call.setListenerTransport(String transportType,boolean useSeparateListener)
call.sendReceiveAsync (SOAPEnvelope, Callback) 

Message Path and Sequence Diagram

a -> call.sendReceiveAsync (SOAPEnvelope, callbackObj)
 p -> correlator.addCorrelationInfor(msgID,allbackObjRef) 
b- > engine.send (..) 
 c -> Send the SOAP message 
 r -> Receive the response by the listener 
 s -> engine.receive(..) 
 w -> ProviderX will be called as the last step in engine.receive(..) 
 q -> correlator.getCorrelationInfo(msgID) 
g -> callbackObj.onComplete() 

Figure 6 ? Sequence diagram corresponds to sendRecieveAync with one way transport.

Asynchronous invocation with one way transport

The programming model almost similar to asynchronous invocation with two way transport. Only difference is that  for outgoing and incoming messages, it uses two engine instances, and outgoing transport dose not wait for response. Instead, corresponding incoming message is processed by different transport which is created by call object while it is sending the request. Here the Listener is the newly created transport, which is running to get the incoming message. Corresponding sequence diagram is shown in Figure 6, code snippet and message paths are described below.

Code Snippet

call.setTO(EPR)
 call.setAction(String) 
call.setListenerTransport(?http?, false) 
call.sendReceiveAsync(SOAPEnvelope, Callback) 

Message paths

a -> call.sendReceiveAsync (SOAPEnvelope, callbackObj) p -> correlator.addCorrelationInfor(msgID,allbackObjRef) 
b- > engine.send (..) 
c -> Send the SOAP message 
r -> Receive the response by the listener 
s -> engine.receive(..) 
w -> ProviderX will be called as the last step in engine.receive(..) 
 q -> correlator.getCorrelationInfo(msgID) 
g -> callbackObj.onComplete() 

Figure 6 ? Sequence diagram corresponds to sendRecieveAync with one way transport.

What is supported in M1

From the above interaction patterns for Milestone1, we have only implemented the following two types.

  • Blocking Invocation of type In-Out
  • Non Blocking Invocation of type In-Out --> Method 1: Without a Client Side Listener

However from the client's point of view the other interaction patterns are also implemented except the Non Blocking Invocation of type In-Out with a client side listener, but still we could not test them since we need complete server implementation to test them.