Apache Axis2 Web Services: Writing an Axis2 Module


Apache Axis2 Web Services, 2nd Edition

Apache Axis2 Web Services, 2nd Edition

Create secure, reliable, and easy-to-use web services using Apache Axis2.

  • Extensive and detailed coverage of the enterprise ready Apache Axis2 1.5 Web Services / SOAP / WSDL engine.
  • Attain a more flexible and extensible framework with the world class Axis2 architecture.
  • Learn all about AXIOM - the complete XML processing framework, which you also can use outside Axis2.
  • Covers advanced topics like security, messaging, REST and asynchronous web services.
  • Written by Deepal Jayasinghe, a key architect and developer of the Apache Axis2 Web Service project; and Afkham Azeez, an elected ASF and PMC member.
        Read more about this book      

(For more resources on this subject, see here.)

Web services are gaining a lot of popularity in the industry and have become one of the major enabler for application integration. In addition, due to the flexibility and advantages of using web services, everyone is trying to enable web service support for their applications. As a result, web service frameworks need to support new and more custom requirements. One of the major goals of a web service framework is to deliver incoming messages into the target service. However, just delivering the message to the service is not enough; today's applications are required to have reliability, security, transaction, and other quality services.

In our approach, we will be using code sample to help us understand the concepts better.

Brief history of the Axis2 module

Looking back at the history of Apache Web Services, the Handler concept can be considered as one of the most useful and interesting ideas. Due to the importance and flexibility of the handler concept, Axis2 has also introduced it into its architecture. Notably, there are some major differences in the way you deploy handlers in Axis1 and Axis2. In Axis1, adding a handler requires you to perform global configuration changes and for an end user, this process may become a little complex. In contrast, Axis2 provides an easy way to deploy handlers. Moreover, in Axis2, deploying a handler is similar to deploying a service and does not require global configuration changes.

At the design stage of Axis2, one of the key considerations was to have a mechanism to extend the core functionality without doing much. One of the main reasons behind the design decision was due to the lesson learned from supporting WS reliable messaging in Axis1. The process of supporting reliable messaging in Axis1 involved a considerable amount of work, and part of the reason behind the complex process was due to the limited extensibility of Axis1 architecture. Therefore, learning from a session in Axis1, Axis2 introduced a very convenient and flexible way of extending the core functionality and providing the quality of services. This particular mechanism is known as the module concept.

Module concept

One of the main ideas behind a handler is to intercept the message flow and execute specific logic. In Axis2, the concept of a module is to provide a very convenient way of deploying service extension. We can also consider a module as a collection of handlers and required resources to run the handlers (for example, third-party libraries). One can also consider a module as an implementation of a web service standard specification. As an illustration, Apache Sandesha is an implementation of WS-RM specification. Apache Rampart is an implementation of WS-security; likewise, in a general module, is an implementation of a web service specification. One of the most important features and aspects of the Axis2 module is that it provides a very easy way to extend the core functionality and provide better customization of the framework to suit complex business requirements. A simple example would be to write a module to log all the incoming messages or to count the number of messages, if requested.

Module structure

Axis1 is one of the most popular web service frameworks and it provides very good support for most of the web service standards. However, when it comes to new and complex specifications, there is a significant amount of work we need to do to achieve our goals. The problem becomes further complicated when the work we are going to do involves handlers, configuration, and third-party libraries. To overcome this issue, the Axis2 module concept and its structure can be considered as a good candidate. As we discussed in the deployment section, both Axis2 services and modules can be deployed as archive files. Inside any archive file, we can have configuration files, resources, and the other things that the module author would like to have.

It should be noted here that we have hot deployment and hot update support for the service; in other words, you can add a service when the system is up and running. However, unfortunately, we cannot deploy new modules when the system is running. You can still deploy modules, but Axis2 will not make the changes to the runtime system (we can drop them into the directory but Axis2 will not recognize that), so we will not use hot deployment or hot update. The main reason behind this is that unlike services, modules tend to change the system configurations, so performing system changes at the runtime to an enterprise-level application cannot be considered a good thing at all.

Adding a handler into Axis1 involves global configuration changes and, obviously, system restart. In contrast, when it comes to Axis2, we can add handlers using modules without doing any global level changes. There are instances where you need to do global configuration changes, which is a very rare situation and you only need to do so if you are trying to add new phases and change the phase orders. You can change the handler chain at the runtime without downer-starting the system.

Changing the handler chain or any global configuration at the runtime cannot be considered a good habit. This is because in a production environment, changing runtime data may affect the whole system. However, at the deployment and testing time this comes in handy.

The structure of a module archive file is almost identical to that of a service archive file, except for the name of the configuration file. We know that for a service archive file to be a valid one, it is required to have a services.xml. In the same way, for a module to be a valid module archive, it has to have a module.xml file inside the META-INF directory of the archive. A typical module archive file will take the structure shown in the following screenshot. We will discuss each of the items in detail and create our own module in this article as well.

Apache Axis2 1.5 Web Services: Writing an Axis2 Module

Module configuration file (module.xml)

The module archive file is a self-contained and self-described file. In other words, it has to have all the configuration required to be a valid and useful module. Needless to say, that is the beauty of a self-contained package. The Module configuration file or module.xml file is the configuration file that Axis2 can understand to do the necessary work.

A simple module.xml file has one or more handlers. In contrast, when it comes to complex modules, we can have some other configurations (for example, WS policies, phase rules) in a module.xml. First, let's look at the available types of configurations in a module.xml. For our analysis, we will use a module.xml of a module that counts all the incoming and outgoing messages. We will be discussing all the important items in detail and provide a brief description for the other items:

  • Handlers alone with phase rules
  • Parameters
  • Description about module
  • Module implementation class
  • WS-Policy
  • End points

Handlers and phase rules

A module is a collection of handlers, so a module could have one or more handlers. Irrespective of the number of handlers in a module, module.xml provides a convenient way to specify handlers. Most importantly, module.xml can be used to provide enough configuration options to add a handler into the system and specify the exact location where the module author would like to see the handler running. Phase rules can be used as a mechanism to tell Axis2 to put handlers into a particular location in the execution chain, so now it is time to look at them with an example.

Before learning how to write phase rules and specifying handlers in a module.xml, let's look at how to write a handler. There are two ways to write a handler in Axis2:

  • Implement the org.apache.axis2.engine.Handler interface
  • Extend the org.apache.axis2.handlers.AbstractHandler abstract class

In this article, we are going to write a simple application to provide a better understanding of the module. Furthermore, to make the sample application easier, we are going to ignore some of the difficulties of the Handler API. In our approach, we will extend the AbstractHandler. When we extend the abstract class, we only need to implement one method called invoke. So the following sample code will illustrate how to implement the invoke method:

