JavaEnterprise JavaWriting an Axis2 Service from Scratch

Writing an Axis2 Service from Scratch

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Axis2 has designed and implemented in a way that makes the end user’s job easier. Once he has learnt and understood the Axis2 basics, working with Axis2 is very convenient. Discussing Axis2 basic and its architecture is obviously out of scope of this document; if you are interesting in those topics, there are enough documents for reference. There are slight changes in the way that you implement a service in Axis2 and Axis1. Axis2 introduced a new way of deploying a service as an archive file where you bundle all your service-related resources, services classes, and third-party libraries, and then deploy the archive file.

Introduction

A Web service is obviously an application deployed in a Web service engine. Service implementation, service descriptors, and the way of deploying them vary one engine to another. No matter what Web service engine you are using, there are two main approaches to writing a Web service:

  1. Contract first approach: Starting from a WSDL file
  2. Code first approach: Starting from a source code

The recommended way to write a service is to start from a WSDL file, but the code first approach is still valid; most developers use that technique for their application. One of the concerns with the contract first approach is writing the WSDL document to match his requirement; that obviously requires a good knowledge of WSDL.

Code first approach

If you are new to the world of Web services, your knowledge of WSDL may not enough to write your own WSDL file and then create the service using the WSDL document. So, the best way is to start from a Java class and learn how to expose the Java class as a Web service.

At runtime, no one can understand whether the service was created using code first approach or contract first approach because what you have at the runtime is a set of Java classes. There are three main steps involve in creating a new Web service using the code first approach in Axis2:

  1. Write the service implementation class.
  2. Write a service descriptor (services.xml).
  3. Create a service archive file.

Writing the service implementation class

There is no magic involved or no special things to remember when writing a service implementation class. If you are trying to use Axis2’s advanced features such as session management and service life cycle, of course you have to do few additional things. But, for a simple Web service, it is very straightforward to write the service implementation class. The following code snippet demonstrates what the service implementation class for the “hello” Web service looks like.

public class HelloWorld {
   public String sayHello(String name) {
      return "Hello " + name;
   }
}

This simple Java class has one public method. It takes a string name as an argument and returns a string value as the result.

Writing the services.xml file

To be a valid service in Axis2 when deploying as an archive file, you have to have services.xml inside the service archive file. services.xml is nothing but the deployment descriptor for the service that you are trying to deploy. The service deployment descriptor will tell the deployment module how to configure and deploy the service. Writing a services.xml for service mentioned above is very simple and very straightforward. There are few things you have to remember when writing such a services.xml file:

  • Fully qualified class name of the service implementation class
  • Message receiver or receivers that you are going to use

Note: Axis2 has a set of built-in message receivers; some of them can only handle a XML-in, XML-out scenario; those are called RawXML message receivers. Meanwhile, there are message receivers that can handle any kind of JavaBeans + simple Java types + XML; those are called RPC message receivers. According to the sample code above, it is obvious that you can use none of the RawXML message receivers for this particular service, so the simple answer is to use RPC message receivers.

There are different ways to write services.xml; they vary depending on the way you specify the message receivers, operation overriding, and so forth. You should start with very basic services.xml to understand the concept very easily, so the services.xml corresponding to the service above can be written as follows:

<service>
   <description>
      This is my first service, which says hello
   </description>
   <parameter name="ServiceClass">HelloWorld</parameter>
   <operation name="sayHello">
      <messageReceiver
      class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
   </operation>
</service>

I have bolded few lines in services.xml above; those are the important XML tags that you have to remember when writing a services.xml.

Service implementation class

To specify the corresponding service implementation class, you need to add a parameter with the name ServiceClass; the value of that parameter should be the fully qualified name of the service implementation class.

Specifying the message receiver

There are a few ways to specify the message receiver for a given service. One way is to add the operation tag with the actual Java method name and include the message receiver inside the operation tag. The services.xml mentioned above has followed this approach. As you can see, the service implementation class has a method called sayHello, and services.xml has an operation tag with the same name. Inside the operation element ,it has added the message receiver element.

Creating a service archive file

The next step is to create a service archive file by putting the compile codes of the service implementation class and services.xml. The inside folder structure of the service archive file will look like the following:

HelloWorld.aar
   META-INF
      Services.xml

   HelloWorld.class

Deploying the service is just a matter of dropping the service archive file into the services directory in your aixs2 server repository. If your server is Tomcat, you easily can upload the service by using axis2 Web administration console.

Note: In this case, the name of the deployed service will be HelloWorld.

Different ways of specifying message receivers

As mentioned above, there are a few ways to specify message receivers for a given service:

  • Specify the message receiver at the operation level for each operation.
  • Specify all the message receivers at the service level for the whole service.
  • Specify service level message receiver and override them by operations as and when required.
Specify the message receiver at the operation level

The example described above has used the first approach, where it has specified the message receiver at the operation level.

Specify message receivers at the service level for whole the service

Think about the scenario where you have a large number of operations to be published in services.xml; in this case, adding a message receiver for each and every operation seems useless. If you can specify a message receiver for whole service, it makes the service author’s job easier and simplifies services.xml as well.

