Message Builder's in ESB
In WSO2 ESB message
builders are used to convert the message into SOAP. Whenever a
message came into ESB, the receiving transport will select a message
builder from axis2.xml based on the content type of the message and
convert it to SOAP and it will be used throughout the mediation.
There are predefined
message builders inside ESB and you can refer [1] for more details on
it.
In some
circumstances, we need to change the logic inside the predefined
message builders to achieve some custom tasks while the message get
build. Here, for example, consider that there is a message with
invalid namespace configuration or malformed xml message comes into
the ESB and at that time while building at axiom level it will throw
exception and the message will not propagate
to synapse level.
For some validation purpose or guranteed delivery we may need the
message to be
get into synapse
level, even when there is a exception occur at message builder.
In these cases we
need to create a custom message builder to capture the exception and
handling it and passing a custom payload with the original message to
the synapse level. Below is the sample custom message builder, which
will capture the exception while message building and send a custom
payload back to synapse level. In this sample used the Builder
interface to implement the custom message builder and as the expected
message content type is application/xml used the same logic of the
ApplicationXMLBuilder and handled the exception. Based on your need
you can modify which contentType you want to handle and use the
Builder interface to implement your custom use case.
When using this if
you want to use this for a specific proxy service only in a JMS
listener you need to first add this to axis2.xml
<messageBuilder contentType="application/test" class="com.custom.messagebuilder.CustomApplicationXMLMessageBuilder"/>
Then add the content
type parameter in the proxy as below:
<parameter name="transport.jms.ContentType">application/test</parameter>
The Java Sample Message Builder
package com.custom.messagebuilder; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PushbackInputStream; import java.io.StringWriter; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.impl.OMNodeEx; import org.apache.axiom.om.impl.builder.StAXBuilder; import org.apache.axiom.om.impl.builder.StAXOMBuilder; import org.apache.axiom.om.util.AXIOMUtil; import org.apache.axiom.om.util.StAXParserConfiguration; import org.apache.axiom.om.util.StAXUtils; import org.apache.axiom.soap.SOAPBody; import org.apache.axiom.soap.SOAPEnvelope; import org.apache.axiom.soap.SOAPFactory; import org.apache.axis2.AxisFault; import org.apache.axis2.builder.Builder; import org.apache.axis2.context.MessageContext; import org.apache.axis2.Constants; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /* This is a custom message builder to escape the build error's at axis2 level due to invalid messages and forward a custom error message with the actual message as value for <originalMessage> * tag to the synapse level. * */ public class CustomApplicationXMLMessageBuilder implements Builder { private static final Log log = LogFactory .getLog(CustomApplicationXMLMessageBuilder.class); private final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); public CustomApplicationXMLMessageBuilder() { inputFactory.setProperty("javax.xml.stream.supportDTD", Boolean.FALSE); inputFactory.setProperty( "javax.xml.stream.isReplacingEntityReferences", Boolean.FALSE); inputFactory.setProperty( "javax.xml.stream.isSupportingExternalEntities", Boolean.FALSE); } public OMElement processDocument(InputStream inputStream, String contentType, MessageContext messageContext) throws AxisFault { if (log.isInfoEnabled()) { log.info("[CustomApplicationXMLMessageBuilder]" + "- Invoked"); log.info("[CustomApplicationXMLMessageBuilder]" + "- Content Type Received: " + contentType); } // Cloning the input stream to get the original message into exception. byte[] byteArray = null; try { byteArray = IOUtils.toByteArray(inputStream); } catch (IOException e2) { e2.printStackTrace(); } InputStream input1 = new ByteArrayInputStream(byteArray); InputStream input2 = new ByteArrayInputStream(byteArray); SOAPFactory soapFactory = OMAbstractFactory.getSOAP11Factory(); SOAPEnvelope soapEnvelope = soapFactory.getDefaultEnvelope(); if (input1 != null) { if (log.isInfoEnabled()) { log.info("[CustomApplicationXMLMessageBuilder] Inputstream not null."); } try { PushbackInputStream pushbackInputStream = new PushbackInputStream( input1); int b; if ((b = pushbackInputStream.read()) > 0) { pushbackInputStream.unread(b); javax.xml.stream.XMLStreamReader xmlReader; if ("true" .equals(messageContext .getProperty(Constants.Configuration.APPLICATION_XML_BUILDER_ALLOW_DTD)) || ((messageContext .getParameter(Constants.Configuration.APPLICATION_XML_BUILDER_ALLOW_DTD) != null) && ("true" .equals(messageContext .getParameter( Constants.Configuration.APPLICATION_XML_BUILDER_ALLOW_DTD) .getValue())))) { xmlReader = inputFactory .createXMLStreamReader( pushbackInputStream, (String) messageContext .getProperty(Constants.Configuration.CHARACTER_SET_ENCODING)); } else { xmlReader = StAXUtils .createXMLStreamReader( StAXParserConfiguration.SOAP, pushbackInputStream, (String) messageContext .getProperty(Constants.Configuration.CHARACTER_SET_ENCODING)); } // Handling the exception thrown, when a invalid message received to StAXOMBuilder try { StAXBuilder builder = new StAXOMBuilder(xmlReader); OMNodeEx documentElement = (OMNodeEx) builder .getDocumentElement(); documentElement.setParent(null); SOAPBody body = soapEnvelope.getBody(); body.addChild(documentElement); } catch (Exception e) { if (log.isWarnEnabled()) { log.warn("[CustomApplicationXMLMessageBuilder] Exception thrown due to Invalid Message and creating a custom message to forward to synapse level."); } // Reading the original message by copying the input stream to writer StringWriter writer = new StringWriter(); String originalPayload; IOUtils.copy(input2, writer); originalPayload = writer.toString(); if (log.isDebugEnabled()) { log.debug("[CustomApplicationXMLMessageBuilder] Original Payload Received at Input Stream: " + originalPayload); } //Appending the custom payload to the soap body SOAPBody body = soapEnvelope.getBody(); OMElement documentElementInvalidMessage = null; OMElement documentElementOriginalPayload = null; documentElementInvalidMessage = AXIOMUtil.stringToOM("<messageType>" + "INVALID_MESSAGE" + "</messageType>"); documentElementOriginalPayload = AXIOMUtil.stringToOM("<originalMessage>"+ "<![CDATA[" + originalPayload + "]]>" +"</originalMessage>"); body.addChild(documentElementInvalidMessage); body.addChild(documentElementOriginalPayload); } } } catch (XMLStreamException e) { if (log.isWarnEnabled()) { log.warn("[CustomApplicationXMLMessageBuilder]" + "- Entered XML Stream Exception."); } throw AxisFault.makeFault(e); } catch (IOException e) { if (log.isWarnEnabled()) { log.warn("[CustomApplicationXMLMessageBuilder]" + "- Entered IO Exception."); } throw AxisFault.makeFault(e); } } if (log.isInfoEnabled()) { log.info("[CustomApplicationXMLMessageBuilder]" + "- Returned SOAP Envelope: " + soapEnvelope); } return soapEnvelope; } }
The pom.xml
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <groupid>CustomApplicationXMLMessageBuilder</groupid> <artifactid>CustomApplicationXMLMessageBuilder</artifactid> <version>0.0.1</version> <name>CustomApplicationXMLMessageBuilder</name> <dependencies> <dependency> <groupid>org.apache.axis2.wso2</groupid> <artifactid>axis2</artifactid> <version>1.6.1.wso2v14</version> </dependency> <dependency> <groupid>org.apache.ws.commons.axiom.wso2</groupid> <artifactid>axiom</artifactid> <version>1.2.11.wso2v6</version> </dependency> <dependency> <groupid>commons-logging</groupid> <artifactid>commons-logging</artifactid> <version>1.1.1</version> </dependency> <dependency> <groupid>org.apache.commons</groupid> <artifactid>commons-io</artifactid> <version>1.3.2</version> </dependency> </dependencies> <repositories> <repository> <releases> <enabled>true</enabled> <updatepolicy>daily</updatepolicy> <checksumpolicy>ignore</checksumpolicy> </releases> <id>wso2-nexus</id> <url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url> </repository> </repositories> <pluginrepositories> <pluginrepository> <releases> <enabled>true</enabled> <updatepolicy>daily</updatepolicy> <checksumpolicy>ignore</checksumpolicy> </releases> <id>wso2-nexus</id> <url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url> </pluginrepository> </pluginrepositories> <build> <plugins> <plugin> <artifactid>maven-eclipse-plugin</artifactid> <version>2.9</version> <configuration> <buildcommands> <buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand> </buildcommands> <projectnatures> <projectnature>org.wso2.developerstudio.eclipse.artifact.mediator.project.nature</projectnature> <projectnature>org.eclipse.jdt.core.javanature</projectnature> </projectnatures> </configuration> </plugin> </plugins> </build> </project>
No comments:
Post a Comment