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>

      <!-- lets forward the inbound message to a service -->
      <xsl:when test="@id = '4'">
        <jbi:forward service="foo:trace"/>
      </xsl:when>

      <!-- lets generate the output XML to use as input, copy the input properties and define some new propertes -->
      <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="/">

    <!-- lets invoke a number of services one after the other -->
    <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="/">

    <!-- lets pass a new message body -->
    <jbi:invoke service="foo:service1">
      <cheese id="{/foo/@id}">Edam</cheese>
    </jbi:invoke>

    <!--  lets split the message  -->
    <jbi:invoke service="foo:service2">
      <xsl:copy-of select="/foo/beer"/>
    </jbi:invoke>

    <!-- 1-many split -->
    <xsl:for-each select="/foo/lineitem">
      <jbi:invoke service="foo:service3">
        <xsl:copy-of select="."/>
      </jbi:invoke>
    </xsl:for-each>

    <!--  pass the  entire message to the final endpoint  -->
    <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