Tuesday, October 21, 2008

Creating your own 'Mediator'

Recently I was asked by Ruwan to verify an issue reported by some customer. In order to test the issue, I had to write a new mediator. Since I'm not much familiar with writing these sort of stuff, I was struggling hard to get it working and in the end Ruwan helped me out to write a simple mediator and also taught me how to test it with WSO2 ESB. I will briefly describe how this can be done easily.

Pre-requisites - You need to download and install the latest version of WSO2 ESB on your local machine. (Assume that you have downloaded the WSO2 ESB instance to C:\wso2esb-1.7. I will be referring to this folder as ESB_HOME from this point onwards)

Step 1 - Create a mediator class

As the initial step I wrote a small java class which extends the method AbstractMediator as below.

package org.wso2.esb.client;

import org.apache.axiom.soap.SOAPFault;
import org.apache.synapse.MessageContext;
import org.apache.synapse.mediators.AbstractMediator;

public class TestMediator extends AbstractMediator{

public boolean mediate(MessageContext synCtx) {
SOAPFault fault = synCtx.getEnvelope().getBody().getFault();
return false;

Assume that you have your compiled java class at C:\ESB\mediator\testMediator\org\wso2\esb\client\TestMediator.class

Step 2 - Creating the JAR file

After compiling the class, I created a JAR file using the compiled class.

Open a new command prompt and go to the folder which you have the compiled package (E.g.:- C:\ESB\mediator\testMediator) and type the following command

jar cf testMediator.jar org

Once you type this command it would create the JAR file testMediator.jar at the current location (E.g.:- C:\ESB\mediator\testMediator )

Step 3 - Creating the synapse configuration

In order to test the newly created mediator you can use a simple configuration as below. You can call the mediator which you created using a class mediator ( E.g.:- <class name="org.wso2.esb.client.TestMediator"/> ).

<definitions xmlns="http://ws.apache.org/ns/synapse">
<registry provider="org.wso2.esb.registry.ESBRegistry">
<parameter name="root">file:registry/</parameter>
<parameter name="cachableDuration">15000</parameter>
<sequence name="main">
<sequence key="sampleSequence"/>
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default "fault" sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
<sequence name="sampleSequence" onError="soap11_fault">
<address format="soap11" uri="http://localhost:9000/soap/Adding1"/>
<class name="org.wso2.esb.client.TestMediator"/>
<log level="full"/>
<class name="org.wso2.esb.client.TestMediator"/>
<sequence name="soap11_fault">
<log level="full" separator=","/>
<makefault version="soap11">
<code xmlns:sf11="http://schemas.xmlsoap.org/soap/encoding/" value="sf11:VersionMismatch"/>
<reason value="Exception occurred when transforming the request/response"/>
<log level="full"/>
<header name="To" action="remove"/>
<property name="RESPONSE" value="true"/>

Step 4 - Starting the WSO2 ESB server with the created configuration

Copy this configuration to the ESB_HOME\webapp\WEB-INF\classes\conf and start the WSO2 ESB server. To do this, go to ESB_HOME\bin and run the command wso2-esb.bat

Step 5 - Creating the client to invoke the service

Assume that you have created a service (For you reference I will be attaching the service Adding1.aar which I have created) and deploy it in ESB_HOME\samples\axis2Server\repository\services. Go to the folder ESB_HOME\samples\axis2Server and start the SimpleAxis2Server by executing the executable bat file 'axis2server.bat'.

Now create a client as below and invoke the service deployed through WSO2 ESB.

package org.wso2.esb.client;

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;

public class AxiomClient {
public static void main(String[] args)throws AxisFault{
Options options = new Options();
options.setTo(new EndpointReference("http://localhost:8280/soap"));
ServiceClient sender = new ServiceClient();
OMElement result = sender.sendReceive(getPayload());

private static OMElement getPayload() {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace("http://service.esb.wso2.org", "ns");
OMElement method = fac.createOMElement("add", omNs);
OMElement value1 = fac.createOMElement("x", omNs);
OMElement value2 = fac.createOMElement("y", omNs);
value1.addChild(fac.createOMText(value1, "10"));
value2.addChild(fac.createOMText(value2, "10"));
return method;

Step 6 - Verifying through viewing the logs

Once you invoke the client, the logs displayed on the WSO2 ESB console will show how the class mediator has been invoked

[HttpClientWorker-1] DEBUG InMediator Start : In mediator
[HttpClientWorker-1] DEBUG InMediator Current message is a response - skipping child mediators
[HttpClientWorker-1] DEBUG InMediator End : In mediator
[HttpClientWorker-1] DEBUG OutMediator Start : Out mediator
[HttpClientWorker-1] DEBUG OutMediator Current message is outgoing - executing child mediators
[HttpClientWorker-1] DEBUG OutMediator Sequence <OutMediator> :: mediate()
[HttpClientWorker-1] DEBUG ClassMediator Start : Class mediator
[HttpClientWorker-1] DEBUG ClassMediator invoking : class org.wso2.esb.client.TestMediator.mediate()
The service cannot be found for the endpoint reference (EPR) http://localhost:9000/soap/Adding1
[HttpClientWorker-1] DEBUG ClassMediator End : Class mediator
[HttpClientWorker-1] DEBUG OutMediator End : Out mediator

As you can see only the Class mediator is invoked and non of the mediators specified after wards are not invoked. The reason for this is that when creating the mediator, you have set 'return' to false. Therefore when the Class mediator is invoked none of the mediators available after that Class mediator will not be invoked. If you need to invoke the other mediators that are available after the Class mediator, you have to set 'return' to true. Try this out by yourself. Once you execute the client, it should invoke the Class mediator first and the the Log mediator and after that the rest of the mediators specified.

No comments: