blob: 92fe551a7d05691bdc0c6b01ce7893097f831822 [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>Axis2 User's Guide</title>
<meta name="generator" content="amaya 9.2.1, see http://www.w3.org/Amaya/">
</head>
<body lang="en-US" dir="ltr">
<h4><a name="Axis2_User's_Guide">Axis2 User's Guide</a></h4>
<p><i>Version 0.94</i></p>
<i>User Feedback: <a
href="mailto:axis-user@ws.apache.org">axis-user@ws.apache.org</a></i>
<p align="right">Pages: <a href="userguide.html">Content</a>, <a
href="userguide1.html">1</a>, <a href="userguide2.html">2</a>, <b>3</b>, <a
href="userguide4.html">4</a>, <a href="userguide5.html">5</a></p>
<p><b><font size="4">Note (on samples):</font></b> In this page of the user's
guide we will look at how to write Web Service Clients using Axis2. All the
user's guide samples are located at the <b><font
color="#000000">"samples/userguide/src"</font></b> directory of the binary
distribution. So... let's explore the samples.</p>
<h2><a name="Web_Service_Clients_Using_Axis2">Web Service Clients Using
Axis2</a></h2>
<p>Now let's see how we can write a Web Service Client to use this Web
Service.</p>
<p>Web services can be used to provide wide range of functionality to the
users ranging from simple, less time consuming  operations such as
"getStockQuote"  to time consuming business services. When we utilize (invoke
using client applications) these Web Service we cannot use some simple
generic invocation paradigm that suites 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 and IN-OUT operation that take
long time to complete, then most of the time 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 in to play when we need them. Let's try to analyze some common
service invocation paradigms.</p>
<p>Many web service engines provide the 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 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 <strong>Non-Blocking API</strong> as
<b>API Level Asynchrony.</b></p>
<p>Both these mechanisms use single transport connection to send the request
and to receive the response. They severely lags the capability of using two
transport connections for the request and the response (either One-Way of
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 <strong>two
separate transport connections for request and response</strong>. The
asynchronous behavior that we gain using this solution can be called
<b>Transport Level Asynchrony</b>.</p>
<p>By combining API Level Asynchrony &amp; Transport Level Asynchrony 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>Simplest and the 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. No 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>Below we describe how to write Web Services Clients using Axis2. This can
be done in two methods:</p>
<ol>
<li><a href="#Writing_Web_Service_Clients_using_Axis2's_Primary_APIs">Using
the Axis2's primary APIs</a></li>
<li><p><a
href="#Writing_Web_Service_Clients_using_Code_Generation_with_Data_Binding_Support">Using
stubs generated with data binding support</a>, making the life easy for
developers writing Web Service client applications</p>
</li>
</ol>
<h3><a name="Writing_Web_Service_Clients_using_Axis2's_Primary_APIs">Writing
Web Service Clients Using Axis2's Primary APIs</a></h3>
<h4><a name="EchoBlockingClient">EchoBlockingClient</a></h4>
<p>Axis2 provides the user with several invocation patterns for Web Services,
ranging from pure blocking single channel invocations to a 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: #24C113">
Options options = new Options();
options.setTo(targetEPR);
options.setListenerTransportProtocol(Constants.TRANSPORT_HTTP);
options.setUseSeparateListener(false);
ServiceClient serviceClient = new ServiceClient();
serviceClient.setOptions(options);
OMElement result = sender.sendReceive(payload);
</span>
StringWriter writer = new StringWriter();
result.serializeWithCache(new OMOutput(XMLOutputFactory.newInstance().createXMLStreamWriter(writer)));
writer.flush();
System.out.println(writer.toString());
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}
}</pre>
</source>
<p>The green lines shows the set of operations that you need to perform
inorder to invoke a web service. The rest is used to create the OMElement
that needs to be sent and display the response OMElement. To test this
client, use the provided ant build file that can be found in the
"Axis2Home/samples" directory. Run the "testEchoBlockingClient" target . If
you can see the response OMElement printed in your command line,  then you
have successfully tested the client. </p>
<h4><a name="PingClient">PingClient</a></h4>
<p>In the Web Service "MyService" we had a IN-ONLY operation with the name
"ping" (see <a href="userguide2.html#Web_Services_Using_Axis2">Web Services
Using Axis2</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);
}
catch (AxisFault axisFault) {
axisFault.printStackTrace();
}</pre>
<p>Since we are accessing a IN-ONLY operation we can directly use the
"fireAndForget()" in ServiceClient to invoke this operation , and that will
not block the invocation, hence it will return the control immediately back
to the client. You can test this client by running the target
"testPingClient" of the ant build file at "Axis2Home/samples".</p>
<p>We have invoked the two operations in our service. Are we done? No! There
are lot more to explore. Let's see some other ways to invoke the same
operations...</p>
<h4><a name="EchoNonBlockingClient">EchoNonBlockingClient</a></h4>
<p>In the EchoBlockingClient once the "serviceCleint.sendReceive(payload);"
is called, the client is blocked till the operation is completed. This
behavior is not desirable when there are many Web Service invocations to be
done in a single client application. 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
"Axis2Home/samples/userguide/src/userguide/clients" with the name
EchoNonBlockingClient. If we consider the changes that user 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. 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
invocations and provides the user 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
"testEchoNonBlockingClient" target of the ant file found at the
"Axis2Home/samples" directory.</p>
<h4><a name="EchoNonBlockingDualClient">EchoNonBlockingDualClient</a></h4>
<p>The solution provided by the Non-Blocking API has one limitation when it
comes to  Web Service invocations which takes long time to complete. The
limitation is due to the use of single transport connection to invoke the Web
Service and to retrieve the response. In other words, client API provides a
non blocking invocation mechanism for the users, but the request and the
response comes 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/Submission/ws-addressing/"
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
users 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();<br> options.setTo(targetEPR);<br> options.setListenerTransportProtocol(Constants.TRANSPORT_HTTP);
//The boolean flag informs the axis2 engine to use two separate transport connection
//to retrieve the response.
<br> options.setUseSeparateListener(true);
ServiceClient serviceClinet = new ServiceClinet();
<br> serviceClinet.setOptions(options);</pre>
<pre>
//Callback to handle the response
Callback callback = new Callback() {
public void onComplete(AsyncResult result) {
try {
StringWriter writer = new StringWriter();
result.serializeWithCache(new OMOutput(XMLOutputFactory.newInstance()
.createXMLStreamWriter(writer)));
writer.flush();
System.out.println(writer.toString());
} catch (XMLStreamException e) {
onError(e);
}
}
public void onError(Exception e) {
e.printStackTrace();
}
};
//Non-Blocking Invocation
serviceClinet.sendReceiveNonblocking(payload, callback);
//Wait till the callback receives the response.
while (!callback.isComplete()) {
Thread.sleep(1000);
}
serviceClinet.finalizeInvoke();
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}</pre>
<p><font color="#0000ff"><font color="#000000">The boolean flag (value true)
in the "<b>options.setUseSeparateListener(...)</b>" method informs the Axis2
engine to use separate transport connections for request and response.
Finally "<b>serviceClinet.finalizeInvoke()</b>" informs the Axis2 engine to
stop the client side listener started to retrieve the
response.</font></font></p>
<p>Before we run the sample client we have one more step to perform. As
mentioned earlier Axis2 uses addressing based correlation mechanism, hence we
need to "engage" addressing module in the server side as well. According to
the Axis2 architecture, addressing module is deployed in the
"<strong>pre-dispatch</strong>" phase (See <a
href="Axis2ArchitectureGuide.html" target="_blank">Architecture Guide</a> for
more details about phases)  and hence "engaging" means simply adding module
reference in the "axis2.xml" (NOT the "services.xml"). Now add the following
line to the "axis2.xml" that you can find in the "/webapps/axis2/WEB-INF"
directory in the servlet container. </p>
<pre style="margin-bottom: 0.2in"> &lt;module ref="addressing"/&gt;</pre>
<p>Note: <font color="#000000">Once you change the "axis2.xml" you need to
restart the servlet container.</font></p>
<p>This will enable the addressing in the server side. Now you can test the
"TestEchoNonBlockingDualClient" using the "testEchoNonBlockingDualClient"
target of the ant file found at "Axis2Home/samples" directory. If you see the
response OMElement printed in the client side, then you have successfully
tested the Non Blocking API with two transport channels at the client
side.</p>
<h4><a name="EchoBlockingDualClient">EchoBlockingDualClient</a></h4>
<p>This is again a Two-Way transport request/response client, but this time,
we use a Blocking API in the client code. Sample code for this can be found
in the "Axis2Home/samples/userguide/src/userguide/clients/" directory and the
explanation is similar to the <a
href="#EchoNonBlockingDualClient">EchoNonBlockingDualClient</a>, except that
here we do not use a callback object to handle response. This is a very
useful mechanism when the service invocation is IN-OUT in nature and the
transports are One-Way (e.g. SMTP). For the sample client we use two HTTP
connections for request and response. User can test this client using the
"echoBlockingDualClient" target of the ant build file found in the
"Axis2Home/samples" directory.</p>
<p>See <a href="http-transport.html" target="_blank">Configuring
Transports</a> for use different transports.</p>
<h3><a
name="Writing_Web_Service_Clients_using_Code_Generation_with_Data_Binding_Support">Writing
Web Service Clients using Code Generation with Data Binding Support</a></h3>
<p>Axis2 provides the data binding support for Web Service client as well.
The user can generate the required stubs from a given WSDL with the other
supporting classes. Let's generate stubs for the WSDL used earlier to
generate the skeleton for the "Axis2SampleDocLitPortType". Simply run the
WSDL2Java tool that can be found in the bin directory of the Axis2
distribution using the following command:</p>
<pre style="margin-bottom: 0.2in">WSDL2Java -uri ..\samples\wsdl\Axis2SampleDocLit.wsdl -o ..\samples\src -p org.apache.axis2.userguide</pre>
<p>This will generate the required stub "Axis2SampleDocLitPortTypeStub.java"
that can be used to invoke the Web Service Axis2SampleDocLitPortType. Let's
see how we can use this stub to write Web Service clients to utilize the Web
Service Axis2SampleDocLitPortType (the service that we have already
deployed).</p>
<h4><a name="Client_for_echoVoid_Operation">Client for echoVoid
Operation</a></h4>
<p>Following code fragment shows the necessary code for utilizing the
echoVoid operation of the Axis2SampleDocLitPortType that we have already
deployed. In this operation, a blank SOAP body element is sent to the Web
Service and the same SOAP envelope is echoed back.</p>
<pre> try {
//Create the stub by passing the AXIS_HOME and target EPR.
//We pass null to the AXIS_HOME and hence the stub will use the current directory as the AXIS_HOME
Axis2SampleDocLitPortTypeStub stub = new Axis2SampleDocLitPortTypeStub(null,
"http://localhost:8080/axis2/services/Axis2SampleDocLitPortType");
stub.echoVoid();
} catch (Exception e) {
e.printStackTrace();
}</pre>
<h4><a name="Client_for_echoString_Operation">Client for echoString
Operation</a></h4>
<p>Following code fragment shows the necessary code for utilizing the
echoString operation of the Axis2SampleDocLitPortType that we have already
deployed. The code is very simple to understand and the explanations are in
the form of comments.</p>
<pre>try {
//Create the stub by passing the AXIS_HOME and target EPR.
//We pass null to the AXIS_HOME and hence the stub will use the current directory as the AXIS_HOME
Axis2SampleDocLitPortTypeStub stub= new Axis2SampleDocLitPortTypeStub(null,
"http://localhost:8080/axis2/services/Axis2SampleDocLitPortType");
//Create the request document to be sent.
EchoStringParamDocument reqDoc= EchoStringParamDocument.Factory.newInstance();
reqDoc.setEchoStringParam("Axis2 Echo");
//invokes the web service.
EchoStringReturnDocument resDoc=stub.echoString(reqDoc);
System.out.println(resDoc.getEchoStringReturn());
} catch (Exception e) {
e.printStackTrace();
}</pre>
<p>Similarly following code fragments show client side code for
echoStringArray operation and echoStruct operation respectively.</p>
<h4><a name="Client_for_echoStringArray_Operation">Client for echoStringArray
Operation</a></h4>
<pre>try {
//Create the stub by passing the AXIS_HOME and target EPR.
//We pass null to the AXIS_HOME and hence the stub will use the current directory as the AXIS_HOME
Axis2SampleDocLitPortTypeStub stub = new Axis2SampleDocLitPortTypeStub(null,
"http://localhost:8080/axis2/services/Axis2SampleDocLitPortType");
//Create the request document to be sent.
EchoStringArrayParamDocument reqDoc = EchoStringArrayParamDocument.Factory.newInstance();
ArrayOfstringLiteral paramArray = ArrayOfstringLiteral.Factory.newInstance();
paramArray.addString("Axis2");
paramArray.addString("Echo");
reqDoc.setEchoStringArrayParam(paramArray);
EchoStringArrayReturnDocument resDoc = stub.echoStringArray(reqDoc);
//Get the response params
String[] resParams = resDoc.getEchoStringArrayReturn().getStringArray();
for (int i = 0; i &lt; resParams.length; i++) {
System.out.println(resParams[i]);
}
} catch (Exception e) {
e.printStackTrace();
}</pre>
<h4><a name="Client_for_echoStruct_Operation">Client for echoStruct
Operation</a></h4>
<pre>try {
//Create the stub by passing the AXIS_HOME and target EPR.
//We pass null to the AXIS_HOME and hence the stub will use the current directory as the AXIS_HOME
Axis2SampleDocLitPortTypeStub stub = new Axis2SampleDocLitPortTypeStub(null,
"http://localhost:8080/axis2/services/Axis2SampleDocLitPortType");
//Create the request Document
EchoStructParamDocument reqDoc = EchoStructParamDocument.Factory.newInstance();
//Create the complex type
SOAPStruct reqStruct = SOAPStruct.Factory.newInstance();
reqStruct.setVarFloat(100.50F);
reqStruct.setVarInt(10);
reqStruct.setVarString("High");
reqDoc.setEchoStructParam(reqStruct);
//Service invocation
EchoStructReturnDocument resDoc = stub.echoStruct(reqDoc);
SOAPStruct resStruct = resDoc.getEchoStructReturn();
System.out.println("floot Value :" + resStruct.getVarFloat());
System.out.println("int Value :" + resStruct.getVarInt());
System.out.println("String Value :" + resStruct.getVarString());
} catch (Exception e) {
e.printStackTrace();
}</pre>
<p align="right"><a href="userguide2.html"><img src="images/arrow_left.gif">
Previous</a> | <a href="userguide4.html">Next <img
src="images/arrow_right.gif"></a></p>
<p>Pages: <a href="userguide.html">Content</a>, <a
href="userguide1.html">1</a>, <a href="userguide2.html">2</a>, <b>3</b>, <a
href="userguide4.html">4</a>, <a href="userguide5.html">5</a></p>
</body>
</html>