Thursday, September 18, 2008

Reliable message exchange with WSO2 ESB - Invoking WS-RM Service using nonWS-RM one-way client

Invoking a WS-RM enabled service using a one-way client where WS-RM is not enabled

Reliable messaging allows messages to be delivered reliably between applications in the presence of system, or network failures. I will breifly describe how reliable messaging is made possible with WSO2 ESB along with some samples. Step by step information will be provided on how to configure WSO2 ESB to handle the exchanging of messages between WS-Reliable Messaging (WS-RM) enabled services and clients.

To start off with, you will need to download and install WSO2 ESB on your machine. (Refer https://wso2.org/project/esb/java/1.7.1/docs/installationguide.html on how to download and install WSO2 ESB). From this point onwards the location where WSO2 ESB is installed will be refered to as ESB_HOME.


Step 1 - Creating and deploying a WS-RM enabled service.

The implementation class should be created as follows.

package org.wso2.esb.services;

public class RMService {
public void Ping(String x){
System.out.println("Received Ping request");
}
}

Then create a services.xml file as follows

<service name="RMService">
<description>This service is created to add two numbers.</description>
<parameter name="ServiceClass" locked="false">org.wso2.esb.services.RMService</parameter>
<messageReceivers>
<messageReceiver mep="http://www.w3.org/2006/01/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
<messageReceiver mep="http://www.w3.org/2006/01/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</messageReceivers>
<module ref="Mercury"/>
</service>

Place the above services.xml file in a directory named META-INF. Compile the RMService class and get the compiled class, bundle it with the META-INF file and create an .aar file. For testing purposes we will be using the SimpleAxisServer which comes with the WSO2 ESB package so deploy the services. Therefore drop the created archive file in ESB_HOME/samples/axis2Server/repository/services. (To check if the service has been deployed successfully access http://localhost:9000/soap)


Step 2 - Creating the WSO2 ESB Configuration

Start the WSO2 ESB server located at ESB_HOME/bin and access the WSO2 ESB Admin console through https://localhost:9444/esb/

Inorder for the non-WS-RM client to communicate with the WS-RM enabled service the folling configuration should be used. Log in to the WSO2 ESB admin console (username - admin, password - admin) and create the following configuration.


<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="RMProxy" transports="http" startOnLoad="true" statistics="enable">
<target>
<inSequence>
<RMSequence single="true" version="1.0"/>
<send>
<endpoint>
<address uri="http://localhost:9000/soap/RMService">
<enableAddressing/>
<enableRM/>
</address>
</endpoint>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
<enableRM/>
</proxy>
</definitions>

Step 3 - Generating Stubs

Inorder for the client to successfully execute we need to generate stubs. This can easily be done through WSO2 WSAS. (Refer http://charithaka.blogspot.com/2008/02/securing-axis2wsas-web-services-with.html Step 3). For ease of use I will be providing a generated jar file which works with the below client code. You can download it from here
Make sure to add jars in ESB_HOME/lib and the above downloaded client stub jar to your class path in order to compile the client.

Step 4 - Create a non-WS-RM Client

The next step would be create a client to invoke the WS-RM enabled service as follows. The below client supports only SOAP11 messages. For you to try out SOAP12 messages you can use the client
OneWayAnnonSOAP12Client.

public class OneWayAnnonSOAP11Client {
public static void main(String[] args)throws AxisFault {
ConfigurationContext cc = ConfigurationContextFactory.createConfigurationContextFromFileSystem("/home/rmScenario/client_repo","/home/rmScenario/client-repo/axis2.xml");
OMElement payload = createPayLoad();

ServiceClient serviceclient = new ServiceClient(cc, null);

Options opts = new Options();
opts.setTo(new EndpointReference("http://localhost:8280/soap/RMProxy"));
opts.setAction("urn:Ping");

serviceclient.setOptions(opts);

try {
serviceclient.fireAndForget(payload);
} catch (RemoteException e) {
e.printStackTrace();
}

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public static OMElement createPayLoad(){
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace("http://service.esb.wso2.org", "ns");
OMElement method = fac.createOMElement("Ping", omNs);
OMElement value = fac.createOMElement("ping", omNs);
value.addChild(fac.createOMText(method, "pong"));
method.addChild(value);
return method;
}
}

You can access the entire client code from here.

Before you execute the client, make sure you have copied the Mercury.mar (make sure that the mar file is inside a folder named 'module') and axis2.xml to the specified locations above.

Step 5 - Starting the Simple Axis2 Server

Go to the ESB_HOME/samples/axis2Server and start the simple axis2server
E.g.:- sh ./axis2Server.sh

Step 6 - Executing the client

Now you are all set to execute the client. To see whether the messages are being sent properly you can send them through TCPMon.