INT-1659 changed the name of the attribute to 'evaluate-as-string', updated schema and tests. Updated documentation

This commit is contained in:
Oleg Zhurakousky
2010-12-03 13:37:42 -05:00
parent 928f38f315
commit 6725b68d5d
6 changed files with 64 additions and 23 deletions

View File

@@ -485,20 +485,61 @@
<si:poller fixed-rate="2000"/>
</si-xml:xpath-splitter>]]></programlisting>
</para>
<para>
XPath router namespace support allows for the creation of a Message Endpoint with an input channel but no output channel
since the output channel is determined dynamically. The <code>multi-channel</code> attribute causes the creation of a multi channel router capable of
routing a single message to many channels when true and a single channel router when false.
<programlisting language="xml"><![CDATA[<!-- route the message according to exactly one order type channel -->
<si-xml:xpath-router id="orderTypeRouter" input-channel="orderChannel" multi-channel="false">
since the output channel(s) is determined dynamically.
<programlisting language="xml"><![CDATA[
<si-xml:xpath-router id="orderTypeRouter" input-channel="orderChannel">
<si-xml:xpath-expression expression="/order/type"/>
</si-xml:xpath-router>
<!-- route the order to all responders-->
<si-xml:xpath-router id="responderRouter" input-channel="orderChannel" multi-channel="true">
</si-xml:xpath-router>
]]></programlisting>
</para>
<para>
Internally XPath expression will be evaluated as <emphasis>NODESET</emphasis> type and converted to a
<classname>List&lt;String&gt;</classname> representing channel names. Typically such list will contain a single channel name.
However, based on the result of an XPath Expression XPath router can also take on the characteristics of the <emphasis>Recipient List Router</emphasis>
if XPath Expression returns more then one value, thus resulting in the <classname>List&lt;String&gt;</classname> containing more
then one channel name. In that case Message will be sent to all channels in the list.
So assuming that the xml file passed to the router configured below contains many <code>responder</code> sub-elements representing channel names,
the message will be sent to all of those channels.
<programlisting language="xml"><![CDATA[<!-- route the order to all responders-->
<si-xml:xpath-router id="responderRouter" input-channel="orderChannel">
<si-xml:xpath-expression expression="/request/responders"/>
<si:poller fixed-rate="2000"/>
</si-xml:xpath-router>]]></programlisting>
</si-xml:xpath-router>
]]></programlisting>
If the returned values do not represent the channel names additional mapping could be specified. For example if
the <code>/request/responders</code> expression results in two values <code>responderA</code> and <code>responderB</code> but
you don't want to couple the responder names to channel names you may provide additional mapping as such:
<programlisting language="xml"><![CDATA[<!-- route the order to all responders-->
<si-xml:xpath-router id="responderRouter" input-channel="orderChannel">
<si-xml:xpath-expression expression="/request/responders"/>
<int-xml:mapping value="responderA" channel="channelA"/>
<int-xml:mapping value="responderB" channel="channelB"/>
</si-xml:xpath-router>
]]></programlisting>
</para>
<para>
As we already said the default evaluation type for XPath expressions is NODESET which is converted
to a List&lt;String&gt; of channel names, thus handling single channel scenarios as well as multiple.
However certain XPath expressions may evaluate as String type from the very
beginning (e.g., 'name(./node())' - which will return the name of the root node) thus resulting in
the exception if default evaluation type (NODESET) is used.
For these scenarious you may use <code>evaluate-as-string</code> attribute which will allow you to manage the
evaluation type. It is FALSE by default, however if set to TRUE, the String evaluation type will be used.
For example if we want to route based on the name of the root node we can have use the following configuration:
<programlisting language="xml"><![CDATA[<int-xml:xpath-router id="xpathRouterAsString"
input-channel="xpathStringChannel"
evaluate-as-string="true">
<int-xml:xpath-expression expression="name(./node())"/>
</int-xml:xpath-router>
]]></programlisting>
</para>
</section>

View File

