diff --git a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/DefaultXmlPayloadConverter.java b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/DefaultXmlPayloadConverter.java new file mode 100644 index 0000000000..ac114f8e76 --- /dev/null +++ b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/DefaultXmlPayloadConverter.java @@ -0,0 +1,74 @@ +/* + * 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; + +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.springframework.integration.message.MessagingException; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; + +/** + * Supports {@link Document} and {@link String} + * @author Jonas Partner + * + */ +public class DefaultXmlPayloadConverter implements XmlPayloadConverter { + + private DocumentBuilderFactory documentBuilderFactory; + + public DefaultXmlPayloadConverter() { + this.documentBuilderFactory = DocumentBuilderFactory.newInstance(); + this.documentBuilderFactory.setNamespaceAware(true); + } + + public DefaultXmlPayloadConverter(DocumentBuilderFactory documentBuilderFactory) { + this.documentBuilderFactory = documentBuilderFactory; + } + + public Document convertToDocument(Object object) { + Document doc; + if (object instanceof Document) { + doc = (Document) object; + } + else if (object instanceof String) { + try { + doc = getDocumentBuilder().parse(new InputSource(new StringReader((String) object))); + } + catch (Exception e) { + throw new MessagingException("Failed to parse String payload " + object, e); + } + } + else { + throw new MessagingException("Unsupported payload type " + object.getClass().getName()); + } + return doc; + } + + protected synchronized DocumentBuilder getDocumentBuilder() { + try { + return this.documentBuilderFactory.newDocumentBuilder(); + } + catch (ParserConfigurationException e) { + throw new MessagingException("Failed to create a new DocumentBuilder", e); + } + } + +} diff --git a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/XmlPayloadConverter.java b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/XmlPayloadConverter.java new file mode 100644 index 0000000000..690fc748da --- /dev/null +++ b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/XmlPayloadConverter.java @@ -0,0 +1,30 @@ +/* + * 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; + +import org.w3c.dom.Document; + + +/** + * Converter for creating XML {@link Document} instances + * @author Jonas Partner + * + */ +public interface XmlPayloadConverter { + + public Document convertToDocument(Object object); + +} diff --git a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/router/XPathMultiChannelNameResolver.java b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/router/XPathMultiChannelNameResolver.java index 30d86bb8da..a1f9cb9356 100644 --- a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/router/XPathMultiChannelNameResolver.java +++ b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/router/XPathMultiChannelNameResolver.java @@ -18,15 +18,15 @@ package org.springframework.integration.xml.router; import java.util.List; -import org.w3c.dom.DOMException; -import org.w3c.dom.Node; - import org.springframework.integration.message.Message; import org.springframework.integration.router.AbstractMultiChannelNameResolver; -import org.springframework.integration.xml.util.XPathUtils; +import org.springframework.integration.xml.DefaultXmlPayloadConverter; +import org.springframework.integration.xml.XmlPayloadConverter; import org.springframework.util.Assert; import org.springframework.xml.xpath.NodeMapper; import org.springframework.xml.xpath.XPathExpression; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; /** * @author Jonas Partner @@ -35,15 +35,15 @@ public class XPathMultiChannelNameResolver extends AbstractMultiChannelNameResol private final XPathExpression xPathExpression; - private volatile NodeMapper nodeMapper = new TextContentNodeMapper(); + private volatile XmlPayloadConverter payloadConvertor = new DefaultXmlPayloadConverter(); + private volatile NodeMapper nodeMapper = new TextContentNodeMapper(); public XPathMultiChannelNameResolver(XPathExpression xPathExpression) { Assert.notNull("XPathExpression must not be null"); this.xPathExpression = xPathExpression; } - public void setNodeMapper(NodeMapper nodeMapper) { Assert.notNull(nodeMapper, "NodeMapper must not be null"); this.nodeMapper = nodeMapper; @@ -51,11 +51,15 @@ public class XPathMultiChannelNameResolver extends AbstractMultiChannelNameResol @SuppressWarnings("unchecked") public String[] resolveChannelNames(Message message) { - Node node = XPathUtils.extractPayloadAsNode(message); + Node node = payloadConvertor.convertToDocument(message.getPayload()); List channelNamesList = this.xPathExpression.evaluate(node, this.nodeMapper); return (String[]) channelNamesList.toArray(new String[channelNamesList.size()]); } + public void setPayloadConvertor(XmlPayloadConverter payloadConvertor) { + this.payloadConvertor = payloadConvertor; + } + private static class TextContentNodeMapper implements NodeMapper { public Object mapNode(Node node, int nodeNum) throws DOMException { diff --git a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/router/XPathSingleChannelNameResolver.java b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/router/XPathSingleChannelNameResolver.java index 39a67ddfc9..0e864e5743 100644 --- a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/router/XPathSingleChannelNameResolver.java +++ b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/router/XPathSingleChannelNameResolver.java @@ -16,13 +16,13 @@ package org.springframework.integration.xml.router; -import org.w3c.dom.Node; - import org.springframework.integration.message.Message; import org.springframework.integration.router.AbstractSingleChannelNameResolver; -import org.springframework.integration.xml.util.XPathUtils; +import org.springframework.integration.xml.DefaultXmlPayloadConverter; +import org.springframework.integration.xml.XmlPayloadConverter; import org.springframework.util.Assert; import org.springframework.xml.xpath.XPathExpression; +import org.w3c.dom.Node; /** * @author Jonas Partner @@ -31,6 +31,7 @@ public class XPathSingleChannelNameResolver extends AbstractSingleChannelNameRes private final XPathExpression xPathExpression; + private volatile XmlPayloadConverter payloadConvertor = new DefaultXmlPayloadConverter(); public XPathSingleChannelNameResolver(XPathExpression xPathExpression) { Assert.notNull("XPathExpression must be provided"); @@ -38,8 +39,12 @@ public class XPathSingleChannelNameResolver extends AbstractSingleChannelNameRes } public String resolveChannelName(Message message) { - Node node = XPathUtils.extractPayloadAsNode(message); + Node node = payloadConvertor.convertToDocument(message.getPayload()); return xPathExpression.evaluateAsString(node); } + public void setPayloadConvertor(XmlPayloadConverter payloadConvertor) { + this.payloadConvertor = payloadConvertor; + } + } diff --git a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/util/XPathUtils.java b/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/util/XPathUtils.java deleted file mode 100644 index 4560f3ee3b..0000000000 --- a/org.springframework.integration.xml/src/main/java/org/springframework/integration/xml/util/XPathUtils.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2002-2008 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.util; - -import org.w3c.dom.Node; - -import org.springframework.integration.message.Message; -import org.springframework.integration.message.MessagingException; - -/** - * @author Jonas Partner - * @author Mark Fisher - */ -public abstract class XPathUtils { - - /** - * Return the given Message's payload as a Node if possible, else an Exception will be thrown. - */ - public static Node extractPayloadAsNode(Message message) { - if (!Node.class.isAssignableFrom(message.getPayload().getClass())) { - throw new MessagingException(message, "payload is not assignable to [" + Node.class.getName() + "] so can not be evaluated"); - } - return (Node) message.getPayload(); - } - -} diff --git a/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/DefaultXmlPayloadConverterTests.java b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/DefaultXmlPayloadConverterTests.java new file mode 100644 index 0000000000..682e4babcb --- /dev/null +++ b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/DefaultXmlPayloadConverterTests.java @@ -0,0 +1,57 @@ +/* + * 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; + +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilderFactory; + +import junit.framework.Assert; + +import org.custommonkey.xmlunit.XMLAssert; +import org.junit.Before; +import org.junit.Test; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; + +public class DefaultXmlPayloadConverterTests { + + DefaultXmlPayloadConverter converter; + + Document testDocument; + + String testDocumentAsString = "hello"; + + @Before + public void setUp() throws Exception{ + converter = new DefaultXmlPayloadConverter(); + testDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse( + new InputSource(new StringReader(testDocumentAsString))); + } + + @Test + public void testWithString() { + Document doc = converter.convertToDocument("hello"); + XMLAssert.assertXMLEqual(testDocument, doc); + } + + @Test + public void testWithDocument() { + Document doc = converter.convertToDocument(testDocument); + Assert.assertTrue(doc == testDocument); + } + +} diff --git a/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/router/XPathMultiChannelNameResolverTests.java b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/router/XPathMultiChannelNameResolverTests.java index 8a738dc09e..9d95e6a3ca 100644 --- a/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/router/XPathMultiChannelNameResolverTests.java +++ b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/router/XPathMultiChannelNameResolverTests.java @@ -19,15 +19,13 @@ package org.springframework.integration.xml.router; import static org.junit.Assert.assertEquals; import org.junit.Test; -import org.w3c.dom.Document; - import org.springframework.integration.message.GenericMessage; import org.springframework.integration.message.MessagingException; import org.springframework.integration.message.StringMessage; -import org.springframework.integration.xml.router.XPathMultiChannelNameResolver; 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 @@ -56,6 +54,17 @@ public class XPathMultiChannelNameResolverTests { assertEquals("Wrong channel name", "bOne", channelNames[0]); assertEquals("Wrong channel name", "bTwo", channelNames[1]); } + + @Test + @SuppressWarnings("unchecked") + public void testMultipleNodeValuesAsString() throws Exception { + XPathExpression expression = XPathExpressionFactory.createXPathExpression("/doc/book"); + XPathMultiChannelNameResolver resolver = new XPathMultiChannelNameResolver(expression); + String[] channelNames = resolver.resolveChannelNames(new GenericMessage("bOnebTwo")); + assertEquals("Wrong number of channels returend", 2, channelNames.length); + assertEquals("Wrong channel name", "bOne", channelNames[0]); + assertEquals("Wrong channel name", "bTwo", channelNames[1]); + } @Test(expected = MessagingException.class) public void testNonNodePayload() throws Exception { diff --git a/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/router/XPathSingleChannelNameResolverTests.java b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/router/XPathSingleChannelNameResolverTests.java index 4a12621d7e..bbb433f787 100644 --- a/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/router/XPathSingleChannelNameResolverTests.java +++ b/org.springframework.integration.xml/src/test/java/org/springframework/integration/xml/router/XPathSingleChannelNameResolverTests.java @@ -36,12 +36,22 @@ public class XPathSingleChannelNameResolverTests { @Test @SuppressWarnings("unchecked") public void testSimpleDocType() throws Exception { - Document doc = XmlTestUtil.getDocumentForString(""); + Document doc = XmlTestUtil.getDocumentForString(""); XPathExpression expression = XPathExpressionFactory.createXPathExpression("/doc/@type"); XPathSingleChannelNameResolver resolver = new XPathSingleChannelNameResolver(expression); String channelName = resolver.resolveChannelName(new GenericMessage(doc)); assertEquals("Wrong channel name", "one", channelName); } + + + @Test + @SuppressWarnings("unchecked") + public void testSimpleStringDoc() throws Exception { + XPathExpression expression = XPathExpressionFactory.createXPathExpression("/doc/@type"); + XPathSingleChannelNameResolver resolver = new XPathSingleChannelNameResolver(expression); + String channelName = resolver.resolveChannelName(new GenericMessage("")); + assertEquals("Wrong channel name", "one", channelName); + } @Test(expected = MessagingException.class) public void testNonNodePayload() throws Exception {