2007/12/04
4 Dec, 2007

Hacking Apache Axis2 - Part1 : Dynamic Deployment of Services and Modules

  • Eran Chinthaka
  • Software Engineer - WSO2

Dynamic Deployment of Services and Modules

Apache Axis2 can be configured statically using various configuration files and options. However, taking control of Axis2 dynamically is an interesting task, and is very useful if you are trying to carry out advanced operations inside Axis2 or build your own product on top of Axis2. These operations are hidden underneath the code of Axis2 and this series will introduce and discuss some of those concepts and operations.

Introduction

We will first look at how to deploy services and modules dynamically and also how to engage the modules which are already deployed. The distinction between a deployed versus engaged module is that a module is deployed if the information relevant to the module is read into Axis2 and the AxisModule class is created. A module is said to be engaged when it is configured to work with an operation, service, or with the whole system. For example, simply deploying the WS-Addressing module will not provide WS-Addressing support for the services deployed in the system. If we engage the WS-Addressing module globally, then all the services deployed in the system will receive WS-Addressing support. (If you need more information on modules please read the Module Archive section in the article Axis2 Deployment Model or refer to more resources within Oxygen Tank)

Assume you are trying to write an administrative service which can deploy services or modules from a known location, or you might need to engage the modules for a given service or an operation depending on a set of rules. This article will teach you to accomplish just that.

 

Applies To

Axis2/Java 1.2 or later
JDK 1.4 or later

 

Deploying a Service Dynamically

First let's look at how services can be deployed dynamically. Axis2 has a couple of APIs at different levels of abstractions to accomplish this. Let's first see how we can deploy a Java class which has operations analogues to IN-OUT operations. (IN-OUT operations are just one form of message exchange patterns defined within Web services. There are a few more defined explicilty in various places and this article provides more information on message exchange patterns (MEP) in general).

Step 1 : Create the service implementation class

Let's consider a simple Echo class which has an echoOMElement operation. This operation takes an XML fragment represented using an instance of org.apache.axiom.om.OMElement as the input and echoes it back.

package org.wso2.ot.tutorials.hackingaxis2; 
import org.apache.axiom.om.OMElement;

public class Echo {

public OMElement echoOMElement(OMElement omElement) {
omElement.setLocalName(omElement.getLocalName() + "Response"); return omEle;
}
}

Code Listing 1 : The Echo class with echoOMElement method

Echo class having echoString method

Step 2 : Create an instance of AxisService from the Echo class

Axis2 represents all the services deployed in it using the org.apache.axis2.description.AxisService class. So we need to create an instance of the org.apache.axis2.description.AxisService class using the above Echo class. org.apache.axis2.util.Utils provides an easy method to do that.

javax.xml.namespace.QName serviceName = new javax.xml.namespace.QName("EchoService"); 
javax.xml.namespace.QName operationName = new javax.xml.namespace.QName("echoOMElement");
AxisService service = org.apache.axis2.util.Utils.createSimpleService(serviceName,
org.wso2.ot.tutorials.hackingaxis2.Echo.class.getName(),operationName);

Code Listing 2 : Creating an instance of AxisService from the Echo class

For this case, I am using org.apache.axis2.receivers.RawXMLINOutMessageReceiver as the message receiver to work with this service. If your service needs a different message receiver, you can use the org.apache.axis2.util.Utils.createSimpleService.createSimpleService(QName serviceName, MessageReceiver messageReceiver, String className, QName opName) method instead of the above method.

Step 3 : Deploy the service

Now it is just a matter of deploying this service. You need to have access to org.apache.axis2.engine.AxisConfiguration to deploy this service. AxisConfiguration can be thought of as the global place holder to keep static information like this. (ConfigurationContext, on the other hand, is responsible for holding global dynamic information.) If you are within a handler, or inside another service, the easiest method is to get hold of the message context and get a pointer to the AxisConfiguration through that. Once you have the AxisConfiguration you can use the addService (AxisService service) method to deploy the service.

AxisConfiguration axisConfig = MessageContext.getCurrentMessageContext().getConfigurationContext().getAxisConfiguration(); 

// now deploy the service
axisConfig.addService(service);

Code Listing 3 : Deploying the service to Axis2

Deploying Modules Dynamically

Axis2 represents a module using the org.apache.axis2.description.AxisModule class. When you deploy a module, typically as a mar file, the Axis2 deployment system detects your modules and stores information about your module within this AxisModule class. If you cannot afford to use the in-built deployment system for some reason, and yet want to deploy a module (mar file) dynamically, take the following approach.

