Repository: camel Updated Branches: refs/heads/camel-2.18.x e7571acc9 -> 20a1b012b refs/heads/master 81137b2af -> 61984d5c4
CAMEL-10509: Handle namespaces on XML dump and load operations Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/61984d5c Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/61984d5c Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/61984d5c Branch: refs/heads/master Commit: 61984d5c492ab35e0502c7799f3046bf3282f0e4 Parents: 6480fc5 Author: James Netherton <jamesnether...@gmail.com> Authored: Fri Nov 25 15:25:22 2016 +0000 Committer: Claus Ibsen <davscl...@apache.org> Committed: Tue Nov 29 20:20:19 2016 +0100 ---------------------------------------------------------------------- .../camel/converter/jaxp/XmlConverter.java | 18 ++ .../apache/camel/impl/DefaultCamelContext.java | 28 +-- .../org/apache/camel/model/ModelHelper.java | 209 ++++++++++++++----- .../org/apache/camel/util/ExchangeHelper.java | 2 +- .../properties/PropertiesRouteFromTest.java | 2 +- .../camel/converter/jaxp/XmlConverterTest.java | 30 ++- .../management/ManagedFromRestGetTest.java | 8 +- .../ManagedFromRestPlaceholderTest.java | 8 +- .../LoadRouteFromXmlWithNamespaceTest.java | 44 ++++ .../camel/util/CreateModelFromXmlTest.java | 123 +++++++++++ .../util/DumpModelAsXmlAggregateRouteTest.java | 2 +- .../camel/util/DumpModelAsXmlNamespaceTest.java | 26 ++- .../util/DumpModelAsXmlPlaceholdersTest.java | 7 +- .../apache/camel/model/routeWithNamespace.xml | 32 +++ .../org/apache/camel/util/simpleRoute.xml | 30 +++ .../camel/util/simpleRouteWithNamespaces.xml | 30 +++ .../spring/DumpModelAsXmlPlaceholdersTest.java | 4 +- 17 files changed, 501 insertions(+), 102 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java b/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java index 70f4f87..539eee6 100644 --- a/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java +++ b/camel-core/src/main/java/org/apache/camel/converter/jaxp/XmlConverter.java @@ -283,6 +283,24 @@ public class XmlConverter { } /** + * Converts the given Document to into text + * @param document The document to convert + * @param outputOptions The {@link OutputKeys} properties to control various aspects of the XML output + * @return The string representation of the document + * @throws TransformerException + */ + public String toStringFromDocument(Document document, Properties outputOptions) throws TransformerException { + if (document == null) { + return null; + } + + DOMSource source = new DOMSource(document); + StringWriter buffer = new StringWriter(); + toResult(source, new StreamResult(buffer), outputOptions); + return buffer.toString(); + } + + /** * Converts the source instance to a {@link DOMSource} or returns null if the conversion is not * supported (making it easy to derive from this class to add new kinds of conversion). * @deprecated will be removed in Camel 3.0. Use the method which has 2 parameters. http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java index 9cd8e83..7739c26 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java @@ -98,6 +98,7 @@ import org.apache.camel.management.ManagementStrategyFactory; import org.apache.camel.model.DataFormatDefinition; import org.apache.camel.model.FromDefinition; import org.apache.camel.model.ModelCamelContext; +import org.apache.camel.model.ModelHelper; import org.apache.camel.model.ProcessorDefinition; import org.apache.camel.model.ProcessorDefinitionHelper; import org.apache.camel.model.RouteDefinition; @@ -882,32 +883,7 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon } public synchronized RoutesDefinition loadRoutesDefinition(InputStream is) throws Exception { - // load routes using JAXB - if (jaxbContext == null) { - // must use classloader from CamelContext to have JAXB working - jaxbContext = getModelJAXBContextFactory().newJAXBContext(); - } - - Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); - Object result = unmarshaller.unmarshal(is); - - if (result == null) { - throw new IOException("Cannot unmarshal to routes using JAXB from input stream: " + is); - } - - // can either be routes or a single route - RoutesDefinition answer; - if (result instanceof RouteDefinition) { - RouteDefinition route = (RouteDefinition) result; - answer = new RoutesDefinition(); - answer.getRoutes().add(route); - } else if (result instanceof RoutesDefinition) { - answer = (RoutesDefinition) result; - } else { - throw new IllegalArgumentException("Unmarshalled object is an unsupported type: " + ObjectHelper.className(result) + " -> " + result); - } - - return answer; + return ModelHelper.loadRoutesDefinition(this, is); } public synchronized RestsDefinition loadRestsDefinition(InputStream is) throws Exception { http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/main/java/org/apache/camel/model/ModelHelper.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/ModelHelper.java b/camel-core/src/main/java/org/apache/camel/model/ModelHelper.java index 3a1aa68..a1d30fd 100644 --- a/camel-core/src/main/java/org/apache/camel/model/ModelHelper.java +++ b/camel-core/src/main/java/org/apache/camel/model/ModelHelper.java @@ -17,23 +17,32 @@ package org.apache.camel.model; import java.io.InputStream; -import java.io.StringReader; import java.io.StringWriter; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Properties; +import javax.xml.bind.Binder; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.TransformerException; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; import org.apache.camel.CamelContext; import org.apache.camel.Expression; import org.apache.camel.NamedNode; +import org.apache.camel.converter.jaxp.XmlConverter; import org.apache.camel.model.language.ExpressionDefinition; import org.apache.camel.spi.NamespaceAware; -import org.apache.camel.util.IOHelper; +import org.apache.camel.spi.TypeConverterRegistry; +import org.apache.camel.util.ObjectHelper; import static org.apache.camel.model.ProcessorDefinitionHelper.filterTypeInOutputs; @@ -55,13 +64,7 @@ public final class ModelHelper { * @throws JAXBException is throw if error marshalling to XML */ public static String dumpModelAsXml(CamelContext context, NamedNode definition) throws JAXBException { - JAXBContext jaxbContext; - if (context == null) { - jaxbContext = createJAXBContext(); - } else { - jaxbContext = context.getModelJAXBContextFactory().newJAXBContext(); - } - + JAXBContext jaxbContext = getJAXBContext(context); final Map<String, String> namespaces = new LinkedHashMap<>(); // gather all namespaces from the routes or route which is stored on the expression nodes @@ -75,14 +78,32 @@ public final class ModelHelper { extractNamespaces(route, namespaces); } - // TODO: add all namespaces to the root node so the xml output includes those - Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); StringWriter buffer = new StringWriter(); marshaller.marshal(definition, buffer); - return buffer.toString(); + Document dom = context.getTypeConverter().convertTo(Document.class, buffer.toString()); + + // Add additional namespaces to the document root element + Element documentElement = dom.getDocumentElement(); + for (String nsPrefix : namespaces.keySet()) { + documentElement.setAttribute("xmlns:" + nsPrefix, namespaces.get(nsPrefix)); + } + + // We invoke the type converter directly because we need to pass some custom XML output options + TypeConverterRegistry registry = context.getTypeConverterRegistry(); + XmlConverter xmlConverter = registry.getInjector().newInstance(XmlConverter.class); + + Properties outputProperties = new Properties(); + outputProperties.put(OutputKeys.INDENT, "yes"); + outputProperties.put(OutputKeys.STANDALONE, "yes"); + try { + return xmlConverter.toStringFromDocument(dom, outputProperties); + } catch (TransformerException e) { + throw new IllegalStateException("Failed converting document object to string", e); + } + } /** @@ -95,28 +116,7 @@ public final class ModelHelper { * @throws javax.xml.bind.JAXBException is thrown if error unmarshalling from xml to model */ public static <T extends NamedNode> T createModelFromXml(CamelContext context, String xml, Class<T> type) throws JAXBException { - // TODO: support injecting namespaces into each namespace aware node - - JAXBContext jaxbContext; - if (context == null) { - jaxbContext = createJAXBContext(); - } else { - jaxbContext = context.getModelJAXBContextFactory().newJAXBContext(); - } - - StringReader reader = new StringReader(xml); - Object result; - try { - Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); - result = unmarshaller.unmarshal(reader); - } finally { - IOHelper.close(reader); - } - - if (result == null) { - throw new JAXBException("Cannot unmarshal to " + type + " using JAXB from XML: " + xml); - } - return type.cast(result); + return modelToXml(context, xml, type); } /** @@ -129,18 +129,109 @@ public final class ModelHelper { * @throws javax.xml.bind.JAXBException is thrown if error unmarshalling from xml to model */ public static <T extends NamedNode> T createModelFromXml(CamelContext context, InputStream stream, Class<T> type) throws JAXBException { - // TODO: support injecting namespaces into each namespace aware node + return modelToXml(context, stream, type); + } + + /** + * Marshal the xml to the model definition + * + * @param context the CamelContext, if <tt>null</tt> then {@link org.apache.camel.spi.ModelJAXBContextFactory} is not in use + * @param inputStream the xml stream + * @throws Exception is thrown if an error is encountered unmarshalling from xml to model + */ + public static RoutesDefinition loadRoutesDefinition(CamelContext context, InputStream inputStream) throws Exception { + JAXBContext jaxbContext = getJAXBContext(context); + + Map<String, String> namespaces = new LinkedHashMap<>(); + Document dom = context.getTypeConverter().mandatoryConvertTo(Document.class, inputStream); + extractNamespaces(dom, namespaces); + + Binder<Node> binder = jaxbContext.createBinder(); + Object result = binder.unmarshal(dom); + + if (result == null) { + throw new JAXBException("Cannot unmarshal to RoutesDefinition using JAXB"); + } + + // can either be routes or a single route + RoutesDefinition answer; + if (result instanceof RouteDefinition) { + RouteDefinition route = (RouteDefinition) result; + answer = new RoutesDefinition(); + applyNamespaces(route, namespaces); + answer.getRoutes().add(route); + } else if (result instanceof RoutesDefinition) { + answer = (RoutesDefinition) result; + for (RouteDefinition route : answer.getRoutes()) { + applyNamespaces(route, namespaces); + } + } else { + throw new IllegalArgumentException("Unmarshalled object is an unsupported type: " + ObjectHelper.className(result) + " -> " + result); + } + return answer; + } + + private static <T extends NamedNode> T modelToXml(CamelContext context, Object object, Class<T> type) throws JAXBException { + JAXBContext jaxbContext = getJAXBContext(context); + + Map<String, String> namespaces = new LinkedHashMap<>(); + Document dom = context.getTypeConverter().convertTo(Document.class, object); + extractNamespaces(dom, namespaces); + + Binder<Node> binder = jaxbContext.createBinder(); + Object result = binder.unmarshal(dom); + + if (result == null) { + throw new JAXBException("Cannot unmarshal to " + type + " using JAXB"); + } + + // Restore namespaces to anything that's NamespaceAware + if (result instanceof RoutesDefinition) { + List<RouteDefinition> routes = ((RoutesDefinition) result).getRoutes(); + for (RouteDefinition route : routes) { + applyNamespaces(route, namespaces); + } + } else if (result instanceof RouteDefinition) { + RouteDefinition route = (RouteDefinition) result; + applyNamespaces(route, namespaces); + } + + return type.cast(result); + } + + private static JAXBContext getJAXBContext(CamelContext context) throws JAXBException { JAXBContext jaxbContext; if (context == null) { jaxbContext = createJAXBContext(); } else { jaxbContext = context.getModelJAXBContextFactory().newJAXBContext(); } + return jaxbContext; + } - Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); - Object result = unmarshaller.unmarshal(stream); - return type.cast(result); + private static void applyNamespaces(RouteDefinition route, Map<String, String> namespaces) { + Iterator<ExpressionNode> it = filterTypeInOutputs(route.getOutputs(), ExpressionNode.class); + while (it.hasNext()) { + NamespaceAware na = getNamespaceAwareFromExpression(it.next()); + if (na != null) { + na.setNamespaces(namespaces); + } + } + } + + private static NamespaceAware getNamespaceAwareFromExpression(ExpressionNode expressionNode) { + ExpressionDefinition ed = expressionNode.getExpression(); + + NamespaceAware na = null; + Expression exp = ed.getExpressionValue(); + if (exp instanceof NamespaceAware) { + na = (NamespaceAware) exp; + } else if (ed instanceof NamespaceAware) { + na = (NamespaceAware) ed; + } + + return na; } private static JAXBContext createJAXBContext() throws JAXBException { @@ -152,22 +243,12 @@ public final class ModelHelper { * Extract all XML namespaces from the expressions in the route * * @param route the route - * @param namespaces the map of namespace to add new found XML namespaces + * @param namespaces the map of namespaces to add discovered XML namespaces into */ private static void extractNamespaces(RouteDefinition route, Map<String, String> namespaces) { Iterator<ExpressionNode> it = filterTypeInOutputs(route.getOutputs(), ExpressionNode.class); while (it.hasNext()) { - ExpressionNode en = it.next(); - ExpressionDefinition ed = en.getExpression(); - - // java-dsl sets directly expression so try this first - NamespaceAware na = null; - Expression exp = ed.getExpressionValue(); - if (exp != null && exp instanceof NamespaceAware) { - na = (NamespaceAware) exp; - } else if (ed instanceof NamespaceAware) { - na = (NamespaceAware) ed; - } + NamespaceAware na = getNamespaceAwareFromExpression(it.next()); if (na != null) { Map<String, String> map = na.getNamespaces(); @@ -177,4 +258,30 @@ public final class ModelHelper { } } } + + /** + * Extract all XML namespaces from the root element in a DOM Document + * + * @param document the DOM document + * @param namespaces the map of namespaces to add new found XML namespaces + */ + private static void extractNamespaces(Document document, Map<String, String> namespaces) throws JAXBException { + NamedNodeMap attributes = document.getDocumentElement().getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + Node item = attributes.item(i); + String nsPrefix = item.getNodeName(); + if (nsPrefix != null && nsPrefix.startsWith("xmlns")) { + String nsValue = item.getNodeValue(); + String[] nsParts = nsPrefix.split(":"); + if (nsParts.length == 1) { + namespaces.put(nsParts[0], nsValue); + } else if (nsParts.length == 2) { + namespaces.put(nsParts[1], nsValue); + } else { + // Fallback on adding the namespace prefix as we find it + namespaces.put(nsPrefix, nsValue); + } + } + } + } } http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/main/java/org/apache/camel/util/ExchangeHelper.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/util/ExchangeHelper.java b/camel-core/src/main/java/org/apache/camel/util/ExchangeHelper.java index eca7f0f..ce3fdca 100644 --- a/camel-core/src/main/java/org/apache/camel/util/ExchangeHelper.java +++ b/camel-core/src/main/java/org/apache/camel/util/ExchangeHelper.java @@ -51,7 +51,7 @@ import org.apache.camel.spi.UnitOfWork; /** * Some helper methods for working with {@link Exchange} objects * - * @version + * @version */ public final class ExchangeHelper { http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesRouteFromTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesRouteFromTest.java b/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesRouteFromTest.java index 10eff3b..fb6296d 100644 --- a/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesRouteFromTest.java +++ b/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesRouteFromTest.java @@ -38,7 +38,7 @@ public class PropertiesRouteFromTest extends ContextTestSupport { // use a routes definition to dump the routes String xml = ModelHelper.dumpModelAsXml(context, context.getRouteDefinition("foo")); assertTrue(xml.contains("<from uri=\"{{cool.start}}\"/>")); - assertTrue(xml.contains("<to uri=\"{{cool.end}}\"")); + assertTrue(xml.contains("<to id=\"to1\" uri=\"{{cool.end}}\"/>")); } @Override http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java b/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java index e35a3db..4618131 100644 --- a/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java +++ b/camel-core/src/test/java/org/apache/camel/converter/jaxp/XmlConverterTest.java @@ -20,6 +20,7 @@ import java.io.File; import java.io.InputStream; import java.io.Reader; import java.nio.ByteBuffer; +import java.util.Properties; import javax.xml.transform.OutputKeys; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; @@ -79,6 +80,33 @@ public class XmlConverterTest extends ContextTestSupport { assertEquals("<foo>bar</foo>", out); } + public void testToStringWithDocument() throws Exception { + XmlConverter conv = new XmlConverter(); + + Document document = conv.createDocument(); + Element foo = document.createElement("foo"); + foo.setTextContent("bar"); + document.appendChild(foo); + + String out = conv.toStringFromDocument(document, null); + assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><foo>bar</foo>", out); + } + + public void testToStringWithDocumentSourceOutputProperties() throws Exception { + XmlConverter conv = new XmlConverter(); + + Document document = conv.createDocument(); + Element foo = document.createElement("foo"); + foo.setTextContent("bar"); + document.appendChild(foo); + + Properties properties = new Properties(); + properties.put(OutputKeys.ENCODING, "ISO-8859-1"); + + String out = conv.toStringFromDocument(document, properties); + assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"no\"?><foo>bar</foo>", out); + } + public void testToSource() throws Exception { XmlConverter conv = new XmlConverter(); @@ -497,7 +525,7 @@ public class XmlConverterTest extends ContextTestSupport { XmlConverter conv = new XmlConverter(); SAXSource source = conv.toSAXSource("<foo>bar</foo>", exchange); - DOMSource out = conv.toDOMSource(source); + DOMSource out = conv.toDOMSource(source, exchange); assertNotSame(source, out); assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><foo>bar</foo>", conv.toString(out, exchange)); http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestGetTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestGetTest.java b/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestGetTest.java index 5aa9ec7..2b69d03 100644 --- a/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestGetTest.java +++ b/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestGetTest.java @@ -62,10 +62,10 @@ public class ManagedFromRestGetTest extends ManagementTestSupport { assertTrue(xml.contains("application/json")); assertTrue(xml.contains("</rests>")); - assertTrue(xml.contains("<param name=\"header_letter\" type=\"query\" description=\"header param description2\"" - + " defaultValue=\"b\" required=\"false\" collectionFormat=\"multi\" dataType=\"string\">")); - assertTrue(xml.contains("<param name=\"header_count\" type=\"header\" description=\"header param description1\" " - + "defaultValue=\"1\" required=\"true\" dataType=\"integer\"")); + assertTrue(xml.contains("<param collectionFormat=\"multi\" dataType=\"string\" defaultValue=\"b\" " + + "description=\"header param description2\" name=\"header_letter\" required=\"false\" type=\"query\">")); + assertTrue(xml.contains("<param dataType=\"integer\" defaultValue=\"1\" " + + "description=\"header param description1\" name=\"header_count\" required=\"true\" type=\"header\">")); assertTrue(xml.contains("<value>1</value>")); assertTrue(xml.contains("<value>a</value>")); http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestPlaceholderTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestPlaceholderTest.java b/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestPlaceholderTest.java index 6eec89b..559943a 100644 --- a/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestPlaceholderTest.java +++ b/camel-core/src/test/java/org/apache/camel/management/ManagedFromRestPlaceholderTest.java @@ -69,10 +69,10 @@ public class ManagedFromRestPlaceholderTest extends ManagementTestSupport { assertTrue(xml.contains("application/json")); assertTrue(xml.contains("</rests>")); - assertTrue(xml.contains("<param name=\"header_letter\" type=\"query\" description=\"header param description2\"" - + " defaultValue=\"b\" required=\"false\" collectionFormat=\"multi\" dataType=\"string\">")); - assertTrue(xml.contains("<param name=\"header_count\" type=\"header\" description=\"header param description1\" " - + "defaultValue=\"1\" required=\"true\" dataType=\"integer\">")); + assertTrue(xml.contains("<param collectionFormat=\"multi\" dataType=\"string\" defaultValue=\"b\" description=\"header param description2\" " + + "name=\"header_letter\" required=\"false\" type=\"query\">")); + assertTrue(xml.contains("<param dataType=\"integer\" defaultValue=\"1\" description=\"header param description1\" " + + "name=\"header_count\" required=\"true\" type=\"header\">")); assertTrue(xml.contains("<value>1</value>")); assertTrue(xml.contains("<value>a</value>")); http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/java/org/apache/camel/model/LoadRouteFromXmlWithNamespaceTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/model/LoadRouteFromXmlWithNamespaceTest.java b/camel-core/src/test/java/org/apache/camel/model/LoadRouteFromXmlWithNamespaceTest.java new file mode 100644 index 0000000..aae0265 --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/model/LoadRouteFromXmlWithNamespaceTest.java @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.model; + +import java.io.InputStream; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Route; +import org.apache.camel.component.mock.MockEndpoint; + +public class LoadRouteFromXmlWithNamespaceTest extends ContextTestSupport { + + public void testLoadRouteWithNamespaceFromXml() throws Exception { + InputStream inputStream = getClass().getResourceAsStream("routeWithNamespace.xml"); + RoutesDefinition routes = context.loadRoutesDefinition(inputStream); + context.addRouteDefinitions(routes.getRoutes()); + context.start(); + + Route routeWithNamespace = context.getRoute("routeWithNamespace"); + assertNotNull("Expected to find route with id: routeWithNamespace", routeWithNamespace); + + MockEndpoint bar = context.getEndpoint("mock:bar", MockEndpoint.class); + bar.expectedBodiesReceived("Hello from foo"); + + // Make sure loaded route can process a XML payload with namespaces attached + context.createProducerTemplate().sendBody("direct:foo", "<?xml version='1.0'?><foo xmlns='http://foo'><bar>cheese</bar></foo>"); + + bar.assertIsSatisfied(); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/java/org/apache/camel/util/CreateModelFromXmlTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/util/CreateModelFromXmlTest.java b/camel-core/src/test/java/org/apache/camel/util/CreateModelFromXmlTest.java new file mode 100644 index 0000000..29bcf9b --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/util/CreateModelFromXmlTest.java @@ -0,0 +1,123 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.util; + +import java.io.InputStream; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Expression; +import org.apache.camel.model.ExpressionNode; +import org.apache.camel.model.ModelHelper; +import org.apache.camel.model.RouteDefinition; +import org.apache.camel.model.RoutesDefinition; +import org.apache.camel.model.language.ExpressionDefinition; +import org.apache.camel.spi.NamespaceAware; +import org.junit.Test; + +import static org.apache.camel.model.ProcessorDefinitionHelper.filterTypeInOutputs; + +public class CreateModelFromXmlTest extends ContextTestSupport { + + public static final String NS_CAMEL = "http://camel.apache.org/schema/spring"; + public static final String NS_FOO = "http://foo"; + public static final String NS_BAR = "http://bar"; + + @Test + public void testCreateModelFromXmlForInputStreamWithDefaultNamespace() throws Exception { + RoutesDefinition routesDefinition = createModelFromXml("simpleRoute.xml", false); + assertNotNull(routesDefinition); + + Map<String, String> expectedNamespaces = new LinkedHashMap<>(); + expectedNamespaces.put("xmlns", NS_CAMEL); + + assertNamespacesPresent(routesDefinition, expectedNamespaces); + } + + @Test + public void testCreateModelFromXmlForInputStreamWithAdditionalNamespaces() throws Exception { + RoutesDefinition routesDefinition = createModelFromXml("simpleRouteWithNamespaces.xml", false); + assertNotNull(routesDefinition); + + Map<String, String> expectedNamespaces = new LinkedHashMap<>(); + expectedNamespaces.put("xmlns", NS_CAMEL); + expectedNamespaces.put("foo", NS_FOO); + expectedNamespaces.put("bar", NS_BAR); + + assertNamespacesPresent(routesDefinition, expectedNamespaces); + } + + @Test + public void testCreateModelFromXmlForStringWithDefaultNamespace() throws Exception { + RoutesDefinition routesDefinition = createModelFromXml("simpleRoute.xml", true); + assertNotNull(routesDefinition); + + Map<String, String> expectedNamespaces = new LinkedHashMap<>(); + expectedNamespaces.put("xmlns", NS_CAMEL); + + assertNamespacesPresent(routesDefinition, expectedNamespaces); + } + + @Test + public void testCreateModelFromXmlForStringWithAdditionalNamespaces() throws Exception { + RoutesDefinition routesDefinition = createModelFromXml("simpleRouteWithNamespaces.xml", true); + assertNotNull(routesDefinition); + + Map<String, String> expectedNamespaces = new LinkedHashMap<>(); + expectedNamespaces.put("xmlns", NS_CAMEL); + expectedNamespaces.put("foo", NS_FOO); + expectedNamespaces.put("bar", NS_BAR); + + assertNamespacesPresent(routesDefinition, expectedNamespaces); + } + + private RoutesDefinition createModelFromXml(String camelContextResource, boolean fromString) throws Exception { + InputStream inputStream = getClass().getResourceAsStream(camelContextResource); + + if (fromString) { + String xml = context.getTypeConverter().convertTo(String.class, inputStream); + return ModelHelper.createModelFromXml(context, xml, RoutesDefinition.class); + } + + return ModelHelper.createModelFromXml(context, inputStream, RoutesDefinition.class); + } + + private void assertNamespacesPresent(RoutesDefinition routesDefinition, Map<String, String> expectedNamespaces) { + for (RouteDefinition route : routesDefinition.getRoutes()) { + Iterator<ExpressionNode> it = filterTypeInOutputs(route.getOutputs(), ExpressionNode.class); + if (it.hasNext()) { + ExpressionNode en = it.next(); + ExpressionDefinition ed = en.getExpression(); + + NamespaceAware na = null; + Expression exp = ed.getExpressionValue(); + if (exp != null && exp instanceof NamespaceAware) { + na = (NamespaceAware) exp; + } else if (ed instanceof NamespaceAware) { + na = (NamespaceAware) ed; + } + + assertNotNull(na); + assertEquals(expectedNamespaces, na.getNamespaces()); + } else { + fail("Expected to find at least one ExpressionNode in route"); + } + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlAggregateRouteTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlAggregateRouteTest.java b/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlAggregateRouteTest.java index 3369443..f172942 100644 --- a/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlAggregateRouteTest.java +++ b/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlAggregateRouteTest.java @@ -44,7 +44,7 @@ public class DumpModelAsXmlAggregateRouteTest extends ContextTestSupport { from("direct:start").routeId("myRoute") .to("log:input") .aggregate(header("userId"), new GroupedExchangeAggregationStrategy()).completionSize(3) - .to("mock:aggregate") + .to("mock:aggregate") .end() .to("mock:result"); } http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlNamespaceTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlNamespaceTest.java b/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlNamespaceTest.java index 3216da37..2170609 100644 --- a/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlNamespaceTest.java +++ b/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlNamespaceTest.java @@ -16,19 +16,33 @@ */ package org.apache.camel.util; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import org.apache.camel.ContextTestSupport; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.model.ModelHelper; -/** - * - */ public class DumpModelAsXmlNamespaceTest extends ContextTestSupport { + private static final String URL_FOO = "http://foo.com"; + private static final String URL_BAR = "http://bar.com"; + public void testDumpModelAsXml() throws Exception { String xml = ModelHelper.dumpModelAsXml(context, context.getRouteDefinition("myRoute")); assertNotNull(xml); - log.info(xml); + + Document dom = context.getTypeConverter().convertTo(Document.class, xml); + Element rootNode = dom.getDocumentElement(); + assertNotNull(rootNode); + + String attributeFoo = rootNode.getAttribute("xmlns:foo"); + assertNotNull(attributeFoo); + assertEquals(URL_FOO, attributeFoo); + + String attributeBar = rootNode.getAttribute("xmlns:bar"); + assertNotNull(attributeBar); + assertEquals(URL_BAR, attributeBar); } @Override @@ -38,8 +52,8 @@ public class DumpModelAsXmlNamespaceTest extends ContextTestSupport { public void configure() throws Exception { from("direct:start").routeId("myRoute") .choice() - .when(xpath("/foo:customer").namespace("foo", "http://foo.com")).to("mock:foo") - .when(xpath("/bar:customer").namespace("bar", "http://bar.com")).to("mock:bar"); + .when(xpath("/foo:customer").namespace("foo", URL_FOO)).to("mock:foo") + .when(xpath("/bar:customer").namespace("bar", URL_BAR)).to("mock:bar"); } }; } http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlPlaceholdersTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlPlaceholdersTest.java b/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlPlaceholdersTest.java index c0c25d7..91fb906 100644 --- a/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlPlaceholdersTest.java +++ b/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlPlaceholdersTest.java @@ -22,9 +22,6 @@ import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.properties.PropertiesComponent; import org.apache.camel.model.ModelHelper; -/** - * - */ public class DumpModelAsXmlPlaceholdersTest extends ContextTestSupport { public void testDumpModelAsXml() throws Exception { @@ -32,9 +29,9 @@ public class DumpModelAsXmlPlaceholdersTest extends ContextTestSupport { String xml = ModelHelper.dumpModelAsXml(context, context.getRouteDefinition("Gouda")); assertNotNull(xml); log.info(xml); - assertTrue(xml.contains("<route customId=\"true\" id=\"Gouda\" xmlns=\"http://camel.apache.org/schema/spring\">")); + assertTrue(xml.contains("<route xmlns=\"http://camel.apache.org/schema/spring\" customId=\"true\" id=\"Gouda\">")); assertTrue(xml.contains("<from uri=\"direct:start-{{cheese.type}}\"/>")); - assertTrue(xml.contains("<to uri=\"direct:end-{{cheese.type}}\" customId=\"true\" id=\"log\"/>")); + assertTrue(xml.contains("<to customId=\"true\" id=\"log\" uri=\"direct:end-{{cheese.type}}\"/>")); } @Override http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/resources/org/apache/camel/model/routeWithNamespace.xml ---------------------------------------------------------------------- diff --git a/camel-core/src/test/resources/org/apache/camel/model/routeWithNamespace.xml b/camel-core/src/test/resources/org/apache/camel/model/routeWithNamespace.xml new file mode 100644 index 0000000..a58b66d --- /dev/null +++ b/camel-core/src/test/resources/org/apache/camel/model/routeWithNamespace.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. +--> +<routes xmlns="http://camel.apache.org/schema/spring" xmlns:foo="http://foo"> + <route id="routeWithNamespace"> + <from uri="direct:foo" /> + <choice> + <when> + <xpath>/foo:foo/foo:bar = 'cheese'</xpath> + <setBody> + <constant>Hello from foo</constant> + </setBody> + <to uri="mock:bar"/> + </when> + </choice> + <to uri="log:end"/> + </route> +</routes> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/resources/org/apache/camel/util/simpleRoute.xml ---------------------------------------------------------------------- diff --git a/camel-core/src/test/resources/org/apache/camel/util/simpleRoute.xml b/camel-core/src/test/resources/org/apache/camel/util/simpleRoute.xml new file mode 100644 index 0000000..49f5077 --- /dev/null +++ b/camel-core/src/test/resources/org/apache/camel/util/simpleRoute.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. +--> +<!-- START SNIPPET: e1 --> +<routes xmlns="http://camel.apache.org/schema/spring"> + <route id="foo"> + <from uri="direct:start"/> + <choice> + <when> + <xpath>/a/foo = 'bar'</xpath> + <to uri="mock:bar"/> + </when> + </choice> + </route> +</routes> +<!-- END SNIPPET: e1 --> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/camel-core/src/test/resources/org/apache/camel/util/simpleRouteWithNamespaces.xml ---------------------------------------------------------------------- diff --git a/camel-core/src/test/resources/org/apache/camel/util/simpleRouteWithNamespaces.xml b/camel-core/src/test/resources/org/apache/camel/util/simpleRouteWithNamespaces.xml new file mode 100644 index 0000000..9a29480 --- /dev/null +++ b/camel-core/src/test/resources/org/apache/camel/util/simpleRouteWithNamespaces.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. +--> +<!-- START SNIPPET: e1 --> +<routes xmlns="http://camel.apache.org/schema/spring" xmlns:foo="http://foo" xmlns:bar="http://bar"> + <route id="foo"> + <from uri="direct:start"/> + <choice> + <when> + <xpath>/a/foo = 'bar'</xpath> + <to uri="mock:bar"/> + </when> + </choice> + </route> +</routes> +<!-- END SNIPPET: e1 --> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/61984d5c/components/camel-spring/src/test/java/org/apache/camel/spring/DumpModelAsXmlPlaceholdersTest.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/test/java/org/apache/camel/spring/DumpModelAsXmlPlaceholdersTest.java b/components/camel-spring/src/test/java/org/apache/camel/spring/DumpModelAsXmlPlaceholdersTest.java index 4f533c1..5bf0585 100644 --- a/components/camel-spring/src/test/java/org/apache/camel/spring/DumpModelAsXmlPlaceholdersTest.java +++ b/components/camel-spring/src/test/java/org/apache/camel/spring/DumpModelAsXmlPlaceholdersTest.java @@ -36,9 +36,9 @@ public class DumpModelAsXmlPlaceholdersTest extends SpringTestSupport { assertNotNull(xml); log.info(xml); - assertTrue(xml.contains("<route customId=\"true\" id=\"Gouda\" xmlns=\"http://camel.apache.org/schema/spring\">")); + assertTrue(xml.contains("<route xmlns=\"http://camel.apache.org/schema/spring\" customId=\"true\" id=\"Gouda\">")); assertTrue(xml.contains("<from uri=\"direct:start-{{cheese.type}}\"/>")); - assertTrue(xml.contains("<to uri=\"direct:end-{{cheese.type}}\" customId=\"true\" id=\"log\"/>")); + assertTrue(xml.contains("<to customId=\"true\" id=\"log\" uri=\"direct:end-{{cheese.type}}\"/>")); } }