@@ -47,7 +47,7 @@ public class XPathRouterParser extends AbstractRouterParser {
element.getNamespaceURI(), "xpath-expression");
Assert.isTrue(xPathExpressionNodes.getLength() <= 1, "At most one xpath-expression child may be specified.");
String xPathExpressionRef = element.getAttribute("xpath-expression-ref");
IntegrationNamespaceUtils.setValueIfAttributeDefined(xpathRouterBuilder, element, "evaluate-as-node");
IntegrationNamespaceUtils.setValueIfAttributeDefined(xpathRouterBuilder, element, "evaluate-as-string");
boolean xPathExpressionChildPresent = (xPathExpressionNodes.getLength() == 1);
boolean xPathReferencePresent = StringUtils.hasText(xPathExpressionRef);
Assert.isTrue(xPathExpressionChildPresent ^ xPathReferencePresent,

View File

@@ -47,7 +47,7 @@ public class XPathRouter extends AbstractMessageRouter {
private volatile XmlPayloadConverter converter = new DefaultXmlPayloadConverter();
private volatile boolean evaluateAsNode = true;
private volatile boolean evaluateAsString = false;
/**
* Create a router that uses an XPath expression. The expression may
@@ -97,8 +97,8 @@ public class XPathRouter extends AbstractMessageRouter {
this.xPathExpression = expression;
}
public void setEvaluateAsNode(boolean evaluateAsNode) {
this.evaluateAsNode = evaluateAsNode;
public void setEvaluateAsString(boolean evaluateAsString) {
this.evaluateAsString = evaluateAsString;
}
/**
@@ -117,11 +117,11 @@ public class XPathRouter extends AbstractMessageRouter {
@SuppressWarnings("unchecked")
protected List<Object> getChannelIdentifiers(Message<?> message) {
Node node = this.converter.convertToNode(message.getPayload());
if (this.evaluateAsNode){
return this.xPathExpression.evaluate(node, this.nodeMapper);
if (this.evaluateAsString){
return Collections.singletonList((Object)this.xPathExpression.evaluateAsString(node));
}
else {
return Collections.singletonList((Object)this.xPathExpression.evaluateAsString(node));
return this.xPathExpression.evaluate(node, this.nodeMapper);
}
}

View File

@@ -369,11 +369,11 @@
</xsd:element>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:ID"/>
<xsd:attribute name="evaluate-as-node" type="xsd:boolean" default="true">
<xsd:attribute name="evaluate-as-string" type="xsd:boolean" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
By default XPath expressions are evaluated as NODESET type and then converted
to a List<String> of channel names, thus handling single channel scenarios as well as multiple.
to a List of channel names, thus handling single channel scenarios as well as multiple.
However certain XPath expressions may evaluate as String type from the very
beginning (e.g., 'name(./node())' - which will return the name of the root node) thus resulting in
the exception if default evaluation type (NODESET) is used. This flag will allow you to manage the

View File

@@ -12,7 +12,7 @@
<int-xml:xpath-expression expression="/name"/>
</int-xml:xpath-router>
<int-xml:xpath-router id="xpathRouterAsString" input-channel="xpathStringChannel" evaluate-as-node="false">
<int-xml:xpath-router id="xpathRouterAsString" input-channel="xpathStringChannel" evaluate-as-string="true">
<int-xml:xpath-expression expression="name(./node())"/>
</int-xml:xpath-router>

View File

@@ -52,7 +52,7 @@ public class XPathRouterTests {
Document doc = XmlTestUtil.getDocumentForString("<doc type=\"one\" />");
XPathExpression expression = XPathExpressionFactory.createXPathExpression("/doc/@type");
XPathRouter router = new XPathRouter(expression);
router.setEvaluateAsNode(false);
router.setEvaluateAsString(true);
Object[] channelNames = router.getChannelIdentifiers(new GenericMessage(doc)).toArray();
assertEquals("Wrong number of channels returned", 1, channelNames.length);
assertEquals("Wrong channel name", "one", channelNames[0]);
@@ -64,7 +64,7 @@ public class XPathRouterTests {
Document doc = XmlTestUtil.getDocumentForString("<doc><foo>oleg</foo><bar>bang</bar></doc>");
XPathExpression expression = XPathExpressionFactory.createXPathExpression("name(./node())");
XPathRouter router = new XPathRouter(expression);
router.setEvaluateAsNode(false);
router.setEvaluateAsString(true);
Object[] channelNames = router.getChannelIdentifiers(new GenericMessage(doc)).toArray();
assertEquals("Wrong number of channels returned", 1, channelNames.length);
assertEquals("Wrong channel name", "doc", channelNames[0]);
@@ -95,7 +95,7 @@ public class XPathRouterTests {
public void multipleNodeValuesAsString() throws Exception {
XPathExpression expression = XPathExpressionFactory.createXPathExpression("/doc/book");
XPathRouter router = new XPathRouter(expression);
router.setEvaluateAsNode(false);
router.setEvaluateAsString(true);
Object[] channelNames = router.getChannelIdentifiers(new GenericMessage("<doc type=\"one\"><book>bOne</book><book>bTwo</book></doc>")).toArray();
assertEquals("Wrong number of channels returned", 1, channelNames.length);
assertEquals("Wrong channel name", "bOne", channelNames[0]);