This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 47643558e171682103000c43edfc0dda270d26aa Author: Claus Ibsen <[email protected]> AuthorDate: Sat Jan 1 18:03:41 2022 +0100 CAMEL-17403: camel-core - Dump route as xml include source location:line if debugger enabled --- .../util/DumpModelAsXmlSourceLocationTest.java | 73 ++++++++++++++++++++++ .../java/org/apache/camel/util/MyCoolRoute.java | 29 +++++++++ .../java/org/apache/camel/xml/jaxb/JaxbHelper.java | 27 ++++++++ .../camel/xml/jaxb/JaxbModelToXMLDumper.java | 47 ++++++++++++++ 4 files changed, 176 insertions(+) diff --git a/core/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlSourceLocationTest.java b/core/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlSourceLocationTest.java new file mode 100644 index 0000000..cb9cb9f --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/util/DumpModelAsXmlSourceLocationTest.java @@ -0,0 +1,73 @@ +/* + * 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 org.apache.camel.CamelContext; +import org.apache.camel.ContextTestSupport; +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class DumpModelAsXmlSourceLocationTest extends ContextTestSupport { + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + context.setDebugging(true); + return context; + } + + @Test + public void testDumpModelAsXml() throws Exception { + ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class); + String xml = ecc.getModelToXMLDumper().dumpModelAsXml(context, context.getRouteDefinition("myRoute")); + assertNotNull(xml); + log.info(xml); + + Assertions.assertTrue(xml.contains("sourceLineNumber=\"64\" sourceLocation=\"org.apache.camel.util.DumpModelAsXmlSourceLocationTest$1\"")); + } + + @Test + public void testDumpModelAsXmlExternal() throws Exception { + ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class); + String xml = ecc.getModelToXMLDumper().dumpModelAsXml(context, context.getRouteDefinition("cool")); + assertNotNull(xml); + log.info(xml); + + Assertions.assertTrue(xml.contains("<from sourceLineNumber=\"25\" sourceLocation=\"org.apache.camel.util.MyCoolRoute\" uri=\"direct:cool\"/>")); + Assertions.assertTrue(xml.contains("sourceLineNumber=\"26\" sourceLocation=\"org.apache.camel.util.MyCoolRoute\"")); + } + + @Override + protected RouteBuilder[] createRouteBuilders() throws Exception { + return new RouteBuilder[]{ + new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").routeId("myRoute") + .filter(simple("${body} > 10")) + .to("mock:result"); + } + }, + new MyCoolRoute() + }; + } + +} diff --git a/core/camel-core/src/test/java/org/apache/camel/util/MyCoolRoute.java b/core/camel-core/src/test/java/org/apache/camel/util/MyCoolRoute.java new file mode 100644 index 0000000..871f4ae --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/util/MyCoolRoute.java @@ -0,0 +1,29 @@ +/* + * 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 org.apache.camel.builder.RouteBuilder; + +public class MyCoolRoute extends RouteBuilder { + + @Override + public void configure() throws Exception { + from("direct:cool").routeId("cool") + .to("mock:cool") + .wireTap("mock:tap"); + } +} diff --git a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbHelper.java b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbHelper.java index 2adc14f..52dc762 100644 --- a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbHelper.java +++ b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbHelper.java @@ -41,6 +41,7 @@ import org.apache.camel.TypeConversionException; import org.apache.camel.converter.jaxp.XmlConverter; import org.apache.camel.model.ExpressionNode; import org.apache.camel.model.FromDefinition; +import org.apache.camel.model.OptionalIdentifiedDefinition; import org.apache.camel.model.RouteDefinition; import org.apache.camel.model.RouteTemplateDefinition; import org.apache.camel.model.RouteTemplatesDefinition; @@ -51,6 +52,7 @@ import org.apache.camel.model.language.ExpressionDefinition; import org.apache.camel.model.rest.RestDefinition; import org.apache.camel.model.rest.RestsDefinition; import org.apache.camel.spi.NamespaceAware; +import org.apache.camel.util.KeyValueHolder; import static org.apache.camel.model.ProcessorDefinitionHelper.filterTypeInOutputs; @@ -84,6 +86,31 @@ public final class JaxbHelper { } /** + * Extract all source locations from the route + * + * @param route the route + * @param locations the map of source locations for EIPs in the route + */ + public static void extractSourceLocations(RouteDefinition route, Map<String, KeyValueHolder<Integer, String>> locations) { + // input + String id = route.getRouteId(); + String loc = route.getInput().getLocation(); + int line = route.getInput().getLineNumber(); + if (id != null && line != -1) { + locations.put(id, new KeyValueHolder<>(line, loc)); + } + // and then walk all nodes in the route graphs + for (var def : filterTypeInOutputs(route.getOutputs(), OptionalIdentifiedDefinition.class)) { + id = def.getId(); + loc = def.getLocation(); + line = def.getLineNumber(); + if (id != null && line != -1) { + locations.put(id, new KeyValueHolder<>(line, loc)); + } + } + } + + /** * If the route has been built with endpoint-dsl, then the model will not have uri set which then cannot be included * in the JAXB model dump */ diff --git a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java index 21b650d..2e25f3c 100644 --- a/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java +++ b/core/camel-xml-jaxb/src/main/java/org/apache/camel/xml/jaxb/JaxbModelToXMLDumper.java @@ -20,6 +20,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.StringWriter; import java.nio.charset.StandardCharsets; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -49,9 +50,11 @@ import org.apache.camel.model.RoutesDefinition; import org.apache.camel.spi.ModelToXMLDumper; import org.apache.camel.spi.PropertiesComponent; import org.apache.camel.spi.annotations.JdkService; +import org.apache.camel.util.KeyValueHolder; import org.apache.camel.util.xml.XmlLineNumberParser; import static org.apache.camel.xml.jaxb.JaxbHelper.extractNamespaces; +import static org.apache.camel.xml.jaxb.JaxbHelper.extractSourceLocations; import static org.apache.camel.xml.jaxb.JaxbHelper.getJAXBContext; import static org.apache.camel.xml.jaxb.JaxbHelper.modelToXml; import static org.apache.camel.xml.jaxb.JaxbHelper.newXmlConverter; @@ -67,6 +70,7 @@ public class JaxbModelToXMLDumper implements ModelToXMLDumper { public String dumpModelAsXml(CamelContext context, NamedNode definition) throws Exception { final JAXBContext jaxbContext = getJAXBContext(context); final Map<String, String> namespaces = new LinkedHashMap<>(); + final Map<String, KeyValueHolder<Integer, String>> locations = new HashMap<>(); // gather all namespaces from the routes or route which is stored on the // expression nodes @@ -74,21 +78,33 @@ public class JaxbModelToXMLDumper implements ModelToXMLDumper { List<RouteTemplateDefinition> templates = ((RouteTemplatesDefinition) definition).getRouteTemplates(); for (RouteTemplateDefinition route : templates) { extractNamespaces(route.getRoute(), namespaces); + if (context.isDebugging()) { + extractSourceLocations(route.getRoute(), locations); + } resolveEndpointDslUris(route.getRoute()); } } else if (definition instanceof RouteTemplateDefinition) { RouteTemplateDefinition template = (RouteTemplateDefinition) definition; extractNamespaces(template.getRoute(), namespaces); + if (context.isDebugging()) { + extractSourceLocations(template.getRoute(), locations); + } resolveEndpointDslUris(template.getRoute()); } else if (definition instanceof RoutesDefinition) { List<RouteDefinition> routes = ((RoutesDefinition) definition).getRoutes(); for (RouteDefinition route : routes) { extractNamespaces(route, namespaces); + if (context.isDebugging()) { + extractSourceLocations(route, locations); + } resolveEndpointDslUris(route); } } else if (definition instanceof RouteDefinition) { RouteDefinition route = (RouteDefinition) definition; extractNamespaces(route, namespaces); + if (context.isDebugging()) { + extractSourceLocations(route, locations); + } resolveEndpointDslUris(route); } @@ -108,6 +124,9 @@ public class JaxbModelToXMLDumper implements ModelToXMLDumper { } sanitizeXml(dom); + if (context.isDebugging()) { + enrichLocations(dom, locations); + } // Add additional namespaces to the document root element Element documentElement = dom.getDocumentElement(); @@ -224,4 +243,32 @@ public class JaxbModelToXMLDumper implements ModelToXMLDumper { } } + private static void enrichLocations(Node node, Map<String, KeyValueHolder<Integer, String>> locations) { + if (node instanceof Element) { + Element el = (Element) node; + + // from should grab it from parent (route) + String id = el.getAttribute("id"); + if ("from".equals(el.getNodeName())) { + Node parent = el.getParentNode(); + if (parent instanceof Element) { + id = ((Element) parent).getAttribute("id"); + } + } + if (id != null) { + var loc = locations.get(id); + if (loc != null) { + el.setAttribute("sourceLineNumber", loc.getKey().toString()); + el.setAttribute("sourceLocation", loc.getValue()); + } + } + } + if (node.hasChildNodes()) { + for (int i = 0; i < node.getChildNodes().getLength(); i++) { + Node child = node.getChildNodes().item(i); + enrichLocations(child, locations); + } + } + } + }
