Google I/O 2008 - OpenSocial, OpenID, and OAuth: Oh, My!

Adding Axis2 handlers programmatically

Following the thread here, thought to have this blog post on the $subject.

This explains how you could add handlers in Axis2 programmatically.

package org.apache.ws.axis2;

import java.util.ArrayList;
import java.util.Iterator;

import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.engine.Phase;
import org.apache.axis2.engine.ServiceLifeCycle;
import org.apache.axis2.phaseresolver.PhaseException;

/**
* The service implementation class
*/
public class SimpleService implements ServiceLifeCycle {

/**
* This will be called during the deployment time of the service.
* Irrespective of the service scope this method will be called
*/
public void startUp(ConfigurationContext configctx, AxisService service) {
AxisConfiguration config = null;
ArrayList phases = null;

config = service.getAxisConfiguration();
phases = config.getInFlowPhases();

for (Iterator iterator = phases.iterator(); iterator.hasNext();) {
Phase phase = (Phase) iterator.next();
if ("Security".equals(phase.getPhaseName())) {
SimpleHandler handler = new SimpleHandler();
try {
// This will be the last handler under Security phase
phase.setPhaseLast(handler);
} catch (PhaseException e) {
e.printStackTrace();
}
System.out.println("Added SimpleHandler under Sceurity phase...");
return;
}
}
}

/**
* This will be called during the system shut down time. Irrespective of the
* service scope this method will be called
*/
public void shutDown(ConfigurationContext configctx, AxisService service) {
System.out.println("ServiceLifeCycle:::shutDown()");

}

/**
* The echo method which will be exposed as the echo operation of the web
* service
*/
public String echo() {
return "Hi";
}

}

<service name="SimpleService" class="org.apache.ws.axis2.SimpleService" scope="application">
<operation name="echo">
<messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</operation>
<parameter name="ServiceClass" locked="false">org.apache.ws.axis2.SimpleService</parameter>
</service>

package org.apache.ws.axis2;

import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.description.HandlerDescription;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.description.PhaseRule;
import org.apache.axis2.engine.Handler;

public class SimpleHandler implements Handler {

/**
* {@inheritDoc}
*/
public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {
System.out.println("Service Invoked : " + msgContext.getAxisService().getName());
System.out.println("Operation Invoked : "
+ msgContext.getAxisOperation().getName().getLocalPart());
return InvocationResponse.CONTINUE;
}

/**
* {@inheritDoc}
*/
public HandlerDescription getHandlerDesc() {
HandlerDescription handlerDesc = null;
PhaseRule rule = null;

rule = new PhaseRule("Security");
rule.setPhaseLast(true);

handlerDesc = new HandlerDescription();
handlerDesc.setHandler(this);
handlerDesc.setName(this.getName());
handlerDesc.setRules(rule);

return handlerDesc;
}

/**
* {@inheritDoc}
*/
public String getName() {
return "SimpleHandler";
}

/**
* {@inheritDoc}
*/
public void cleanup() {
}

/**
* {@inheritDoc}
*/
public void flowComplete(MessageContext msgContext) {
}

/**
* {@inheritDoc}
*/
public Parameter getParameter(String name) {
return null;
}

/**
* {@inheritDoc}
*/
public void init(HandlerDescription handlerDesc) {
}

}

Enabling JMS transport for Axis2 services

This post explains how you could enable JMS transport for Axis2 services deployed on WSAS.

WSO2 WSAS is an enterprise ready Web services engine powered by Apache Axis2.

It is a lightweight, high performing platform for Service Oriented Architectures, enabling business logic and applications. Bringing together a number of Apache Web services projects, WSO2 WSAS provides a secure, transactional and reliable runtime for deploying and managing Web services

Once you start WSAS with [WSAS_HOME]\bin\startup.bat and hit the url https://localhost:9443 you can login with admin/admin.

Click the menu item 'services' and you'll find the set of available services.

Click on the 'echo' service and then the 'Manage Transports' - you can find that only http and https transports are available.

