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.
Followings will decide the interaction patterns between client and the service.
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.
Note that client can adopt any one of the above two methods, independent of the way service has been implemented.
The protocol used to send the SOAP message can be categorized mainly in to two types.
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.
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
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
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
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 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)
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.
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.
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 ()
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()
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()
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.
call.setTO(EPR) call.setAction(String) call.setListenerTransport(?http?, false) call.sendReceiveAsync(SOAPEnvelope, Callback)
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.
From the above interaction patterns for Milestone1, we have only implemented the following two types.
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.