Monday, February 25, 2013

Web Services Using Axis2 Tutorial

SOAP Web Services with Apache Axis2


I wrote this tutorial because there are not very many resources for teaching absolute beginners how to use a SOAP web service.  While Axis2 is a great framework, the documentation, which full of examples and sample code, is a little sparse on the explanation of simple web service functionality.  This tutorial is intended to be very descriptive, and the sample code I provide is well commented.

SOAP is a protocol that uses a standardized XML format to transfer information via web services.  Web services, in the context of this tutorial, are nothing more than a set of Java methods on an external server that can be accessed from a remote program.  SOAP was created to standardize the format of the data, making it easily accessed by many platforms and programming languages.

This tutorial was written for a Windows machine, but Axis2 is cross platform.

Writing the Service

First we will be writing the service that resides on the server. 

1.  Download and extract Axis2. 
Go to the Apache Axis2 download page and download the Binary distribution.  Extract the file to a directory.  This will be the AXIS2_HOME directory.  I extracted mine to c:\axis2-1.6.2\.  Next, you'll need to set an environment variable on your system, so add a variable called AXIS2_HOME with a value of the directory you extracted Axis2.

2.  Write the Web Service java file, compile
Now we'll want to write the web service itself.  Make a new working directory anywhere on your computer.  We will be making a Hello World example, so the service is fairly simple.  The code should look like this:

public class HelloWorldService {
    public String sayHello() {
        return "Hello World!";

Here we've made a simple class called HelloWorldService, which is the name of the web service.  It has one method, sayHello, which will be our endpoint that our client application will access.  It takes no parameters, and simply returns "Hello World!" to the client.  Compile this file using the command:

javac -g

You should now have a class file in your working directory alongside the source file.

3.  Use the java2wsdl script to convert it to a web service descriptor language

A Web Service Descriptor Language (WSDL) file describes how a client will interact with a web service.  You'll usually want to provide these files with your web service.  Axis2 comes with a script that converts java class files into a WSDL file.  In your working directory, run:

%AXIS2_HOME%\bin\java2wsdl -cp . -cn HelloWorldService -of HelloWorldService.wsdl

This takes the class name (HelloWorldService) and generates an output file (HelloWorldService.wsdl).

4.  Make services.xml

Services.xml is a file that describes the web service at a higher level.  Ours will look like this:

<service name="HelloWorldService" scope="application">
        Says Hello World to you.
    <parameter name="ServiceClass">

Items to note are the name parameter in the service tag, the description tag, and the parameter ServiceClass tag.  The message receivers are java classes than handle the message sent to the server; these were the default ones, and will work fine for our simple example.

5.  Organize in directory structure, compress to jar
Now that we have all of the components for our web service, we need to organize them in a file hierarchy that Axis2 can understand and compress it into a jar.  You'll need to organize your directory like so:

- top leve working Directory (not included in jar)

Now compress the directory into a jar.  I used the command:

jar cf HelloWorldService.aar META-INF HelloWorldService.class

Note the .aar file extension, which is what Axis2 will recognize.  This took both files in META-INF and the class file and compressed it into an jar archive. 
6.  Place in repository, test.

Take the .aar file you just made and drop it into AXIS2_HOME\repository\services.  Inside that directory, there should be a file called services.list.  Edit that file and add HelloWorldService.aar to the list.

Now, start the Axis2 server by running AXIS2_HOME\bin\axis2server.bat.  Assuming there are no errors, you should be able to navigate to http://localhost:8080/ and see a splash screen, showing the HelloWorldService and its one action, sayHello.  Navigating to http://localhost:8080/axis2/services/HelloWorldService?wsdl will bring up the WSDL file, and finally, navigating to http://localhost:8080/axis2/services/HelloWorldService/sayHello should bring up some XML, with Hello World! clearly visible.

If all of this works, then your simple HelloWorldService is complete!

Writing the Client

Now we will want to access this service from a Java program, so we'll need to write a client.  Axis2 provides many ways of auto generating clients using the WSDL file, but for our simple task we'll just write one from scratch using the Axis2 API.

1. Write the client code.
First, make a new directory anywhere on your computer and add this file in it.  It is our client, and here is the code.

//this is a Request-Response, Blocking Client

import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;

public class GreetMe {
    private static EndpointReference targetEPR = new EndpointReference("http://localhost:8080/axis2/services/HelloWorldService"); //this is the url of our endpoint.  These endpoints are listed in the wsdl:service tag.

    public static void main(String[] args) {
        try {
            OMElement payload = getsayHelloOMElement();  // get the payload, or SOAP XML request to send to server
            Options options = new Options();
            options.setTo(targetEPR); //set the end point address of the options
            options.setAction("urn:sayHello"); //tell it the action to use is sayHello

            //Blocking invocation
            ServiceClient sender = new ServiceClient(); //the ServiceClient object is provided by the Axis2 API and sends and receives the SOAP message
            OMElement result = sender.sendReceive(payload);  //send request, get the result of the payload request as a OMElement


        } catch (AxisFault axisFault) {
    public static OMElement getsayHelloOMElement() {
        OMFactory fac = OMAbstractFactory.getOMFactory();
        OMNamespace omNs = fac.createOMNamespace(
                "", "example1"); //the xml namespace of the service.  found in the the first arg is found in the wsdl file in the wsdl:definitions tag, in the xmlns:ns parameter.  The second is the prefix, which can be pretty much anything, as its purpose is simply to prevent naming conflicts.
        OMElement method = fac.createOMElement("sayHello", omNs); //the name of the method, using the namespace.  If you didn’t write the service and don’t know the method name, it is in the WSDL file as one of the xs:element tags.
        OMElement value = fac.createOMElement("Text", omNs);
        value.addChild(fac.createOMText(value, "Axis2 Echo String ")); //here we are adding a description to the request.  We are adding a Text xml element, and adding it as a child to the method xml element.

        return method;

2.  Make an ANT file
Rather than building from command line, I chose to make an Ant script to handle the classpaths and jvm options:

<project name="custom client" default="compile">
    <property name="mainDir" value="c:\axis2-1.6.2\" />  <!--The AXIS2_HOME directory -->
    <path id="axis.classpath">
        <fileset dir="${mainDir}/lib">    <!--include the jars in the AXIS2_HOME/lib directory -->
            <include name="*.jar"/>
        <pathelement location="."/>        <!--also include the working directory -->

    <target name="compile"> <!-- our compile target -->
        <delete file="GreetMe.class" />
        <javac srcdir="." destdir=".">
            <classpath refid="axis.classpath" />
    <target name="run" depends="compile"> <!-- the run target, which first calls compile -->
        <java classname="GreetMe" classpathref="axis.classpath" fork="true"> <!-- our client class -->
            <jvmarg value="-Daxis2.repo=${mainDir}/repository"/>
            <jvmarg value="-Daxis2.xml=conf/axis2.xml"/>
            <!-- the above arguments tell the class where the repository is, which holds the configuration files.  By default, it will look for axis2.xml there, but you can also specify exactly where axis2.xml is, as seen in the second arg.  See references for details.

3.  Run the file

Make sure the Axis2 server (AXIS2_HOME/bin/axis2server.bat) is running, then use the command:

ant run

To compile and run the client.  It should output the XML seen in the browser when testing the service.  This is my output:

<ns:sayHelloResponse xmlns:ns=""><ns:return>Hello World!</ns:return></ns:sayHelloResponse>

Web Service, deploy as POJO:
Blocking client: