Skip to Main Content

How to Write a Synapse Handler | WSO2 Integrator

In this tutorial, we will explain step by step how to write a Synapse Handler using WSO2 Enterprise Integrator.

What is a custom Synapse Handler?

A custom synapse handler can be used to process each individual request in a specific manner.  The handler enables callbacks to be registered in the following scenarios:

 

  • Request in flow: This executes when the request reaches the synapse handler.
public boolean handleRequestInFlow(MessageContext messageContext);
  • Request out flow: This executes when the request leaves the synapse handler.
public boolean handleRequestOutFlow(MessageContext messageContext);
  • Response in flow: This executes when the response reaches the synapse handler.
public boolean handleResponseInFlow(MessageContext messageContext);
  • Response out flow: This executes when the response leaves the synapse handler.
public boolean handleResponseOutFlow(MessageContext messageContext);

How to create a Synapse Handler

1.In order to write a synapse handler create a new project with the following Maven dependencies added:

<repositories>
    <repository>
        <id>wso2-nexus</id>
        <name>WSO2 internal Repository</name>
        <url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
        <releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
        </releases>
    </repository>
</repositories>
<dependencies>
    <dependency>
        <groupId>org.apache.synapse</groupId>
        <artifactId>synapse-core</artifactId>
        <version>2.1.7-wso2v143</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.3</version>
    </dependency>
    <dependency>
        <groupId>org.apache.axis2.wso2</groupId>
        <artifactId>axis2</artifactId>
        <version>1.6.1-wso2v41</version>
    </dependency>
</dependencies>

2. Once the dependencies have been addressed, extend the rg.apache.synapse.AbstractSynapseHandler class and create the necessary callbacks:

public class CustomHandler extends AbstractSynapseHandler {
    private final static Log log = LogFactory.getLog(CustomHandler.class);

    public boolean handleRequestInFlow(MessageContext messageContext) {
        if (log.isDebugEnabled()) {
log.info("handleRequestInFlow");
        }
        
        return true;
    }

    public boolean handleRequestOutFlow(MessageContext messageContext) {
        if (log.isDebugEnabled()) {
log.info("handleRequestOutFlow");
        }

        return true;
    }

    public boolean handleResponseInFlow(MessageContext messageContext) {
        if (log.isDebugEnabled()) {
log.info("handleResponseInFlow");
        }
        
        return true;
    }

    public boolean handleResponseOutFlow(MessageContext messageContext) {
        if (log.isDebugEnabled()) {
log.info("handleResponseOutFlow");
        }
        
        return true;
    }
}

3. Then compile the project using the following command:

mvn clean install

Synapse Handler Installation

1.When the compilation ends, copy the jar created in the lib folder into Enterprise Integrator or Micro Integrator:

cp ${HANDLER_HOME}/target/com.chakray.integrator.handler-1.0.jar ${INTEGRATOR}/lib

2. In order to enable the Custom Handler, edit the ${INTEGRATOR}/conf/synapse-handlers.xml file and add the following line:

<handler name="CustomHandler" class="com.chakray.integrator.handler.CustomHandler"/>

3. Add the corresponding loggers by attaching the following lines to the ${INTEGRATOR}/conf/log4j2.properties file:

loggers = custom-handler, AUDIT_LOG...
...
logger.custom-handler.name=com.chakray.integrator.handler.CustomHandler
logger.custom-handler.level=DEBUG

 

4. Launch Integrator once all changes have been applied. For each request performed, a log is created on each callback:

Handler Uses

Headers

One of the most common uses of handlers is the reading, modification, or deletion of headers during the request.

Read headers in the request in flow handleRequestInFlow:

org.apache.axis2.context.MessageContext axis2MessageContext = ((Axis2MessageContext) messageContext)
    .getAxis2MessageContext();

// Read headers from request
Object headers = axis2MessageContext
    .getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);

log.info("Headers from request");

for (Object header: ((Map) headers).entrySet()) {
    log.info(header);
}

  • Add a new header/cookie (JSESSIONID) to the response in flow handleResponseOutFlow:
org.apache.axis2.context.MessageContext axis2MessageContext = ((Axis2MessageContext) messageContext)
    .getAxis2MessageContext();

// Add new header to response
Map headers = (Map) axis2MessageContext.getProperty(
    org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS
);

String session = Constants.SESSION_COOKIE_JSESSIONID + "=" + System.currentTimeMillis();
headers.put("Cookie", session);

messageContext.setProperty(
    org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS, headers
);

log.info("Headers from response");
for (Object header: ((Map) axis2MessageContext.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS) ).entrySet()) {
    log.info(header);
}

Body

Another possible Handler use is the reading or modification of the body of the request or response.

  • Read the body of the request in flow handleRequestOutFlow:
try {
    RelayUtils.buildMessage(((Axis2MessageContext) messageContext).getAxis2MessageContext());
} catch (Exception e) {
    log.error(e.getMessage());
}

// Read body request
log.info("Body from request");
log.info(
    messageContext.getEnvelope().getBody().toString()
);

OMElement ns = messageContext.getEnvelope().getBody().getFirstElement();

log.info("Parameters from request");
if (ns != null) {
    Iterator parameters = ns.getChildElements();
    while (parameters.hasNext()) {
        OMElement param = (OMElement) parameters.next();
        log.info("Key: " + param.getQName());
        log.info("Value: " + param.getText());
    }
}

  • Modify the body of the response. In this example, we use a service that restores user attributes and the handler replaces the user password with “*****“. E.g.
try {
    RelayUtils.buildMessage(((Axis2MessageContext) messageContext).getAxis2MessageContext());
} catch (Exception e) {
    log.error(e.getMessage());
}

// Read body response
log.info("Body from response");
log.info(
    messageContext.getEnvelope().getBody().toString()
);

OMElement ns = messageContext.getEnvelope().getBody().getFirstElement();

log.info("Parameters from response");
if (ns != null) {
    Iterator parameters = ns.getChildElements();
    while (parameters.hasNext()) {
        OMElement param = (OMElement) parameters.next();
        Iterator it = param.getChildElements();

        while (it.hasNext()) {
OMElement attribute = (OMElement) it.next();
log.info("Attribute: " + attribute.getLocalName());
log.info("Value: " + attribute.getText());

String localName = attribute.getLocalName();
// Replace user password with ***
if (localName.equals("UM_USER_PASSWORD") ||
localName.equals("UM_SALT_VALUE")) {
attribute.setText("*****");
}
        }
    }
}