public class IncomingCounterHandler extends AbstractHandler implements
CounterConstants {
public InvocationResponse invoke(MessageContext messageContext) throws
AxisFault {
//get the counter property from the configuration context
ConfigurationContext configurationContext = messageContext.
Integer count =
(Integer) configurationContext.getProperty(INCOMING_
//increment the counter
count = Integer.valueOf(count.intValue() + 1 + «»);
//set the new count back to the configuration context
//print it out
System.out.println(«The incoming message count is now « +
return InvocationResponse.CONTINUE;

As we can see, the method takes MessageContext as a method parameter and returns InvocationResponse as the response. You can implement the method as follows:

  1. First get the configurationContext from the messageContext.
  2. Get the property value specified by the property name.
  3. Then increase the value by one.
  4. Next set it back to configurationContext.
  5. In general, inside the invoke method, as a module author, you have to do all the logic processing, and depending on the result you get, we can decide whether you let AxisEngine continue, suspend, or abort. Depending on your decision, you can return to one of the three following allowed return types:
    • InvocationResponse.CONTINUE
      Give the signal to continue the message
    • InvocationResponse.SUSPEND
      The message cannot continue as some of the conditions are not satisfied yet, so you need to pause the execution and wait.
    • InvocationResponse.ABORT
      Something has gone wrong, therefore you need to drop the message and let the initiator know about it.
  6. The message cannot continue as some of the conditions are not satisfied yet, so you need to pause the execution and wait.
  7. InvocationResponse.ABORT
  8. Something has gone wrong, therefore you need to drop the message and let the initiator know about it.

The corresponding CounterConstants class a just a collection of constants and will look as follows:

public interface CounterConstants {
String INCOMING_MESSAGE_COUNT_KEY = "incoming-message-count";
String OUTGOING_MESSAGE_COUNT_KEY = "outgoing-message-count";
String COUNT_FILE_NAME_PREFIX = "count_record";

As we already mentioned, the sample module we are going to implement is for counting the number of request coming into the system and the number of messages going out from the system. So far, we have only written the incoming message counter and we need to write the outgoing message counter as well, and the implementation of the out message count hander will look like the following:

public class OutgoingCounterHandler extends AbstractHandler implements
CounterConstants {
public InvocationResponse invoke(MessageContext messageContext)
throws AxisFault {
//get the counter property from the configuration context
ConfigurationContext configurationContext = messageContext.
Integer count =
(Integer) configurationContext.getProperty(OUTGOING_
//increment the counter
count = Integer.valueOf(count.intValue() + 1 + «»);
//set it back to the configuration
//print it out
System.out.println(«The outgoing message count is now « +
return InvocationResponse.CONTINUE;

The implementation logic will be exactly the same as the incoming handler processing, except for the property name used in two places.

Module implementation class

When we work with enterprise-level applications, it is obvious that we have to initialize various settings such as database connections, thread pools, reading property, and so on. Therefore, you should have a place to put that logic in your module. We know that handlers run only when a request comes into the system but not at the system initialization time. The module implementation class provides a way to achieve system initialization logic as well as system shutdown time processing. As we mentioned earlier, module implementation class is optional. A very good example of a module that does not have a module implementation class is the Axis2 addressing module. However, to understand the concept clearly in our example application, we will implement a module implementation class, as shown below:

public class CounterModule implements Module, CounterConstants {
private static final String COUNTS_COMMENT = "Counts";
private static final String TIMESTAMP_FORMAT = "yyMMddHHmmss";
private static final String FILE_SUFFIX = ".properties";

public void init(ConfigurationContext configurationContext,
AxisModule axisModule) throws AxisFault {
//initialize our counters
System.out.println("inside the init : module");
initCounter(configurationContext, INCOMING_MESSAGE_COUNT_KEY);
initCounter(configurationContext, OUTGOING_MESSAGE_COUNT_KEY);

private void initCounter(ConfigurationContext
String key) {
Integer count = (Integer) configurationContext.
if (count == null) {
configurationContext.setProperty(key, Integer.

public void engageNotify(AxisDescription axisDescription) throws
AxisFault {
System.out.println("inside the engageNotify " +

public boolean canSupportAssertion(Assertion assertion) {
//returns whether policy assertions can be supported
return false;

public void applyPolicy(Policy policy,
AxisDescription axisDescription) throws
AxisFault {
// Configuure using the passed in policy!

public void shutdown(ConfigurationContext configurationContext)
throws AxisFault {
//do cleanup - in this case we'll write the values of the
counters to a file
try {
SimpleDateFormat format = new SimpleDateFormat(TIMESTAMP_
File countFile = new File(COUNT_FILE_NAME_PREFIX + format.
format(new Date()) + FILE_SUFFIX);
if (!countFile.exists()) {

Properties props = new Properties();
//write to a file
props.store(new FileOutputStream(countFile), COUNTS_
} catch (IOException e) {
//if we have exceptions we'll just print a message and let
it go
System.out.println("Saving counts failed! Error is " +

As we can see, there are a number of methods in the previous module implementation class. However, notably not all of them are in the module interface. The module interface has only the following methods, but here we have some other methods for supporting our counter module-related stuff:

  • init
  • engageNotify
  • applyPolicy
  • shutdown

At the system startup time, the init method will be called, and at that time, the module can perform various initialization tasks. In our sample module, we have initialized both in-counter and out-counter.

When we engage this particular module to the whole system, to a service, or to an operation, the engageNotify method will be called. At that time, a module can decide whether the module can allow this engagement or not; say for an example, we try to engage the security module to a service, and at that time, the module finds out that there is a conflict in the encryption algorithm. In this case, the module will not be able to engage and the module throws an exception and Axis2 will not engage the module. In this example, we will do nothing inside the engageNotify method.

As you might already know, WS-policy is one of the key standards and plays a major role in the web service configuration. When you engage a particular module to a service, the module policy should be applied to the service and should be visible when we view the WSDL of that service. So the applyPolicy method sets the module policy to corresponding services or operations when we engage the module. In this particular example, we do not have any policy associated with the module, so we do not need to worry about this method as well.

As we discussed in the init method, the method shutdown will be called when the system has to shut down. So if we want to do any kind of processing at that time, we can add this logic into that particular method. In our example, for demonstration purposes, we have added code to store the counter values in a file.

        Read more about this book      

(For more resources on this subject, see here.)

Writing the module.xml file

So far, we have written two handlers and module implementation classes. Now, the only remaining thing to do is to write the module descriptor file. When writing module.xml, we have to use phase rules to specify the location of handlers and we have discussed phase rules before (it is time to refresh our mind about the phase rule). The most simple module.xml file for our module is shown here:

<module name="counterModule" class="org.apache.axis2.sample.module.
Counts the incoming and outgoing messages
<handler name="IncomingMessageCountHandler"
<order phase="Transport" after="RequestURIBasedDispatcher"
<handler name="OutgoingMessageCountHandler"
<order phase="MessageOut"/>

In the file module.xml, we have specified the description of the module as "Counts the incoming and outgoing messages"; in the meantime, it has specified the two handlers we implemented earlier with phase rules.

As you can see, we try to put our incoming message counter into the transport phase and the exact location is after RequestURIBasedDispatcher and before SOAPActionBasedDispatcher. If you look at the default axis2.xml file, you can see the two handlers in the inFlow. Meanwhile, in the outgoing message, a counter is added to the message-out phase and this does not specify the exact location.

If you look carefully, you can see in the root element that there is an attribute called "class", which specifies the module interface class. We need to remember that this attribute is an optional one and some modules may or may not have this attribute.

There are instances where the module author needs to use a new phase for the module. In such a situation, one can edit the axis2.xml and specify the new phase(s) one wants. Once specified, phases can be used inside the module.xml.

In the module.xml file, we have not discussed how to add the fault handlers, as we already know, there are two flows for fault processing: InFaultFlow and OutFaultFlow. The InFaultFlow is executed when there is an incoming fault. Similarly, OutFaultFlow is executed when there is an outgoing message. If you want to add handler(s) to any of those phases, you can do that just like you did with the other two flows.

Deploying and engaging the module

Now we have written everything you need for a valid module, the only remaining thing is to create the module archive file and deploy it to the repository. First we compile our source code and then, as we know, it creates .class files.

Assuming org.apache.axis2.sample.module.request is the package name of our source file, we can find all the .class files under classes/org/apache/axis2/sample/module/request.

Now create a directory called META-INF under the classes directory and copy the module.xml file into it. Then our classes directory should look like the following screenshot:

Apache Axis2 1.5 Web Services: Writing an Axis2 Module

Now create a ZIP file from the classes directory and rename the ZIP file into the counter-module.mar.

Deploying the module is as simple as dropping the file into the TOMCAT_HOME/webapps/axis2/WEB-INF/modules or repository/modules directory. In this case, let's focus on deploying the module in Tomcat or your favorite web application server. As we know, Axis2 does not support module hot deployment, so just dropping the module will not make any changes to the runtime system. To deploy our module and apply the necessary changes to runtime, we need to restart Axis2; in other words, we need to restart the application server.

It should be noted that just deploying a module does not add its handlers into the handler chain; to add handlers into the system, it is necessary to engage the module. Now, let's see how we engage a module in Axis2. For this purpose, we can use the Axis2 web administration console. Moreover, to make the story simple, let's try to engage the module to all the services in the system using the web administration console (we can engage to a single service also using the administration console). We can engage the module to the system by carrying out the following steps:

  1. Go to http://localhost:8080/axis2/.
  2. Click on the Administration tab. This will open up a new page and ask for the username and password.
  3. Enter admin as the username and axis2 as the password. This will open up the administration console.
  4. After that, click on the Available Modules in the side navigation menu on the left-hand side. There we will find our Counter module as
    counterModule: Counts the incoming and outgoing messages.
  5. Now go to Engage Module\For all Services and this will open up a new page with a drop-down menu.
  6. Select counterModule from that and click engage.
  7. Now we should see the message counterModule module engaged globally successfully.
  8. Go to Global Chains and you will be able to see the IncomingMessageCountHandler handler in the transport phase between RequestURIBasedDispatcher and SOAPActionBasedDispatcher.

Now, this simply tells us that we have engaged the module successfully and we have added the handler into the correct phases to invoke the version server, enter the following into your browser:


Then, in the console, you will see the following:

Apache Axis2 1.5 Web Services: Writing an Axis2 Module

This simply tells us that the request has gone though the incoming counter handler and the response has gone though the outgoing counter handler. Now, let's invoke the service one more time and see what we get in the console. We will see the following:

Apache Axis2 1.5 Web Services: Writing an Axis2 Module

Now we know how to write a very simple module, deploy it, and engage it. As an exercise, we can change the module.xml and see what happens. Also, we can change the phase rules and see whether it puts the handlers into the correct locations. In the meantime, we can restart Tomcat, without engaging the module. Here, we should not see any output in the console. This will help us to understand that handlers are invoked only when we engage the module.

There are other ways of engaging a module, for example, to engage a module globally, a user can edit axis2.xml and add the <module ref="modulename"/> element. Moreover, if a user wants to engage it to particular services, he/she can do that by editing the services.xml and adding the same tag mentioned earlier.

Advanced module.xml

Here, we looked at a very simple module.xml, but when it comes to very complex applications, we need to have many more configurations in a module.xml file. We might need to have parameters, WS-Policy, and endpoints. Now let's look at them one at a time in brief.


Adding a parameter here is the same as adding a parameter in services.xml or axis2.xml. We just need to add the following tag into module.xml and Axis2 will do the right thing for us:

<parameter name="foo">bar</parameter>

We can have any number of parameters in a module.xml, and when we want to access the parameter, we can do that by carrying out the following steps:

  • First we need to get the AxisModule. We can do that either by using the init method (Axis2 passes the AxisModule ) or we need to get the corresponding AxisModule from the ConfigurationContext (inside the Module implementation class) or from messageContext (inside a handler).
  • After this, we can ask for the parameter from the AxisModule.


Specifying a WS-Policy element in module.xml is one way of configuring a module. We can add WS-Policy element inside a module.xml. If we consider the Sandesha2 (reliable message implementation) module, we can find the following policy element:

<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
policy" wsu:Id="RMPolicy">


In Axis2, an endpoint is an operation of a web service. So, adding an endpoint is the same as adding an operation. The key question is—why do we need to add an endpoint to a module? To understand this, let's assume that we have a module and this module has a set of control operations. The most suitable example is reliable messaging, as it has a number of control messages (for example, create sequence, last message, terminate sequence). Say, we need to invoke a service in a reliable manner. It first needs to set up a sequence with the service. For this, it will send the control message called createSequence to the service we need to access. But that service does not have that method, so if we try to send the createSequence message without adding the method, Axis2 will throw an exception saying Unable to dispatch. Therefore, adding an endpoint will solve that issue. Hence, when we engage Sandesha, it adds a method called createSequence to the service at the time we engage the module (or all the services, if we engage that to the whole system). When a request comes, Axis2 will dispatch without having any problem. This operation or the endpoint has its own message receiver to do the right thing.

So, it is obvious that when a module needs control operations exchange, it is required to add endpoint to represent those operations. Adding an endpoint is very simple. What we need to do is add an operation element(s) along with a message receiver and a set of action mapping. To get an idea about that, let's take the Sandesha module as a reference. Its module.xml has the following operation tag to add the control operations. Remember, when we have the operation tag in module.xml, Axis2 will do all the processing, including creating AxisOperation and adding that. As a module author, all we need to do is specify them in the module.xml file:

<operation name="Sandesha2OperationInOut" mep="http://www.
<messageReceiver class="org.apache.sandesha2.msgreceivers.
<!-- namespaces for the 2005-02 spec -->

If we look at the Sandesha module.xml, we will be able to learn and find out more about writing a module.xml file.


Due to the popularity of web services, standard bodies are producing new web service standards, and it is hard to support those new standards if the web service framework is not flexible enough. From the very beginnings of Axis2, flexibility and extensibility were the two main design considerations. The idea of Axis2 modules is to extend the core functionality of the system without performing any changes to the core system. For example, Axis2 supports reliability and security as two separate modules, and the core engine is fully independent of those two qualities of service modules.

Further resources on this subject:

You've been reading an excerpt of:

Apache Axis2 Web Services, 2nd Edition

Explore Title