Skip to main content

Invoking Web Services using Apache Axis2

December 13, 2006

alt="{cs.r.title}" border="0" align="left" hspace="10" vspace="0">






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.

Invoking a service in a synchronous manner
Figure 1. Invoking a service in a synchronous manner

Invoking a service in asynchronous 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:

<wsdl:service name="MyService">
    <wsdl:port name="ServicePort1" binding="axis2:ServiceBinding1">
        <soap:address
        location="http://127.0.0.1:8080/axis2/services/MyService"/>
    </wsdl:port>
    <wsdl:port name="ServicePort2" binding="axis2: ServiceBinding2 ">
        <soap12:address
        location="http://127.0.0.1:8080/axis2/services/MyService"/>
    </wsdl:port>
</wsdl:service>

Working Samples with ServiceClient

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.

Service invocation with two transports
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. location folder where you have your axis2 jar files. --> 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.

Step 1. Create a ServiceClient
instance.

ServiceClient client = new ServiceClient();

Step 2. Create an OperationClient.

OperationClient operationClient = client.createClient(
               ServiceClient.ANON_OUT_IN_OP);

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:

//pass message label as method argument 
MessageContext inMsgtCtx = operationClient.getMessageContext("In"); 

SOAPEnvelope response = inMsgtCtx.getEnvelope();
System.out.println(response);

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:

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header/>
    <soapenv:Body>
        <ns:echoResponse xmlns:ns="http://ws.apache.org/axis2/xsd">
            <ns:return>Hello</ns:return>
        </ns:echoResponse>
    </soapenv:Body>
</soapenv:Envelope>

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!

Resources

Deepal Jayasinghe is a senior software engineer at WSO2 Inc., an open source technology company creating middleware platforms for Web services.
Related Topics >> Web Services and XML   |