Let's see how we can configure JMS for the 'echo' service.

You can find axis2.xml inside [WSAS_HOME]\conf - edit it to uncomment the following.

<transportReceiver name="jms" class="org.apache.axis2.transport.jms.JMSListener">
<parameter name="myTopicConnectionFactory">
<parameter name="java.naming.factory.initial">
org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter>
<parameter name="java.naming.provider.url">
tcp://localhost:61616</parameter>
<parameter name="transport.jms.ConnectionFactoryJNDIName">
TopicConnectionFactory</parameter>
</parameter>

<parameter name="myQueueConnectionFactory">
<parameter name="java.naming.factory.initial">
org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter>
<parameter name="java.naming.provider.url">
tcp://localhost:61616</parameter>
<parameter name="transport.jms.ConnectionFactoryJNDIName">
QueueConnectionFactory</parameter>
</parameter>

<parameter name="default">
<parameter name="java.naming.factory.initial">
org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter>
<parameter name="java.naming.provider.url">
tcp://localhost:61616</parameter>
<parameter name="transport.jms.ConnectionFactoryJNDIName">
QueueConnectionFactory</parameter>
</parameter>
</transportReceiver>


<transportSender name="jms"
class="org.apache.axis2.transport.jms.JMSSender"/>
The above configuration defines three connection factories.

The JMS transport receiver configuration allows you to define the default connection factory (named as "default") for use by Axis2 services using the JMS transport. This connection factory would be used by any service which does not explicitly specify a connection factory name in its services.xml.

In case your service needs a different connection factory,other than the 'default' one - that needs to be mentioned in the services.xml.

<parameter name="transport.jms.ConnectionFactory" locked="true">myTopicConnectionFactory</parameter>
Now you need to run a message broker. You can download ActiveMQ 5.2 from here.

Copy the file activemq-all-5.2.0.jar from [ACTIVEMQ_HOME] to [WSAS_HOME]\lib.

All set - now restart the WSAS.

If you view transports available for 'echo' service through WSAS admin console [as you did previously], you'll find JMS is now available.

Also in the 'echo' service page you may notice that there are three endpoints available under 'Endpoint References' - what we'll be using for the 'echo' service client is the 'jms' endpoint.

One thing to notice here is a service on an Axis2 instance is deployed on all started transports by default, unless a list of transports are specified in its services.xml.

In case your service only to be deployed on JMS, you should specify it in the services.xml

<transports>
<transport>jms</transport>
</transports>
All set - let's move to the client.

Make sure you have the actievemq-all-5.2.0.jar in the client classpath and jms transport being enabled in client.axis2.xml.

package org.apache.ws.axis2;

import javax.xml.namespace.QName;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;

public class Client {

/**
* @param args
* @throws AxisFault
*/
public static void main(String[] args) throws AxisFault {

ConfigurationContext context = null;
ServiceClient client = null;
Options options = null;
OMElement response = null;

context = ConfigurationContextFactory.createConfigurationContextFromFileSystem("repo",
"repo/conf/client.axis2.xml");
client = new ServiceClient(context, null);
options = new Options();
options.setAction("urn:echoString");
options
.setTo(new EndpointReference(
"jms:/echo?transport.jms.ConnectionFactoryJNDIName=QueueConnectionFactory"
+ "&java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory"
+ "&java.naming.provider.url=tcp://localhost:61616"));

client.setOptions(options);
response = client.sendReceive(getPayload("hi"));
System.out.println(response.getFirstChildWithName(new QName("return")).getText());
}

private static OMElement getPayload(String value) {
OMFactory factory = null;
OMNamespace ns = null;
OMElement elem = null;
OMElement childElem = null;

factory = OMAbstractFactory.getOMFactory();
ns = factory.createOMNamespace("http://echo.services.wsas.wso2.org", "ns1");
elem = factory.createOMElement("echoString", ns);
childElem = factory.createOMElement("param0", null);
childElem.setText(value);
elem.addChild(childElem);
return elem;
}

}