Apache Axis2 is the
successor to the renowned Apache Axis SOAP project. Axis2 is a
major improvement of the web services core engine and aims to be
the platform to build applications based on service oriented architecture (SOA). It is blazing the trail by being a clean and
extensible open source web services platform. The architecture of
Axis2 is highly flexible and supports additional functionalities,
features and enhancements such as:
AXIOM
(AXIs2 Object Model), a new XML infoset representation with
streaming support
An improved client with both synchronous and asynchronous
support
Native support for MTOM (Message Transmission Optimization
Mechanism)
Full support for WSDL 2.0 defined MEPs (Message Exchange
Patterns)
This document is mainly focused on Axis2 client-related
technologies and their usage. At the end this article, you should
understand the key terminologies and concepts, and most importantly how
to use Axis2 client for your SOA applications.
The Axis2 Client API
There are two main usage patterns for Axis2. One is as a server
to deploy web services and the other as a client to invoke services.
When it comes to the client side, there are numerous requirements
to cater to in today's web services. Asynchronous or non-blocking
invocation patterns are assumed to be at the top of this
requirements list. As stated above, one of the key feature in Axis2
is asynchronous web service invocation support. If you are not
familiar with synchronous and asynchronous web service invocation,
Figures 1 and 2 will help you to understand them. In the
synchronous (blocking) case, a client sends the message and waits
until it receives a response, while in an asynchronous (non-blocking)
invocation, the client sends the message but does not wait for the
response. For asynchronous uses, there will be some other mechanism
(such as callback or pooling) to receive the response; Axis2 uses
callback mechanisms in asynchronous web service invocations.
Figure 1. Invoking a service in a synchronous manner
Figure 2. Invoking a service in an asynchronous manner
In addition to synchronous and asynchronous invocations, the
client API has been divided into two main sub-APIs:
An easy-to-use API for average users:
ServiceClient
An API for advanced tasks: OperationClient
Working with ServiceClient
As mentioned above, the ServiceClient API provides
an easy way of invoking services for average users. Axis2 assumes
that an average user is a person who just cares about the payload
(i.e., the SOAP body) of the message and nothing else. Advanced
users are considered to be the those who deal not only with the
payload but also with the full SOAP envelope.
Using ServiceClient, you can invoke a service in a
synchronous manner or in an asynchronous manner, which will be discussed
later.
To give better flexibility, ServiceClient provides
a set of different constructors from which you can pick the correct
constructor to cater to your requirements. For each
ServiceClient you create, there has to be an Axis2
runtime to invoke the service. An Axis2 runtime is called a
ConfigurationContext and it consists of configurations,
parameters, and other relevant data. Semantically,
ConfigurationContext is similar to
ServletContext in an application server.
Creating a ServiceClient using Its Default
Constructor
The easiest way to create a ServiceClient is to use
its default constructor as shown below. In this case, it creates a
ConfigurationContext using the Axis2 default
configuration file. Even if you create ServiceClient
in this manner, you can use it to invoke any available web
service.
ServiceClient serviceClient = new ServiceClient ();
One important point to note here is that if you try to create an
instance of ServiceClient using the above constructor
inside a running Axis2 server (or inside an application server
where Axis2 is deployed), then rather than creating a
ConfigurationContext from the Axis2 default
configuration, it uses the server's runtime as its
ConfigurationContext. In that case, the client will
have the luxury of accessing server's configuration data.
Creating a ServiceClient using Your own
ConfigurationContext
There are many instances where you want to share the same Axis2
runtime across multiple clients or want to reuse the same runtime
for every invocation. Also, maybe you do not like Axis2
default configuration and you want to create
a ConfigurationContext instance using your own
configurations. In such situations it is best to use the following
constructor.
ServiceClient serviceClient = new ServiceClient (configContext, axisService);
As you can see in the constructor, it takes two arguments,
ConfigurationContext and AxisService. The
AxisService is a metadata representation of a web
service in Axis2. On the client side, you do not need to worry too
much about this. The idea of the AxisService argument
is to provide a configured service proxy, which most of the time
you are not going to use. So when you use this constructor, you can
pass null for the AxisService
argument.
Creating a Dynamic Client
The idea of a dynamic client is to create a
ServiceClient on the fly, or simply create a client
for a given WSDL at runtime and use the created
ServiceClient instance to invoke the corresponding
service (the service corresponding to the WSDL). When you create
the ServiceClient in this manner, it will create and
configure a service proxy inside the client. The constructor for
creating a dynamic client is as follows:
ServiceClient dynamicClient = new ServiceClient(
configContext,
wsdlURL,
wsdlServiceName,
portName);
configContext: The ConfigurationContext you
want to use, which can be null. If it is
null, then ConfigurationContext will be
created either using Axis2's default configuration or will use the
server's ConfigurationContext.
wsldURL: This argument specifies the URL for the WSDL file
and should not be null.
wsdlServiceName: A WSDL document might have multiple
service elements, so if you want to pick a specific service element,
then you can pass the QName of that service element or just pass
null if you do not care about it. If the value is
null, then the first entry in the service element list
will be considered as the service element.
portName: A service element in a WSDL file could have
multiple ports. So if you want to select a specific port, then you
can pass the name of the port as value for this argument. Then
again, if the value is null, the first one from the port list will
be selected as the port.
Sample WSDL to understand above service elements and ports is
shown below:
There is nothing like code to explain. So the best way to understand
ServiceClient API is to write a few real-world
samples. Before writing client code, you need to start the Axis2
server and deploy the MyService.aar found in the Resources
section of this article.
To understand the usage of ServiceClient, let's try
to write some scenarios to invoke the service above.
Scenario 1. Invoking the service in a blocking
manner (sendReceive())
The most common service invocation pattern is the
request-response (called "in-out MEP" in WSDL 2.0 terminology).
With Axis2 you can invoke in-out MEP in either a blocking manner or
a non-blocking manner. The first sample invokes a service in
blocking manner.
Step 1. Create an instance of
ServiceClient using any of the above constructors.
Step 2. Create an OMElement for payload
(request SOAP body, or the message). As stated in the introduction,
XML representation in Axis2 is completely based on AXIOM, so
OMElement is the XML element representation of
AXIOM.
You can use following code snippet to create the payload. You do
not need to pay much attention to AXIOM here. To work in Axis2, one
of the prerequisites is to have a good understanding about AXIOM,
so check out the AXIOM tutorial to learn more about it.
public OMElement createPayLoad() {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace(
"http://ws.apache.org/axis2/xsd", "ns1");
OMElement method = fac.createOMElement("echo", omNs);
OMElement value = fac.createOMElement("value", omNs);
value.setText("Hello , my first service utilization");
method.addChild(value);
return method;
}
Step 3. To invoke the service, you need to provide
parameters such as endpoint address, SOAP Action, etc. For that, you
need to create an instance of Option, which is a
metadata representation for a particular invocation. The following
code snippet shows you how to create an option object and fill
it.
ServiceClient client = new ServiceClient();
// create option object
Options opts = new Options();
//setting target EPR
opts.setTo(new EndpointReference("http://127.0.0.1:8080/axis2/services/MyService"));
//Setting action ,and which can be found from the wsdl of the service
opts.setAction("urn:echo");
//setting created option into service client
sc.setOptions(opts);
If you create a ServiceClient as a dynamic client,
then you do not need to create an option object. It is
automatically created.
Step 4.sendReceive is the ServiceClient
API for invoking a service in blocking manner.
OMElement res = sc.sendReceive(createPayLoad());
System.out.println(res);
Once you run this sample code you will get the following
output:
<ns:echoResponse xmlns:ns="http://ws.apache.org/axis2/xsd">
<ns:return>Hello , my first service utilization</ns:return>
</ns:echoResponse>
The above XML segment is called the response payload. You can
find the complete source code for this scenario in
Scenario1Client.java inside the file invoking-web-services-using-apache-axis2.zip, found in the Resources section below.
Scenario 2. Invoking a service in a
non-blocking manner (sendReceiveNonBlocking())
To invoke an in-out MEP in an asynchronous manner, you can use
this API. As mentioned above, Axis2 uses a callback mechanism to
provide asynchronous support; hence, you need to have an instance of
org.apache.axis2.client.async.Callback to use this
API.
In this scenario, you could follow Steps 1 to 3 from
Scenario 1 without any modification; the changes are in Step 4.
Step 4. Invoking the service, first create an anonymous
callback object.
//creating an anonymous callback object
Callback callback = new Callback() {
public void onComplete(AsyncResult result) {
System.out.println(
result.getResponseEnvelope().getBody().getFirstElement());
}
public void onError(Exception e) {
e.printStackTrace();
}
};
//invoking the service
sc.sendReceiveNonBlocking(createPayLoad(), callback);
Once you run the code sample, you should get the following
output:
-------Invoke the service---------
<ns:echoResponse xmlns:ns="http://ws.apache.org/axis2/xsd">
<return>Hello , my first service utilization</return>
</ns:echoResponse>
The key differences in Scenarios 1 and 2 are as follows:
In Scenario 2, need to create callback object.
sendReceiveNonBlocking is a void operation.
You can find the complete source code for this scenario in
Scenario2Client.java inside the file invoking-web-services-using-apache-axis2.zip.
Scenario 3. Invoking a service using two
transports
With minor modifications you can use Scenario 1 or Scenario 2 to
send the request using one transport and receive via some other
transport (for example, sending via HTTP and receiving via TCP).
The scenario can be represented graphically, as shown in Figure
3.
Figure 3. Service invocation with two transports
To invoke a service in the above manner, you need to have
WS-Addressing support; therefore, you need to engage the addressing
module on both the client and sever sides.
By changing Step 3 in the following manner, you can invoke the
service via two transports. Let's send a request via HTTP and try
to get the response via TCP.
ServiceClient client = new ServiceClient();
Options opts = new Options();
opts.setTo(new EndpointReference(
"http://127.0.0.1:8080/axis2/services/MyService"));
//engaging addressing module
client.engageModule(new QName("addressing"));
// I need to use separate listener for my response
opts.setUseSeparateListener(true);
// Need to receive via TCP
opts.setTransportInProtocol(Constants.TRANSPORT_TCP);
opts.setAction("urn:echo");
client.setOptions(opts);
One thing to notice here is that you need to drop
addressing-1.1.mar (found in the Resources section) into your classpath). The classpath in this case is the location where you have your Axis2 .jar files, so drop the addressing .mar file into the same folder. You can find
the complete source code for this scenario in Scenario4Client.java inside the invoking-web-services-using-apache-axis2.zip file.
Scenario 4. Invoke an in-only MEP
(fireAndForget())
If you want to send data to a server without worrying about
getting a response or exceptions, then you could use the "fire and
forget" approach. Let's try to invoke the ping operation in
MyService.
Step 1. Create a ServiceClient.
Step 2. Create the payload OMElement. Here
the payload section is a bit different compared to the above;
specifically, the operation name is changed from echo to
ping.
public OMElement createPayLoad() {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace(
"http://ws.apache.org/axis2/xsd", "ns1");
OMElement method = fac.createOMElement("ping", omNs);
OMElement value = fac.createOMElement("value", omNs);
value.setText("10");
method.addChild(value);
return method;
}
Step 3. When you run the following code, you will see
the message "I got this value : Hello there" in the server's
console, and you don't get any response or exception, even if
something goes wrong in the server.
ServiceClient client = new ServiceClient();
Options opts = new Options();
opts.setTo(new EndpointReference("http://127.0.0.1:8080/axis2/services/MyService"));
opts.setAction("urn:ping");
client.setOptions(opts);
client.fireAndForget(createPayLoad());
Replace setTo with an invalid one and see
whether you are getting any exception.
Scenario 5: Invoking an in-only MEP
(sendRobust())
This API also offers one-way operation; the key difference from
Scenario 4 is that if something goes wrong in the server, the
client will be informed. You can use Scenario 4 code with a minor
change to invoke the service in a robust manner. Steps 1 and 2 of
Scenario 4 remain unchanged and Step 3 needs the following
changes.
ServiceClient client = new ServiceClient();
Options opts = new Options();
opts.setTo(new EndpointReference(
"http://127.0.0.1:8080/axis2/services/MyService"));
opts.setAction("urn:ping");
client.setOptions(opts);
client.sendRobust(createPayLoad());
Replace setTo with an invalid one and see
whether you get an exception.
You can find the complete source code for this scenario in
Scenario5Client.java.
Working with OperationClient
As you already know from ServiceClient, you have
access to payload on both the sending and receiving sides, but that
is not enough if you are trying to implement enterprise-level web
applications where you will need to have more control. In those
cases you might want to add custom headers to the outgoing SOAP
message, access the incoming SOAP process directly, or access
incoming and outgoing message contexts. However, with
ServiceClient you can do none of these. The solution
is to use OperationClient for those scenarios. Let's
invoke the echo operation using OperationClient to
better understand this API.
Unlike ServiceClient, you do not have multiple ways
of creating OperationClient; there is only one way.
First create a ServiceClient, and then create
OperationClient using that.
The constant ANON_OUT_IN_OP is the name of an
anonymous operation, used when you create
ServiceClient using its default constructor.
Step 3. Create a MessageContext (runtime
representation of a particular message) and set properties on its
option object:
/creating message context
MessageContext outMsgCtx = new MessageContext();
//assigning message context’s option object into instance variable
Options opts = outMsgCtx.getOptions();
//setting properties into option
opts.setTo(new EndpointReference(
"http://127.0.0.1:8080/axis2/services/MyService"));
opts.setAction("urn:echo");
Step 3. Create a SOAPEnvelope and add that
to the message context. This time, you need to create a full SOAP
envelope, whereas in previous cases you had the luxury of just
creating the SOAP body or the payload.
outMsgCtx.setEnvelope(creatSOAPEnvelope());
The createSOAPEnvelope method will look like this:
public SOAPEnvelope creatSOAPEnvelope() {
SOAPFactory fac = OMAbstractFactory.getSOAP11Factory();
SOAPEnvelope envelope = fac.getDefaultEnvelope();
OMNamespace omNs = fac.createOMNamespace(
"http://ws.apache.org/axis2/xsd", "ns1");
// creating the payload
OMElement method = fac.createOMElement("echo", omNs);
OMElement value = fac.createOMElement("echo", omNs);
value.setText("Hello");
method.addChild(value);
envelope.getBody().addChild(method);
return envelope;
}
Step 4. Add a message context to operationClient:
operationClient.addMessageContext(outMsgCtx);
Step 5. To send the message, you need to call the
execute method in operationClient:
operationClient.execute(true);
The Boolean argument to this method indicates whether you want
to invoke in a blocking manner (true) or non-blocking manner
(false).
Step 6. Access response message context and response
SOAPEnvelope:
When you are invoking an in-out MEP as in this sample, the
message label of the request is "Out" and value of the response is
"In," which is why you have to pass "In" as a message label value
to get the response message context. Once you have the message
context, you can use that to access SOAPEnvelope, properties,
transport headers, etc.
When you run this code sample you should get the following as
console output:
Again you can find the complete source code for this
scenario in Scenario6Client.java inside the
invoking-web-services-using-apache-axis2.zip file.
Conclusion
The Axis2 client API is very convenient and it has cool features
like asynchronous web service utilization, multiple transport
selection, and so on. Once you run the samples you will understand
the basics of the Axis2 client API. To understand the rest of the API
you need to write complex code. Good luck!
Slightly different asynchronous model in Axis 1.3
2007-08-10 00:07:19 alpatino
[Reply | View]
Your examples in scenarios number 2 and 3 use now deprecated methods. To invoke asynchronously an operation using the new model in Axis2 1.3 see the following example, as you can see the difference is very slight but is good to know this!
public static void main(String[] args) throws Exception {
ServiceClient sender = new ServiceClient();
;
// create option object
Options opts = new Options();
try {
// setting target EPR
opts.setTo(new EndpointReference(
"http://localhost:8080/Tutorial/services/MyService"));
// Setting action ,and which can be found from the wsdl of the
// service
opts.setAction("urn:echo");
/**
* This is called when we receive a message.
*
* @param msgContext
* the (response) MessageContext
*/
public void onMessage(MessageContext msgContext) {
OMElement result = msgContext.getEnvelope().getBody()
.getFirstElement();
System.out.println(msgContext.toString());
System.out.println(msgContext.getEnvelope().toString());
System.out.println(msgContext.getEnvelope().getBody()
.getFirstElement());
finish = true;
}
/**
* This gets called when a fault message is received.
*
* @param msgContext
* the MessageContext containing the fault.
*/
public void onFault(MessageContext msgContext) {
System.out.println(msgContext.getEnvelope().getBody()
.getFault().toString());
}
/**
* This gets called ONLY when an internal processing exception
* occurs.
*
* @param e
* the Exception which caused the problem
*/
public void onError(Exception e) {
}
/**
* This is called at the end of the MEP no matter what happens,
* quite like a finally block.
*/
public void onComplete() {
System.out.println("OnComplete!!!");
}
};
sender.setOptions(opts);
sender.engageModule("addressing");
System.out.println("-------Invoke the service---------");
// wait till you get the response, in real applications you do not
// need
// to do this, since once the response arrive axis2 will notify
// callback,
// then you can implement callback to do whatever you want, may be
// to update GUI
synchronized (callback) {
if (!finish) {
callback.wait(45000);
if (!finish) {
throw new AxisFault(
"Server was shutdown as the async response take too long to complete");
}
}
}
} finally {
if (sender != null)
sender.disengageModule("addressing");
sender.cleanup();
}
}
public static OMElement createPayLoad() {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace("http://ws.apache.org/axis2",
"ns1");
OMElement method = fac.createOMElement("echo", omNs);
OMElement value = fac.createOMElement("value", omNs);
value.setText("Hello , my first service utilization");
method.addChild(value);
return method;
}
}
Slightly different asynchronous model in Axis 1.3
2007-08-10 02:36:40 deepal
[Reply | View]
Yes in Axis2 1.3 release we had to change that , there was a big discussion in Axis2-dev list and finally the conclusion was to add new class called AxisCallbck and use that for Async invocation. As you have mentioned we have just marked the old methods as deprecated so in 1.3 also you can use the code as it is.
Whirlwind tour to Axis2 WS-Addresing and Asynchronous WS
2007-07-24 22:56:23 alpatino
[Reply | View]
Superb explanation about Axis2 client functionality to use WS-Addressing and different MEP, but not very clear the scenario 3, considering the ws-addresing server module engaging, I'd like to see also the web service code, is there any special coding there?
Thanks
Whirlwind tour to Axis2 WS-Addresing and Asynchronous WS
2007-07-24 23:52:00 deepal
[Reply | View]
To run the scenario 3 you do not need to do anything at the server side , the service is not aware whether it invoke using one transport or two transport.
Whirlwind tour to Axis2 WS-Addresing and Asynchronous WS
2007-07-26 22:04:48 alpatino
[Reply | View]
You are right I was confusing the use of two transports with the replyTo feature to change the EPR target reply, well, by anyway I only need to reference the addressing module in services.xml
Serialization of database data to SOAP message
2007-07-23 07:54:49 eppitis
[Reply | View]
I want to get some database data using Axis2 Async Mode. I want to know if Axis2 is able to serialize the DB data to a soap message or I do have to use javax.xml.parsers first?
Serialization of database data to SOAP message
2007-07-25 00:01:19 deepal
[Reply | View]
Well , in this particular case you have two options
option 1 : You have to write a Message Receiver which can serialize data base data into XML
option 2 : Use WSO2 WSAS , which has implemented to support database support, So with that you can expose relational database as Web service.
Serialization of database data to SOAP message
2007-07-26 04:10:49 eppitis
[Reply | View]
The Server is a JBoss Application Server, so option 2 is not what we want. Can I tranform the database data to SOAP with StaX and then read them with AXIOM?
Serialization of database data to SOAP message
2007-08-09 22:27:07 deepal
[Reply | View]
WSAS can deploy in JBoss as well.
yes of course you can convert database code to OMElement and return that object too
Serialization of database data to SOAP message
2007-08-14 11:09:11 eppitis
[Reply | View]
Can I use OMDataSource to connect to the database? OMDataSource is different from Java DataSource?