As mentioned, our target should be to create an instance of org.apache.axis2.description.AxisModule from its mar file, and then deploy this AxisModule. Axis2 holds information about the modules it has within the AxisConfiguration. Since module deployment is meant to be used statically, we will be deploying our module to AxisConfiguration.

Step 1 : Create an instance of org.apache.axis2.description.AxisModule

The org.apache.axis2.deployment.DeploymentEngine class within Axis2 comes with the static method AxisModule buildModule(File modulearchive, AxisConfiguration config) to build an instance of the AxisModule from a given mar file. As you can see, this method also requires access to AxisConfiguration. We can use the same method that we used earlier during the deployment of services. We will use MessageContext to get access to AxisConfiguration.

File pathToMyModule = ...; 
AxisConfiguration axisConfiguration = MessageContext.getCurrentMessageContext().getConfigurationContext().getAxisConfiguration();
AxisModule myModule = DeploymentEngine.buildModule(pathToMyModule, axisConfiguration);

Code Listing 4 : Creating an instance of AxisModule from a module archive

Step 3 : Initialize the module

Note that the Axis2 module API contains an init method which must be invoked by the deployer before deploying or engaging this module. The module author can implement the org.apache.axis2.modules.Module interface and expect Axis2 to invoke methods in that. Since we are deploying this module now, we need to get hold of this Module implementation and call the init method. We also need to pass a reference to ConfigurationContext when we call this method. We can get hold of ConfigurationContext using MessageContext.

ConfigurationContext configContext =
MessageContext.getCurrentMessageContext().getConfigurationContext();
Module module = myModule.getModule();
module.init(configContext, myModule);

Code Listing 5 : Initializing the module

Step 3 : Deploy the module

Now it is just a matter of deploying the module.

axisConfiguration.addModule(myModule);

 

Dynamic Module Engagement

We looked at deploying a module dynamically. Now let's see how we can engage this module. Even if you only need to engage a module, which is already deployed in the system, you can follow these steps to accomplish it.

Before moving on, let's just refresh our minds on where we can engage modules. Modules consists of handlers that act on a given message. You can configure these modules to

  1. act on all the messages - global engagement
  2. act on messages coming to a given service - service level engagement
  3. act on messages coming to a given operation - operation level engagement

Before engaging the module, you need to get hold of the proper module. If you didn't follow the Deploying Modules Dynamically section above, you might have to follow the following steps to get access to a module to engage.

AxisConfiguration axisConfiguration =
MessageContext.getCurrentMessageContext().getConfigurationContext().getAxisConfiguration();
AxisModule module = axisConfiguration.getModule("MyModuleName");

Code Listing 6 : Finding the module to engage

The axisConfiguration.getModule("MyModuleName") will return a reference to the module that you are looking for if it has been deployed. If you think there are multiple versions of the same module deployed already, you can give the version number and retrieve that particular version of the module.

AxisModule module = axisConfiguration.getModule("MyModuleName","ModuleVersion");

Code Listing 7 : Retrieving modules with a version

Now that we have the module, let's engage it. The following code snippet will show you how to engage your module at a global level, service level, and operation level. All three methods will be the same except that you need to use the proper object to engage it to.

// engaging globally 
axisConfiguration.engageModule(module);

// engage to a service
AxisService service = .... // get access to the service that you need to engage to service.engageModule(module);

// engage to an operation
AxisOperation operation = .... // get access to the operation that you need to engage to operation.engageModule(module);

Code Listing 8 : Engaging the module at different levels

If you want to engage this module to a service, you can search for that service using axisConfiguration.getService(String name). This will give you a reference to AxisService which represents the service to which you want to engage the module.

If you want to find the operation, first find the service that operation belongs to by using the getService() method. Then use the AxisService.getOperation(QName operationName)method to find the AxisOperation representing the operation.

Summary

In this article, we looked at how we can change the behaviour of the Axis2 engine by deploying a service dynamically (at runtime) and also looked at the deployment of modules. We also looked at engaging modules at various levels, including at runtime. We will look at more advanced features like this, within Axis2, in the upcoming articles of the "Hacking Axis2" series.

 

Resources

Axis2 User Guide

Axis2 deployment model - This contains a good introduction to Axis2 modules and service packaging

Introduction to Message Exchange Patterns

Author

Eran Chinthaka, Member - Apache Software Foundation, chinthaka(!) at apache(!).org(!)

 

About Author

  • Eran Chinthaka
  • Software Engineer
  • WSO2 Inc.