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);
+            }
+        }
+    }
+
 }

Reply via email to