From d03bb7ae5a71f3ee8e625df462a119d0932c4d87 Mon Sep 17 00:00:00 2001 From: Jonas Partner Date: Mon, 29 Sep 2008 16:07:44 +0000 Subject: [PATCH] OPEN - issue INT-309: XPath Message Selector Added XPAth MessageSelector namespace to follow --- .../AbstractXPathMessageSelector.java | 94 +++++++++++++++ .../BooleanTestXPathMessageSelector.java | 80 +++++++++++++ .../StringValueTestXPathMessageSelector.java | 108 ++++++++++++++++++ .../BooleanTestXpathMessageSelectorTests.java | 66 +++++++++++ ...ingValueTestXPathMessageSelectorTests.java | 66 +++++++++++ .../integration/xml/util/XmlTestUtil.java | 9 +- 6 files changed, 420 insertions(+), 3 deletions(-) create mode 100644 org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/AbstractXPathMessageSelector.java create mode 100644 org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/BooleanTestXPathMessageSelector.java create mode 100644 org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/StringValueTestXPathMessageSelector.java create mode 100644 org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/selector/BooleanTestXpathMessageSelectorTests.java create mode 100644 org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/selector/StringValueTestXPathMessageSelectorTests.java diff --git a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/AbstractXPathMessageSelector.java b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/AbstractXPathMessageSelector.java new file mode 100644 index 0000000000..511cf801c7 --- /dev/null +++ b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/AbstractXPathMessageSelector.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.integration.xml.selector; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.integration.message.selector.MessageSelector; +import org.springframework.integration.xml.DefaultXmlPayloadConverter; +import org.springframework.integration.xml.XmlPayloadConverter; +import org.springframework.xml.xpath.XPathExpression; +import org.springframework.xml.xpath.XPathExpressionFactory; + +/** + * Base class for XPath {@link MessageSelector} implementations + * @author Jonas Partner + * + */ +public abstract class AbstractXPathMessageSelector implements MessageSelector { + + private final XPathExpression xPathExpresion; + + private XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); + + /** + * + * @param xPathExpression simple String expression + */ + public AbstractXPathMessageSelector(String xPathExpression){ + this.xPathExpresion = XPathExpressionFactory.createXPathExpression(xPathExpression); + } + + /** + * + * @param xPathExpression + * @param prefix + * @param namespace + */ + public AbstractXPathMessageSelector(String xPathExpression, String prefix, String namespace){ + Map namespaces = new HashMap(); + namespaces.put(prefix, namespace); + this.xPathExpresion = XPathExpressionFactory.createXPathExpression(xPathExpression,namespaces); + } + + /** + * + * @param xPathExpression + * @param namespaces + */ + public AbstractXPathMessageSelector(String xPathExpression, Map namespaces){ + this.xPathExpresion = XPathExpressionFactory.createXPathExpression(xPathExpression,namespaces); + } + + /** + * + * @param xPathExpression + */ + public AbstractXPathMessageSelector(XPathExpression xPathExpression){ + this.xPathExpresion = xPathExpression; + } + + + protected XmlPayloadConverter getConverter() { + return converter; + } + + /** + * Converter used to convert payloads prior to XPAth testing + * @param converter + */ + public void setConverter(XmlPayloadConverter converter) { + this.converter = converter; + } + + protected XPathExpression getXPathExpresion() { + return xPathExpresion; + } + + + +} diff --git a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/BooleanTestXPathMessageSelector.java b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/BooleanTestXPathMessageSelector.java new file mode 100644 index 0000000000..d6f970aa7d --- /dev/null +++ b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/BooleanTestXPathMessageSelector.java @@ -0,0 +1,80 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.integration.xml.selector; + +import java.util.Map; + +import org.springframework.integration.message.Message; +import org.springframework.integration.message.selector.MessageSelector; +import org.springframework.xml.xpath.XPathExpression; +import org.w3c.dom.Document; + +/** + * Boolean XPath testing {@link MessageSelector}. Requires an XPathExpression + * which can be evaluated using {@link XPathExpression} evaluateAsBoolean. + * Supports payloads of type {@link Document} or {@link String} + * @author Jonas Partner + * + */ +public class BooleanTestXPathMessageSelector extends AbstractXPathMessageSelector { + + /** + * Create a boolean testing XPath {@link MessageSelector} supporting + * mutliple namespaces + * @param pathExpression + * @param namespaces + */ + public BooleanTestXPathMessageSelector(String pathExpression, Map namespaces) { + super(pathExpression, namespaces); + } + + /** + * Create a boolean testing XPath {@link MessageSelector} supporting a + * single namespace + * @param pathExpression + * @param prefix + * @param namespace + */ + public BooleanTestXPathMessageSelector(String pathExpression, String prefix, String namespace) { + super(pathExpression, prefix, namespace); + } + + /** + * Creates a boolean testing XPath {@link MessageSelector} with no namespace + * support + * @param pathExpression + */ + public BooleanTestXPathMessageSelector(String pathExpression) { + super(pathExpression); + } + + /** + * Creates a boolean testing XPath {@link MessageSelector} using the + * provided {@link XPathExpression} + * @param pathExpression + */ + public BooleanTestXPathMessageSelector(XPathExpression pathExpression) { + super(pathExpression); + } + + /** + * return true if the {@link XPathExpression} evaluates to true + */ + public boolean accept(Message message) { + Document doc = getConverter().convertToDocument(message.getPayload()); + return getXPathExpresion().evaluateAsBoolean(doc); + } +} diff --git a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/StringValueTestXPathMessageSelector.java b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/StringValueTestXPathMessageSelector.java new file mode 100644 index 0000000000..85e4bd4237 --- /dev/null +++ b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/selector/StringValueTestXPathMessageSelector.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.integration.xml.selector; + +import java.util.Map; + +import org.springframework.integration.message.Message; +import org.springframework.integration.message.selector.MessageSelector; +import org.springframework.xml.xpath.XPathExpression; +import org.w3c.dom.Document; + +/** + * XPath {@link MessageSelector} which tests for a provided value Supports + * payloads of type {@link Document} or {@link String} + * @author Jonas Partner + * + */ +public class StringValueTestXPathMessageSelector extends AbstractXPathMessageSelector { + + private final String valueToTestFor; + + private volatile boolean caseSensitive = true; + + /** + * Create a selector which tests for the given value and supports multiple + * namespaces + * @param pathExpression + * @param namespaces + * @param valueToTestFor + */ + public StringValueTestXPathMessageSelector(String pathExpression, Map namespaces, + String valueToTestFor) { + super(pathExpression, namespaces); + this.valueToTestFor = valueToTestFor; + } + + /** + * Creates a single namespace Xpath selector + * @param pathExpression + * @param prefix + * @param namespace + * @param valueToTestFor + */ + public StringValueTestXPathMessageSelector(String pathExpression, String prefix, String namespace, + String valueToTestFor) { + super(pathExpression, prefix, namespace); + this.valueToTestFor = valueToTestFor; + } + + /** + * Creates non namespaced testing selector + * @param pathExpression + * @param valueToTestFor + */ + public StringValueTestXPathMessageSelector(String pathExpression, String valueToTestFor) { + + super(pathExpression); + this.valueToTestFor = valueToTestFor; + } + + /** + * Creates selector with provided {@link XPathExpression} + * @param pathExpression + * @param valueToTestFor + */ + public StringValueTestXPathMessageSelector(XPathExpression pathExpression, String valueToTestFor) { + super(pathExpression); + this.valueToTestFor = valueToTestFor; + } + + /** + * Evaluate the payload returning true if the value returned by the + * {@link XPathExpression} is equal to the valueToTestFor + */ + public boolean accept(Message message) { + if (caseSensitive) { + return valueToTestFor.equals(getXPathExpresion().evaluateAsString( + getConverter().convertToDocument(message.getPayload()))); + } + else { + return valueToTestFor.equalsIgnoreCase(getXPathExpresion().evaluateAsString( + getConverter().convertToDocument(message.getPayload()))); + } + } + + /** + * should comparison of value returned by {@link XPathExpression} to test + * value be case sensitive + * @param caseSensitive + */ + public void setCaseSensitive(boolean caseSensitive) { + this.caseSensitive = caseSensitive; + } + +} diff --git a/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/selector/BooleanTestXpathMessageSelectorTests.java b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/selector/BooleanTestXpathMessageSelectorTests.java new file mode 100644 index 0000000000..98d44d57b7 --- /dev/null +++ b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/selector/BooleanTestXpathMessageSelectorTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.integration.xml.selector; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.springframework.integration.message.GenericMessage; +import org.springframework.integration.message.StringMessage; +import org.springframework.integration.xml.util.XmlTestUtil; +import org.springframework.xml.xpath.XPathExpression; +import org.springframework.xml.xpath.XPathExpressionFactory; +import org.w3c.dom.Document; + +/** + * + * @author Jonas Partner + * + */ +public class BooleanTestXpathMessageSelectorTests { + + @Test + public void testWithSimpleString(){ + BooleanTestXPathMessageSelector selector = new BooleanTestXPathMessageSelector("boolean(/one/two)"); + assertTrue(selector.accept(new StringMessage("")) ) ; + assertFalse(selector.accept(new StringMessage("")) ) ; + } + + @Test + public void testWithDocument() throws Exception{ + BooleanTestXPathMessageSelector selector = new BooleanTestXPathMessageSelector("boolean(/one/two)"); + assertTrue(selector.accept(new GenericMessage(XmlTestUtil.getDocumentForString(""))) ) ; + assertFalse(selector.accept(new GenericMessage(XmlTestUtil.getDocumentForString(""))) ) ; + } + + @Test + public void testWithNamespace(){ + BooleanTestXPathMessageSelector selector = new BooleanTestXPathMessageSelector("boolean(/ns1:one/ns1:two)","ns1", "www.example.org"); + assertTrue(selector.accept(new StringMessage("")) ) ; + assertFalse(selector.accept(new StringMessage("")) ) ; + } + + @Test + public void testWithXPathExpressionProvided(){ + XPathExpression xpathExpression = XPathExpressionFactory.createXPathExpression("boolean(/one/two)"); + BooleanTestXPathMessageSelector selector = new BooleanTestXPathMessageSelector(xpathExpression); + assertTrue(selector.accept(new StringMessage("")) ) ; + assertFalse(selector.accept(new StringMessage("")) ) ; + } + + +} diff --git a/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/selector/StringValueTestXPathMessageSelectorTests.java b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/selector/StringValueTestXPathMessageSelectorTests.java new file mode 100644 index 0000000000..1ca64feda0 --- /dev/null +++ b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/selector/StringValueTestXPathMessageSelectorTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.integration.xml.selector; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.springframework.integration.message.StringMessage; + +/** + * + * @author Jonas Partner + * + */ +public class StringValueTestXPathMessageSelectorTests { + + @Test + public void testMatchWithSimpleString() { + StringValueTestXPathMessageSelector selector = new StringValueTestXPathMessageSelector("/one/two", + "red"); + assertTrue(selector.accept(new StringMessage("red"))); + } + + @Test + public void testNoMatchWithSimpleString() { + StringValueTestXPathMessageSelector selector = new StringValueTestXPathMessageSelector("/one/two", + "red"); + assertFalse(selector.accept(new StringMessage("yellow"))); + } + + @Test + public void testMatchWithSimpleStringAndNamespace() { + StringValueTestXPathMessageSelector selector = new StringValueTestXPathMessageSelector("/ns1:one/ns1:two","ns1","www.example.org", + "red"); + assertTrue(selector.accept(new StringMessage("red"))); + } + + + @Test + public void testCaseSensitiveByDefault() { + StringValueTestXPathMessageSelector selector = new StringValueTestXPathMessageSelector("/ns1:one/ns1:two","ns1","www.example.org", + "red"); + assertFalse(selector.accept(new StringMessage("RED"))); + } + + @Test + public void testNotCaseSensitive() { + StringValueTestXPathMessageSelector selector = new StringValueTestXPathMessageSelector("/ns1:one/ns1:two","ns1","www.example.org", + "red"); + selector.setCaseSensitive(false); + assertTrue(selector.accept(new StringMessage("RED"))); + } +} diff --git a/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/util/XmlTestUtil.java b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/util/XmlTestUtil.java index b9581cba81..b90cb7c0bd 100644 --- a/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/util/XmlTestUtil.java +++ b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/util/XmlTestUtil.java @@ -18,6 +18,7 @@ package org.springframework.integration.xml.util; import java.io.StringReader; +import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Result; import javax.xml.transform.Source; @@ -25,11 +26,10 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; +import org.springframework.xml.transform.StringResult; import org.w3c.dom.Document; import org.xml.sax.InputSource; -import org.springframework.xml.transform.StringResult; - /** * Utility class for XML related testing * @@ -38,7 +38,10 @@ import org.springframework.xml.transform.StringResult; public class XmlTestUtil { public static Document getDocumentForString(String strDoc) throws Exception { - return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse( + DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance(); + builder.setNamespaceAware(true); + + return builder.newDocumentBuilder().parse( new InputSource(new StringReader(strDoc))); }