Monday, March 27, 2017

How to use the custom Axis2 handler in WSO2 ESB

In this article, I'm going to explain how to use Axis2 handler in WSO2 ESB

1. Implement a sample Synapse handler. You can follow my previous blog to write a Synapse handler

2. Implement a sample module

package com.wso2.handler.sample;

import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisDescription;
import org.apache.axis2.description.AxisModule;
import org.apache.axis2.modules.Module;
import org.apache.neethi.Assertion;
import org.apache.neethi.Policy;

/**
 * Created by tharanga.
 */
public class SampleAxis2Module implements Module {
    public void init(ConfigurationContext configurationContext, AxisModule axisModule) throws AxisFault {
        System.out.println("==================================================");
    }

    public void engageNotify(AxisDescription axisDescription) throws AxisFault {

    }

    public boolean canSupportAssertion(Assertion assertion) {
        return true;
    }

    public void applyPolicy(Policy policy, AxisDescription axisDescription) throws AxisFault {

    }

    public void shutdown(ConfigurationContext configurationContext) throws AxisFault {

    }
}

3. Created module.xml as below (in resources folder /META-INF/module.xm)


<module name="CustomLoggingModule" class="com.wso2.handler.sample.SampleAxis2Module">
    <InFlow>
        <handler name="InFlowLogHandler" class="com.wso2.handler.sample.SampleAxis2Handler">
            <order phase="CustomLoggingModulePhase" />
        </handler>
    </InFlow>
</module>

4. Build the jar file and rename to mar and put it into the ESB_HOME/repository/deployment/server/axis2modules/ folder

5. Added the module to the axis2.xml as below
<module ref="CustomLoggingModule"/>

6. To test the scenario I added the phase to the InFlow as below

<phaseOrder type="InFlow">
    ....
    ....
    <phase name="CustomLoggingModulePhase"/>
 </phaseOrder>

7. Start the ESB

How to write Axis2 handler to validate the request payload and send back the response to the client?

In this article I'm going to cover below areas...
  1. How to write a custom Axis2 handler
  2. How to get the request payload
  3. How to validate payload (In this example, I'm checking whether the payload is a valid JSON or not)
  4. Respond to the customer without invoking the mediation flow.
Implement the handler class with extending the AbstractHandler class and implementing the Handler interface.

package com.wso2.handler.sample;

import net.minidev.json.parser.JSONParser;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.AxisEngine;
import org.apache.axis2.engine.Handler;
import org.apache.axis2.handlers.AbstractHandler;
import org.apache.commons.io.IOUtils;
import org.apache.synapse.transport.passthru.util.RelayUtils;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.soap.SOAPFault;
import org.apache.axiom.soap.SOAPFaultCode;
import org.apache.axiom.soap.SOAPFaultDetail;
import org.apache.axiom.soap.SOAPFaultReason;
import org.apache.axis2.util.MessageContextBuilder;

import javax.xml.namespace.QName;

import java.io.InputStream;
import java.io.StringWriter;

/**
 * Created by tharanga on 3/24/17.
 */
public class SampleAxis2Handler extends AbstractHandler implements Handler {

    public InvocationResponse invoke(MessageContext messageContext) throws AxisFault {
        try {

            RelayUtils.buildMessage(messageContext);

            InputStream jsonPaylodStream = (InputStream) (messageContext).getProperty(
                            "org.apache.synapse.commons.json.JsonInputStream");
            StringWriter writer = new StringWriter();
            IOUtils.copy(jsonPaylodStream, writer);
            String payloadMessge = writer.toString();

            try {
                //Validate the json message.
                JSONParser jsonParser = new JSONParser();
                jsonParser.parse(payloadMessge);

                System.out.println(messageContext.getEnvelope().getBody().toString());
                return InvocationResponse.CONTINUE;
            } catch (Exception ex) {
                AxisFault _axisFault = createAxisFault(messageContext, ex);
                MessageContext _faultContext = MessageContextBuilder.createFaultMessageContext(messageContext, _axisFault);
                _faultContext.setProperty("HTTP_SC", "400");

                AxisEngine.sendFault(_faultContext);
                return InvocationResponse.ABORT;
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

        return InvocationResponse.ABORT;
    }

    private AxisFault createAxisFault(MessageContext context, Throwable e) {

        SOAPFactory soapFactory;
        String namespace;
        if (context.isSOAP11()) {
            soapFactory = OMAbstractFactory.getSOAP11Factory();
            namespace = SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI;
        } else {
            soapFactory = OMAbstractFactory.getSOAP12Factory();
            namespace = SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI;
        }
        SOAPFault fault = soapFactory.createSOAPFault();

        SOAPFaultCode soapFaultCode = soapFactory.createSOAPFaultCode();
        soapFaultCode.setText(new QName(namespace, "Server", "soapenv"));

        SOAPFaultReason soapFaultReason = soapFactory.createSOAPFaultReason();
        soapFaultReason.setText("Error while mediate message: " + e.getMessage());

        SOAPFaultDetail soapFaultDetail = soapFactory.createSOAPFaultDetail();
        soapFaultDetail.setText("Invalid message");
        fault.setCode(soapFaultCode);
        fault.setDetail(soapFaultDetail);
        fault.setReason(soapFaultReason);

        return new AxisFault(fault);
    }
}


In the above sample, I'm validating the JSON message and if it fails, send the 400 HTTP response code to the client.

Find the sample test result below



  • Payload with valid JSON message
[2017-03-24 17:10:18,271] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "POST /services/Proxy1 HTTP/1.1[\r][\n]"
[2017-03-24 17:10:18,271] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Host: tharanga:8280[\r][\n]"
[2017-03-24 17:10:18,271] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Connection: keep-alive[\r][\n]"
[2017-03-24 17:10:18,271] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Content-Length: 19[\r][\n]"
[2017-03-24 17:10:18,272] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Postman-Token: e2997992-9a63-6858-3afc-9095f7348130[\r][\n]"
[2017-03-24 17:10:18,272] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Cache-Control: no-cache[\r][\n]"
[2017-03-24 17:10:18,272] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop[\r][\n]"
[2017-03-24 17:10:18,272] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36[\r][\n]"
[2017-03-24 17:10:18,272] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Content-Type: application/json[\r][\n]"
[2017-03-24 17:10:18,272] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept: */*[\r][\n]"
[2017-03-24 17:10:18,273] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept-Encoding: gzip, deflate[\r][\n]"
[2017-03-24 17:10:18,273] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept-Language: en-US,en;q=0.8[\r][\n]"
[2017-03-24 17:10:18,273] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "[\r][\n]"
[2017-03-24 17:10:18,273] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "{"name":"tharanga"}"
tharanga
[2017-03-24 17:10:18,275]  INFO - LogMediator status = 11111111111111111111111111111111111111111111
[2017-03-24 17:10:18,276] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "HTTP/1.1 202 Accepted[\r][\n]"
[2017-03-24 17:10:18,277] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Date: Fri, 24 Mar 2017 11:40:18 GMT[\r][\n]"
[2017-03-24 17:10:18,277] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Transfer-Encoding: chunked[\r][\n]"
[2017-03-24 17:10:18,277] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Connection: keep-alive[\r][\n]"
[2017-03-24 17:10:18,277] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "[\r][\n]"
[2017-03-24 17:10:18,277] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "0[\r][\n]"
[2017-03-24 17:10:18,277] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "[\r][\n]"



  • Payload with invalid JSON message
[2017-03-24 17:10:26,709] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "POST /services/Proxy1 HTTP/1.1[\r][\n]"
[2017-03-24 17:10:26,709] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Host: tharanga:8280[\r][\n]"
[2017-03-24 17:10:26,709] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Connection: keep-alive[\r][\n]"
[2017-03-24 17:10:26,709] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Content-Length: 17[\r][\n]"
[2017-03-24 17:10:26,710] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Postman-Token: 9f7fc1bb-be03-e321-b773-62bea5fce577[\r][\n]"
[2017-03-24 17:10:26,710] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Cache-Control: no-cache[\r][\n]"
[2017-03-24 17:10:26,710] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop[\r][\n]"
[2017-03-24 17:10:26,710] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36[\r][\n]"
[2017-03-24 17:10:26,710] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Content-Type: application/json[\r][\n]"
[2017-03-24 17:10:26,710] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept: */*[\r][\n]"
[2017-03-24 17:10:26,710] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept-Encoding: gzip, deflate[\r][\n]"
[2017-03-24 17:10:26,710] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept-Language: en-US,en;q=0.8[\r][\n]"
[2017-03-24 17:10:26,710] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "[\r][\n]"
[2017-03-24 17:10:26,711] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "{"name":"tharanga"
[2017-03-24 17:10:26,742] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "HTTP/1.1 400 Bad Request[\r][\n]"
[2017-03-24 17:10:26,742] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Content-Type: application/json; charset=UTF-8[\r][\n]"
[2017-03-24 17:10:26,743] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Date: Fri, 24 Mar 2017 11:40:26 GMT[\r][\n]"
[2017-03-24 17:10:26,743] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Transfer-Encoding: chunked[\r][\n]"
[2017-03-24 17:10:26,743] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Connection: Close[\r][\n]"
[2017-03-24 17:10:26,743] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "[\r][\n]"
[2017-03-24 17:10:26,743] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "99[\r][\n]"
[2017-03-24 17:10:26,743] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "{"Fault":{"faultcode":"soapenv:Server","faultstring":"Error while mediate message: Unexpected End Of File position 17: null","detail":"Invalid message"}}[\r][\n]"
[2017-03-24 17:10:26,744] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "0[\r][\n]"
[2017-03-24 17:10:26,744] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "[\r][\n]"



How to use the custom Synapse handler in WSO2 ESB

In this article, I'm going to explain how to use Synapse handler in WSO2 ESB
  1. Implement a Synapse handler. You can follow my previous blog to write a Synapse handler
  2. Build a JAR file (If use maven, you can run: mvn clean install)
  3. Edit the <ESB_HOME>/repository/conf/synapse-handlers.xml file as below
<handlers>
    <handler class="com.wso2.handler.sample.SampleMessageHandler" name="SampleMessageHandler">
</handler></handlers>

Start the ESB server

How to write custom WSO2 synapse handler to validate the payload and response to the client?

In this article I'm going to cover below areas

  1. How to write a Synapse handler
  2. How to get the request payload
  3. How to validate payload (In this example, I'm checking whether the payload is a valid JSON or not)
  4. Respond to the customer without invoking the mediation flow.
Implement the handler class with extending the AbstractSynapseHandler class as below

package com.wso2.handler.sample;

import net.minidev.json.parser.JSONParser;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.AbstractSynapseHandler;
import org.apache.synapse.MessageContext;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.apache.synapse.core.axis2.Axis2Sender;
import org.apache.synapse.transport.passthru.util.RelayUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.Map;

/**
 * Created by tharanga
 */
public class SampleMessageHandler extends AbstractSynapseHandler {

    private static final Log log = LogFactory.getLog(SampleMessageHandler.class);

    public boolean handleRequestInFlow(MessageContext messageContext) {
        try {

            org.apache.axis2.context.MessageContext axis2MessageContext = ((Axis2MessageContext) messageContext)
                    .getAxis2MessageContext();
            Object headers = axis2MessageContext
                    .getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);

            RelayUtils.buildMessage(((Axis2MessageContext) messageContext).getAxis2MessageContext());

            InputStream jsonPaylodStream = (InputStream) ((Axis2MessageContext) messageContext)
                    .getAxis2MessageContext().getProperty(
                            "org.apache.synapse.commons.json.JsonInputStream");
            StringWriter writer = new StringWriter();

            IOUtils.copy(jsonPaylodStream, writer);

            String payloadMessge = writer.toString();

            try {
                //Validate the json message.
                JSONParser jsonParser = new JSONParser();
                jsonParser.parse(payloadMessge);

                System.out.println(messageContext.getEnvelope().getBody().toString());

                
                return true;
            } catch (Exception ex) {
                Map headersMap = (Map) headers;
                headersMap.clear();
                axis2MessageContext.setProperty("HTTP_SC", "400");
                messageContext.setProperty("RESPONSE", "true");
                messageContext.setTo(null);

                Axis2Sender.sendBack(messageContext);

                return false;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    public boolean handleRequestOutFlow(MessageContext messageContext) {
        return true;
    }

    public boolean handleResponseInFlow(MessageContext messageContext) {
        return true;
    }

    public boolean handleResponseOutFlow(MessageContext messageContext) {
        return true;
    }
}

In the above sample, I'm validating the JSON message and if it fails, send the 400 HTTP response code to the client.

Find the sample test result below

  • Payload with valid JSON message
[2017-03-23 22:13:55,933] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "POST /services/Proxy1 HTTP/1.1[\r][\n]"
[2017-03-23 22:13:55,952] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Host: tharanga:8280[\r][\n]"
[2017-03-23 22:13:55,952] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Connection: keep-alive[\r][\n]"
[2017-03-23 22:13:55,952] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Content-Length: 19[\r][\n]"
[2017-03-23 22:13:55,952] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Postman-Token: 29dfad86-fa3e-5576-4bfd-25f503687baa[\r][\n]"
[2017-03-23 22:13:55,952] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Cache-Control: no-cache[\r][\n]"
[2017-03-23 22:13:55,952] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop[\r][\n]"
[2017-03-23 22:13:55,956] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36[\r][\n]"
[2017-03-23 22:13:55,956] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Content-Type: application/json[\r][\n]"
[2017-03-23 22:13:55,956] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept: */*[\r][\n]"
[2017-03-23 22:13:55,956] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept-Encoding: gzip, deflate[\r][\n]"
[2017-03-23 22:13:55,956] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept-Language: en-US,en;q=0.8[\r][\n]"
[2017-03-23 22:13:55,957] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "[\r][\n]"
[2017-03-23 22:13:55,957] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "{"name":"tharanga"}"
tharanga
[2017-03-23 22:13:56,239]  INFO - LogMediator status = 11111111111111111111111111111111111111111111
[2017-03-23 22:13:56,250] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "HTTP/1.1 202 Accepted[\r][\n]"
[2017-03-23 22:13:56,251] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Date: Thu, 23 Mar 2017 16:43:56 GMT[\r][\n]"
[2017-03-23 22:13:56,251] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Transfer-Encoding: chunked[\r][\n]"
[2017-03-23 22:13:56,251] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Connection: keep-alive[\r][\n]"
[2017-03-23 22:13:56,251] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "[\r][\n]"
[2017-03-23 22:13:56,252] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "0[\r][\n]"
[2017-03-23 22:13:56,252] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "[\r][\n]"
  • Payload with invalid JSON message
[2017-03-23 22:14:10,283] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "POST /services/Proxy1 HTTP/1.1[\r][\n]"
[2017-03-23 22:14:10,283] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Host: tharanga:8280[\r][\n]"
[2017-03-23 22:14:10,283] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Connection: keep-alive[\r][\n]"
[2017-03-23 22:14:10,283] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Content-Length: 17[\r][\n]"
[2017-03-23 22:14:10,284] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Postman-Token: 194a9cd8-35ed-3998-08b7-fb94598797a3[\r][\n]"
[2017-03-23 22:14:10,284] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Cache-Control: no-cache[\r][\n]"
[2017-03-23 22:14:10,284] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop[\r][\n]"
[2017-03-23 22:14:10,284] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36[\r][\n]"
[2017-03-23 22:14:10,284] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Content-Type: application/json[\r][\n]"
[2017-03-23 22:14:10,284] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept: */*[\r][\n]"
[2017-03-23 22:14:10,284] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept-Encoding: gzip, deflate[\r][\n]"
[2017-03-23 22:14:10,284] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "Accept-Language: en-US,en;q=0.8[\r][\n]"
[2017-03-23 22:14:10,285] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "[\r][\n]"
[2017-03-23 22:14:10,285] DEBUG - wire HTTP-Listener I/O dispatcher-1 >> "{"name":"tharanga"
[2017-03-23 22:14:10,419] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "HTTP/1.1 400 Bad Request[\r][\n]"
[2017-03-23 22:14:10,420] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Content-Type: application/json; charset=UTF-8[\r][\n]"
[2017-03-23 22:14:10,420] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Date: Thu, 23 Mar 2017 16:44:10 GMT[\r][\n]"
[2017-03-23 22:14:10,420] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Transfer-Encoding: chunked[\r][\n]"
[2017-03-23 22:14:10,420] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "Connection: Close[\r][\n]"
[2017-03-23 22:14:10,420] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "[\r][\n]"
[2017-03-23 22:14:10,421] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "11[\r][\n]"
[2017-03-23 22:14:10,421] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "{"name":"tharanga[\r][\n]"
[2017-03-23 22:14:10,421] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "0[\r][\n]"
[2017-03-23 22:14:10,421] DEBUG - wire HTTP-Listener I/O dispatcher-1 << "[\r][\n]"

Thursday, February 9, 2017

How to write a WSO2 custom mediator to convert XSL-FO to PDF.

Description:

XSL-FO stands for Extensible Stylesheer Language Formatting Objects.

XSL-FO is an XML based markup language describing the formatting of XML data for output to sreen, paper or other media.

So, I'm going to describe the way we can convert XSL-FO to PDF using custom mediator.

Tested Environment:

WSO2 ESB 5.0.0
JDK 1.8

Steps

Step 1:

Add below listed depended JAR's to the project (pom.xml)

 <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>fop</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>xmlgraphics-commons</artifactId>
            <version>1.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-bridge</artifactId>
            <version>1.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-gvt</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-transcoder</artifactId>
            <version>1.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.avalon.framework</groupId>
            <artifactId>avalon-framework-api</artifactId>
            <version>4.3.1</version>
        </dependency>
        <dependency>
            <groupId>batik</groupId>
            <artifactId>batik-1.5-fop</artifactId>
            <version>0.20-5</version>
        </dependency>

Step 2:

 Implement class mediator as below

package org.syntouch.esb.mediators;

import java.io.*;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.soap.SOAPBody;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.synapse.MessageContext;
import org.apache.synapse.mediators.AbstractMediator;

/**
 * Created by tharanga on 2/7/17.
 */
public class TestFile extends AbstractMediator {
    @Override
    public boolean mediate(MessageContext messageContext) {
        trace.info("PdfCreationMediator Process Started");

        SOAPBody soapBody = messageContext.getEnvelope().getBody();
        OMElement firstElement = soapBody.getFirstElement();

        OutputStream out = null;

        try {
            out = new BufferedOutputStream(new FileOutputStream(new File("/home/tharanga/workspace/home/XSL-FO-to-pdf/invoice.pdf")));

            final FopFactory fopFactory = FopFactory.newInstance();

            Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);

            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer();

            String firstElementAsString = firstElement.toString();
            Source src = new StreamSource(new StringReader(firstElementAsString));

            Result res = new SAXResult(fop.getDefaultHandler());

            transformer.transform(src, res);

            trace.info("PdfCreationMediator Process Finished successfully");
        } catch (FOPException | TransformerException | IOException e) {
            trace.info(new String("PdfCreationMediator Process Failed"));
            // e.printStackTrace();
        } finally {
            // Clean-up
            try {
                out.close();
            } catch (IOException e) {
                trace.info(new String("PdfCreationMediator Process Failed"));
                // e.printStackTrace();
            }
        }
        return true;
    }
}


Step 3:

Create a sample proxy to execute class mediator

<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="Proxy1"
       startOnLoad="true"
       statistics="disable"
       trace="disable"
       transports="http,https">
   <target>
      <inSequence>
         <class name="org.syntouch.esb.mediators.TestFile"/>
      </inSequence>
   </target>
   <description/>
</proxy>

With the above steps, we can properly convert XSL-FO to PDf. In the above class mediator, I assiume that, XSL-FO data comes with the request body.

When execute the above sample, PDF file successfully store in the mentioned location.

Wednesday, November 23, 2016

How to connect ESB with RabbitMQ MQTT?

Please follow below steps:

1. Install RabbitMQ

2. Enable management plugin using below command
 sudo rabbitmq-plugins enable rabbitmq_management  

3. Enable MQTT using below command
 sudo rabbitmq-plugins enable rabbitmq_mqtt  

4. Add below jar to <ESB_HOME>/repository/components/lib/
      axis2-transport-rabbitmq-amqp_1.1.0.wso2v9.jar  
      org.eclipse.paho.client.mqttv3_1.0.2.jar  

5. Created inboundEndpoint as follows
 <?xml version="1.0" encoding="UTF-8"?>  
 <inboundEndpoint name="test" onError="fault" protocol="mqtt"  
  sequence="TestIn" suspend="false" xmlns="http://ws.apache.org/ns/synapse">  
  <parameters>  
   <parameter name="sequential">true</parameter>  
   <parameter name="mqtt.connection.factory">mqttFactory</parameter>  
   <parameter name="mqtt.server.host.name">localhost</parameter>  
   <parameter name="mqtt.server.port">1883</parameter>  
   <parameter name="mqtt.topic.name">esb.test2</parameter>  
   <parameter name="content.type">application/json</parameter>  
   <parameter name="mqtt.subscription.qos">0</parameter>  
   <parameter name="mqtt.session.clean">false</parameter>  
   <parameter name="mqtt.ssl.enable">false</parameter>  
   <parameter name="mqtt.subscription.username">guest</parameter>  
   <parameter name="mqtt.subscription.password">guest</parameter>  
  </parameters>  
 </inboundEndpoint>  

 <?xml version="1.0" encoding="UTF-8"?>  
 <sequence name="TestIn" trace="disable" xmlns="http://ws.apache.org/ns/synapse">  
  <log level="full"/>  
  <drop/>  
 </sequence>  


You can test above explained setup using below steps:

1. You can see the successfully connected message in the ESB log, as below
 [2016-11-15 22:37:36,397] INFO - MqttConnectionConsumer Connected to the remote server.  

2. Add messages to the RabbitMQ using below command
 mosquitto_pub -h localhost -t esb.test2 -m "{"name":"tharanga"}"  

3. ESB receive messages successfully as below
 [2016-11-05 01:18:03,247] INFO - MqttAsyncCallback Received Message: Topic: esb/test2  
 [2016-11-05 01:18:03,247] INFO - LogMediator To: , MessageID: urn:uuid:AF748E7A7D10D0D8A61478288883249, Direction: request, Payload: {name:tharanga}  

Tested environment:

  • ESB 4.9.0
  • RabbitMQ 3.4.3

Tuesday, September 13, 2016

How handle empty soapAction in WSO2 ESB?

When we publish a WSDL with empty soapAction in ESB, we cannot call the service directly. This article will explain the how to fix this issue.

We defined the soapAction="" in the WSDL as below

...
s0:operation name="getUserProperties">
<s5:operation soapAction="" style="document"/>
<s0:input>
...
<s5:operation soapAction="" style="document"/>
...

Now when you call a service, you will get the below exception:
[2016-08-31 23:47:04,591] ERROR - AxisEngine The endpoint reference (EPR) for the Operation not found is /services/UserRegistryWsdlCxf.UserRegistryWsdlCxfHttpSoap11Endpoint and the WSA Action = . If this EPR was previously reachable, please contact the server administrator.
org.apache.axis2.AxisFault: The endpoint reference (EPR) for the Operation not found is /services/UserRegistryWsdlCxf.UserRegistryWsdlCxfHttpSoap11Endpoint and the WSA Action = . If this EPR was previously reachable, please contact the server administrator.
    at org.apache.axis2.engine.DispatchPhase.checkPostConditions(DispatchPhase.java:102)
    at org.apache.axis2.engine.Phase.invoke(Phase.java:329)
    at org.apache.axis2.engine.AxisEngine.invoke(AxisEngine.java:261)
    at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:167)
    at org.apache.synapse.transport.passthru.ServerWorker.processEntityEnclosingRequest(ServerWorker.java:395)
    at org.apache.synapse.transport.passthru.ServerWorker.run(ServerWorker.java:142)
    at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
   
You can follow below steps to avoid this exception:

1. Add following entry to axis2.xml -> InFlow -> Addressing phase. It'll engage the new WSAddressingHandler.

<handler name="WSAddressingHandler"

class="org.apache.synapse.transport.passthru.util.WSAddressingHandler">

<order phase="Addressing"/>

</handler>


2. In the proxy service which requires WS-Addressing, add the following service parameter.
<parameter name="enforceWSAddressing">true</parameter>


Now you can call a service without any issue.

Reference:
https://docs.wso2.com/display/Governance453/Adding+a+Resource