blob: 8b207811800a0863b38efb4f9496e37dcc12a6ac [file] [log] [blame]
<html>
<head>
<meta http-equiv="content-type" content="">
<title></title>
<link href="../css/axis-docs.css" rel="stylesheet" type="text/css" media="all" />
</head>
<body>
<a name="Web_Service_Clients_Using_Axis2"></a>
<h1>Writing Web Service Clients Using Axis2's Primary APIs</h1>
<p>This section presents complex yet powerful <strong>XML based client
API</strong> which is intended for advanced users. However if you are a new
user we recommend using code generation given in the <a
href="userguide.html">user guide</a>.</p>
<p>Web services can be used to provide a wide-range of functionality to the
user from simple, less time consuming operations such as "getStockQuote" to
time consuming business services. When we utilize (invoke using client
applications) these Web services we cannot use simple generic invocation
paradigms that suite all the timing complexities involved in the service
operations. For example, if we use a single transport channel (such as HTTP)
to invoke a Web service with an IN-OUT operation that takes a long time to
complete, then most often we may end up with "connection time outs". On the
other hand, if there are simultaneous service invocations that we need to
perform from a single client application, then the use of a "blocking" client
API will degrade the performance of the client application. Similarly, there
are various other consequences such as One-Way transports that come into play
when we need them. Let's try to analyze some common service invocation
paradigms.</p>
<p>Many Web service engines provide users with a Blocking and Non-Blocking
client APIs.</p>
<ul>
<li><p style="margin-bottom: 0in"><b>Blocking API</b> -Once the service
invocation is called, the client application hangs and only gets control
back when the operation completes, after which the client receives a
response or a fault. This is the simplest way of invoking Web services
and it also suites many business situations.</p>
</li>
<li><p><b>Non-Blocking API </b>- This is a callback or polling based API,
hence once a service invocation is called, the client application
immediately gets the control back and the response is retrieved using the
callback object provided. This approach provides the flexibility to the
client application to invoke several Web services simultaneously without
blocking the operation already invoked.</p>
</li>
</ul>
<p>Both these mechanisms work in the API level. Let's name the asynchronous
behavior that we can get using the Non-Blocking API as <b>API Level
Asynchrony.</b></p>
<p>Both these mechanisms use single transport connections to send the request
and to receive the response. They severely lag the capability of using two
transport connections for the request and the response (either One-Way or
Two-Way). So both these mechanisms fail to address the problem of long
running transactions (the transport connection may time-out before the
operation completes). A possible solution would be to use two separate
transport connections for request and response. The asynchronous behavior
that we gain using this solution can be called <b>Transport Level
Asynchrony</b>.</p>
<p>By <strong>combining API Level Asynchrony &amp; Transport Level
Asynchrony</strong> we can obtain four different invocation patterns for Web
services as shown in the following table.</p>
<a name="table1"></a>
<table width="100%" border="1" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td width="33%" height="19"><p><strong>API
(Blocking/Non-Blocking)</strong></p>
</td>
<td width="33%"><p><strong>Dual Transports (Yes/No)</strong></p>
</td>
<td width="33%"><p><strong>Description</strong></p>
</td>
</tr>
<tr>
<td width="33%" height="19"><p>Blocking</p>
</td>
<td width="33%"><p>No</p>
</td>
<td width="33%"><p>The simplest and more familiar invocation pattern</p>
</td>
</tr>
<tr>
<td width="33%" height="19"><p>Non-Blocking</p>
</td>
<td width="33%"><p>No</p>
</td>
<td width="33%"><p>Using callbacks or polling</p>
</td>
</tr>
<tr>
<td width="33%" height="19"><p>Blocking</p>
</td>
<td width="33%"><p>Yes</p>
</td>
<td width="33%"><p>This is useful when the service operation is IN-OUT
in nature but the transport used is One-Way (e.g. SMTP)</p>
</td>
</tr>
<tr>
<td width="33%" height="19"><p>Non-Blocking</p>
</td>
<td width="33%"><p>Yes</p>
</td>
<td width="33%"><p>This is can be used to gain the maximum asynchronous
behavior. Non blocking in the API level and also in the transport
level</p>
</td>
</tr>
</tbody>
</table>
<p>Axis2 provides the user with all these possibilities to invoke Web
services.</p>
<p>Following section present clients that use different possibilities
presented above to invoke a Web Service using <code>ServiceClient</code>s.
All samples mentioned in this guide are located at the <b><font
color="#000000">"samples\userguide\src"</font></b> directory of the binary
distribution.</p>
<p>This section presents four types of clients.</p>
<ol>
<li>Request-Response, Blocking Client</li>
<li>One Way Client</li>
<li>Request-Response, Non-Blocking that uses one transport connection</li>
<li>Request-Response, Non-Blocking that uses two transport connections</li>
</ol>
<a name="EchoBlockingClient"></a>
<h4>Request-Response, Blocking Client</h4>
<p>Axis2 provides the user with several invocation patterns for Web services,
ranging from pure blocking single channel invocations to non-blocking dual
channel invocations. Let's first see how we can write a client to invoke
"echo" operation of "MyService" using the simplest blocking invocation. The
client code you need to write is as follows.</p>
<source><pre> try {
OMElement payload = ClientUtil.getEchoOMElement();
<span style="color: rgb(36, 193, 19);">
Options options = new Options();
options.setTo(targetEPR); // this sets the location of MyService service
ServiceClient serviceClient = new ServiceClient();
serviceClient.setOptions(options);
OMElement result = serviceClient.sendReceive(payload);
</span>
System.out.println(result);
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
}
}</pre>
</source>
<p>1. The lines highlighted in green lines show the set of operations that
you need to perform in order to invoke a Web service.</p>
<p>2. The rest is used to create the OMElement that needs to be sent and
display the response OMElement.</p>
<p>To test this client, use the provided ant build file that can be found in
the "<strong>Axis2_HOME/samples/userguide</strong>" directory. Run the
"run.client.blocking" target. If you can see the response OMElement printed
in your command line, then you have successfully tested the client.</p>
<a name="PingClient"></a>
<h4>One Way Client</h4>
<p>In the Web service "MyService" we had an IN-ONLY operation with the name
"ping" (see <a href="userguide.html#Web_Services_Using_Axis2">Creating a New Web Service</a>). Let's write a client to invoke this operation. The client
code is as follows:</p>
<pre> try {
OMElement payload = ClientUtil.getPingOMElement();
Options options = new Options();
options.setTo(targetEPR);
ServiceClient serviceClient = new ServiceClient();
serviceClient.setOptions(options);
serviceClient.fireAndForget(payload);
/**
* We have to block this thread untill we send the request , the problem
* is if we go out of the main thread , then request wont send ,so
* you have to wait some time :)
*/
Thread.sleep(500);
}
catch (AxisFault axisFault) {
axisFault.printStackTrace();
}</pre>
<p>Since we are accessing an IN-ONLY operation we can directly use the
<code>fireAndForget()</code> in ServiceClient to invoke this operation. This
will not block the invocation and will return the control immediately back to
the client. You can test this client by running the target "run.client.ping"
of the ant build file at "<strong>Axis2Home/samples/userguide</strong>".</p>
<p>We have now invoked the two operations in our service. Are we done? No!
There's a lot more to explore. Let's see some other ways to invoke the same
operations.</p>
<a name="EchoNonBlockingClient"></a>
<h4>Request-Response, Non-Blocking that uses one transport connection</h4>
<p>In the "EchoBlockingClient" once the
<code>serviceClient.sendReceive(payload);</code> is called, the client is
blocked till the operation is complete. This behavior is not desirable when
there are many Web service invocations to be done in a single client
application or within a GUI. A solution would be to use a Non-Blocking API to
invoke Web services. Axis2 provides a callback based non-blocking API for
users.</p>
<p>A sample client for this can be found under
"<strong>Axis2_HOME/samples/userguide/src/userguide/clients</strong>" with
the name "EchoNonBlockingClient". If we consider the changes that users may
have to do with respect to the "EchoBlockingClient" that we have already
seen, it will be as follows:</p>
<pre style="margin-bottom: 0.2in">serviceClient.sendReceiveNonblocking(payload, callback);</pre>
<p>The invocation accepts a callback object as a parameter. Axis2 client API
provides an abstract Callback with the following methods:</p>
<pre>public abstract void onComplete(AsyncResult result);
public abstract void onError(Exception e);
public boolean isComplete() {}</pre>
<p>The user is expected to implement the "onComplete " and "onError " methods
of their extended call back class. The Axis2 engine calls the "onComplete"
method once the Web service response is received by the Axis2 Client API
(ServiceClient). This will eliminate the blocking nature of the Web service
invocation and provide users with the flexibility to use Non Blocking API for
Web service Clients.</p>
<p>To run the sample client ("EchoNonBlockingClient") you can simply use the
<code>run.client.nonblocking</code> target of the ant file found at the
"<strong>Axis2_HOME/samples/userguide</strong>" directory.</p>
<a name="EchoNonBlockingDualClient"></a>
<h4>Request-Response, Non-Blocking that uses two transport connections</h4>
<p>The solution provided by the Non-Blocking API has one limitation when it
comes to Web service invocations which take a long time to complete. The
limitation is due to the use of single transport connections to invoke the
Web service and to retrieve the response. In other words, client API provides
a non blocking invocation mechanism for users, but the request and the
response come in a single transport (Two-Way transport) connection (like
HTTP). Long running Web service invocations or Web service invocations using
One-Way transports (like SMTP) cannot be utilized by simply using a non
blocking invocation.</p>
<p>The trivial solution is to use separate transport connections (either
One-Way or Two-Way) for the request and response. The next problem that needs
to be solved is the correlation (correlating the request and the response).
<a href="http://www.w3.org/2002/ws/addr/" target="_blank">WS-Addressing</a>
provides a neat solution to this using &lt;wsa:MessageID&gt; and
&lt;wsa:RelatesTo&gt; headers. Axis2 provides support for addressing based
correlation mechanism and a complying Client API to invoke Web services with
two transport connections. (Core of Axis2 does not depend on WS-Addressing,
but contains a set of parameters like in addressing that can be populated in
any means. WS-Addressing is one of the uses that may populate them. Even the
transports can populate these. Hence Axis2 has the flexibility to use
different versions of addressing)</p>
<p>Users can select between Blocking or Non-Blocking APIs for the Web service
clients with two transport connections. By simply using a boolean flag, the
same API can be used to invoke Web services (IN-OUT operations) using two
separate transport connections. Let's see how it's done using an example.
Following code fragment shows how to invoke the same "echo" operation using
Non-Blocking API with two transport connections<strong>. The ultimate
asynchrony!!</strong></p>
<pre> try {
OMElement payload = ClientUtil.getEchoOMElement();
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
options.setUseSeparateListener(true);
options.setAction("urn:echo"); // this is the action mapping we put within the service.xml
//Callback to handle the response
Callback callback = new Callback() {
public void onComplete(AsyncResult result) {
System.out.println(result.getResponseEnvelope());
}
public void onError(Exception e) {
e.printStackTrace();
}
};
//Non-Blocking Invocation
sender = new ServiceClient();
sender.engageModule(new QName(Constants.MODULE_ADDRESSING));
sender.setOptions(options);
sender.sendReceiveNonBlocking(payload, callback);
//Wait till the callback receives the response.
while (!callback.isComplete()) {
Thread.sleep(1000);
}
//Need to close the Client Side Listener.
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
sender.cleanup();
} catch (AxisFault axisFault) {
//have to ignore this
}
}</pre>
<p>The boolean flag (value true) in the
<b><code>options.setUseSeparateListener(...)</code></b> method informs the
Axis2 engine to use separate transport connections for request and response.
Finally <b><code>sender.cleanup()</code></b> informs the Axis2 engine to stop
the client side listener started to retrieve the response.</p>
<p>To run the sample client ("EchoNonBlockingDualClient") you can simply use
the "run.client.nonblockingdual" target of the ant file found at the
"<strong>Axis2_HOME/samples/userguide/</strong>" directory.</p>
</body>
</html>