Axis2 has built-in support for all the eight MEPs (Message Exchange Pattern) defined in WSDL 2.0. In services.xml, you can specify the MEP and corresponding message receiver, and then, depending on who the MEP operation belongs to, axis2 automatically picks up the message receiver and sets the selected message receiver to the operation.

Note: Inside the operation tag in services.xml, you can add an attribute to specify the MEP of the operation as follows:

<operation name="sayHello"
           mep="http://www.w3.org/2004/08/wsdl/in-out" />

Defining the service level message receivers for a given service is as shown below:

According to services.xml, RPCMessageReceiver is the message receiver for all the in-out operations (for any operation that belongs to in-out, MEP will assign this message receiver as its message receiver) in the service; in the meantime, the service level message receiver for in-only MEP is RPCInOnlyMessageReceiver. If you redeploy the HelloWorld service with a new services.xml, you will definitely get the same result if you invoke the service again.

Specify the service level message receiver and override them by operations

There may be instances where the service author wants to use different message receiver for one or two operations while he has defined service level message receivers. To override service level message receiver by operation can be easily achieved by just adding message receiver element to the operation that you want to override. A sample services.xml which follows this technique is shown below.

Operation sayHello uses a different message receiver than its service level message receivers.

Note: All the public methods in the service implementation class are exposed whether you specified that in services.xml or not. Axis2 calculates the MEP of an operation by checking its corresponding java method. If the method is void, the MEP will be in-only; else, it will be in-out, depending on which MEP message receiver will be set.

Accessing Message context inside the service implementation class

Message context is the property bag + the incoming SOAP message representation in Axis2. There are some services that want to access message context inside its service implementation class; one probable use case could be to access a transport header inside the service and make a decision on that. Axis2 uses a technique called dependency injection to inject message context to the service implementation class; Axis2 uses Java reflection for that. So, if the service wants to access message context inside its service implementation class, it has to add a method called setOperationContext to service the implementation class as follows.

public class HelloWorld {

   private MessageContext inMesasgeContext;

   public void setOperationContext(OperationContext opCtx)
      throws AxisFault {
         inMesasgeContext = opCtx.getMessageContext(
            WSDLConstants.MESSAGE_LABEL_IN_VALUE);
   }

   public String sayHello(String name) {
      return "Hello " + name;
   }
}

Note: Axis2 calls setOperationContext using Hava reflection before it calls an actual Java method corresponding to the incoming message.

Service group and single service

To deploy multiple services (they may be logically related or not) together in a single service archive file, Axis2 introduced the concept of a service group. There, you can have multiple service implementation classes and only one services.xml file to describe all the services. The only difference here is that root element of services.xml is changed to serviceGroup instead of service. As an example, say you want to deploy two services together in a single service archive file and further assume that names of them are MyService1 and MyService2 respectively. The services.xml file can be written as follows:

<serviceGroup>
   <service name="MyService1">
      ........................
   </service>
   <service name="MyService2">
      .......................
   </service>
</serviceGroup>

The only difference in the service element compared to HelloWorld’s services.xml is that here the service element has an additional attribute called name. If you want to have multiple service elements in the services.xml file, you must have the name attribute in each and every service element.

Contract first approach: Starting from WSDL

The easiest way to create a service is to start from WSDL; that is what happens in most production environments. When it comes to production, they have business scenarios and corresponding business contracts or the WSDL file, so why not start from there? The interesting thing is that once they have the WSDL file, both client and producer (service) are given the WSDL and they have to act according to that.

Axis2 has built-in support of the generation service code once you have the WSDL. In this case, as a service author, you have only to do the following few steps:

  • Generate service code (service skeleton)
  • Fill the service skeleton according to the business agreement
  • Run the generated Ant build file
  • Deploy the Ant-created service archive file into your application server where Axis2 is running
Generating code

Axis2 came with a set of tools and IDE plug-ins for code generation (WSDL2Code) to make the work easier. So, you can choose any kind of code generation tool to generate a service skeleton. In the meantime, there is a set of databinding framework support; you can select one of them as your databinding. As an example, you can select xmlbeans, adb, or any other available databinding framework (jibx, jaxme, and so forth). Once you generate server side code, it generates:

  • Service skeleton class
  • Message receivers (most of the time, one or two)
  • services.xml
  • services.wsdl
  • Ant build file
Filling the service skeleton

Axis2 generates a service skeleton class to throw UnSupportOperation from each method. You have to implement the service skeleton class as you want.

Running ant build file

After completing the service skeleton, the next step is to create a service archive file using generated code. To make the job simple, Axis2 generates an Ant build file to create service archive file for you; you have to open the command line console, go to the folder where you generated code, and then type ant build there in the console to run the ant build file. Then, it creates the service archive file for you.

Summary

Making a Java class into a Web service is very straightforward in Axis2. Once you know how to write services.xml correctly, deploying a service is just a matter of creating a service archive file and dropping it into the services directory in the repository. WSDL’s first approach is the easiest way to creating a service because Axis2 has built-in support for code generation and a set of tools to make the job easier.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories