Its often a requirement to perform content based routing in an ESB. This means you route messages around your service bus based on the message properties or the content of the messages. When integrating systems across language boundaries its common to use XML as a universal message format; so XPath is an ideal tool to perform content based routing and transformation.
We support a XPath based routing and transformation mechanism designed for high performance and power.
Example
The following is an example routing and transformation template. Firstly we reuse the XSLT basd transform component.
<sm:activationSpec componentName="transformer" service="foo:transformer">
<sm:component><bean class="org.apache.servicemix.components.xslt.XsltComponent">
<property name="xsltResource" value="classpath:org/apache/servicemix/components/xslt/router.xsl"/>
<!-- lets disable automatic output of the result of the transform; only if we perform
an invoke in the XSLT will we invoke another endpoint -->
<property name="disableOutput" value="true"/>
</bean></sm:component>
</sm:activationSpec>
Then we provide a file in XSLT format, with some JBI extensions
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:jbi="xalan://org.apache.servicemix.components.xslt.XalanExtension"
extension-element-prefixes="jbi"
xmlns:foo="http://servicemix.org/cheese/"
version="1.0">
<xsl:template match="/*">
<xsl:choose>
<xsl:when test="@id = '4'">
<jbi:forward service="foo:trace"/>
</xsl:when>
<xsl:when test="@id = '12'">
<jbi:invoke service="foo:script">
<jbi:copyProperties/>
<jbi:setOutProperty name="foo" select="@sent"/>
<cheese code="{@id}">
<description>This is some content generated from the routing XSL</description>
</cheese>
</jbi:invoke>
</xsl:when>
<xsl:when test="@id != '2'">
<jbi:forward service="foo:receiver"/>
</xsl:when>
<xsl:otherwise>
<jbi:forward service="foo:trace"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
In the above example, depending on the value of the @id attribute, we invoke different services.
Notice that we declare the jbi namespace and some attributes on the root XSLT stylesheet element. We then have the following extension elements available to the XSTL
Xalan extension summary
The following new XML tags are available in Xalan when working with ServiceMix
Element |
Description |
forward |
will forward the current inbound message to the given service, interface and/or operation. This mechanism will use the properties and content of the inbound message to create the outbound message |
invoke |
will perform a one way service invocation where the body of the invoke tag represents the XML content of the message. Notice from the above we can use XPath expressions to create the XML |
Invoking multiple service endpoints
The following example shows a number of services being invoked one after the other, using optionally different properties. In each case the original XML message is used as the body of the new inbound request.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:jbi="xalan://org.apache.servicemix.components.xslt.XalanExtension"
extension-element-prefixes="jbi"
xmlns:foo="http://servicemix.org/cheese/"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<jbi:invoke service="foo:service1">
<jbi:copyProperties/>
<jbi:setOutProperty name="foo" select="/sample"/>
<xsl:copy-of select="/"/>
</jbi:invoke>
<jbi:invoke service="foo:service2">
<jbi:copyProperties/>
<jbi:setOutProperty name="bar" select="/sample/@id"/>
<xsl:copy-of select="/"/>
</jbi:invoke>
<jbi:invoke service="foo:service3">
<jbi:copyProperties/>
<jbi:setOutProperty name="foo" select="string(/sample)"/>
<jbi:setOutProperty name="bar" select="string(/sample/@id)"/>
<xsl:copy-of select="/"/>
</jbi:invoke>
<jbi:invoke service="foo:receiver">
<jbi:copyProperties/>
<jbi:setOutProperty name="bar" select="/sample/@id"/>
<xsl:copy-of select="/"/>
</jbi:invoke>
</xsl:template>
</xsl:stylesheet>
Splitting up an XML message into multiple service invocations
This example demonstrates a message being split into multiple different sections of XML which are then invoked on different services.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:jbi="xalan://org.apache.servicemix.components.xslt.XalanExtension"
extension-element-prefixes="jbi"
xmlns:foo="http://servicemix.org/cheese/" version="1.0">
<xsl:template match="/">
<jbi:invoke service="foo:service1">
<cheese id="{/foo/@id}">Edam</cheese>
</jbi:invoke>
<jbi:invoke service="foo:service2">
<xsl:copy-of select="/foo/beer"/>
</jbi:invoke>
<xsl:for-each select="/foo/lineitem">
<jbi:invoke service="foo:service3">
<xsl:copy-of select="."/>
</jbi:invoke>
</xsl:for-each>
<jbi:invoke service="foo:receiver">
<jbi:copyProperties/>
<jbi:setOutProperty name="bar" select="/sample/@id"/>
<xsl:copy-of select="/"/>
</jbi:invoke>
</xsl:template>
</xsl:stylesheet>
Why use Xalan?
We use Xalan to implement our XPath based router and transformation engine. The main reasons for doing so are
- we typically need to evaluate many XPath expressions on a single message exchange; so we can create them all inside the stylesheet such that they are evaluated efficiently each time.
- Xalan can turn the stylesheet into bytecode, which we can then cache/pool to ensure the routing and transformations are as fast as possible while still using the power and flexiblity of XPath.
- Xalan is optimised to only parse what is required of a document to satisfy the template