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


The following commit(s) were added to refs/heads/main by this push:
     new b21e782  CAMEL-17400: Enrich route model with source location:line for 
JVM programming language, Java, Kotlin, Groovy etc.
b21e782 is described below

commit b21e7829bbdf5adc6d6563d86c838650cd90f5d2
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Jan 1 11:02:06 2022 +0100

    CAMEL-17400: Enrich route model with source location:line for JVM 
programming language, Java, Kotlin, Groovy etc.
---
 .../java/org/apache/camel/LineNumberAware.java     | 10 +++++++
 .../org/apache/camel/builder/RouteBuilder.java     |  8 +++---
 .../camel/model/OptionalIdentifiedDefinition.java  | 29 +++++++++++++++++++-
 .../apache/camel/model/ProcessorDefinition.java    | 21 +++++++++++++-
 .../camel/model/ProcessorDefinitionHelper.java     | 27 ++++++++++++++++++
 .../org/apache/camel/model/RouteDefinition.java    | 12 +++++++-
 .../org/apache/camel/model/RoutesDefinition.java   |  1 +
 .../camel/main/DefaultConfigurationProperties.java | 10 +++++++
 .../management/mbean/ManagedCamelContext.java      | 11 ++++++--
 .../camel/management/mbean/ManagedProcessor.java   |  7 +++--
 .../camel/management/mbean/ManagedRoute.java       |  2 +-
 .../camel/management/ManagedCamelContextTest.java  | 32 ++++++++++++++++++++--
 12 files changed, 155 insertions(+), 15 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/LineNumberAware.java 
b/core/camel-api/src/main/java/org/apache/camel/LineNumberAware.java
index fa9f299..941b3e5 100644
--- a/core/camel-api/src/main/java/org/apache/camel/LineNumberAware.java
+++ b/core/camel-api/src/main/java/org/apache/camel/LineNumberAware.java
@@ -36,4 +36,14 @@ public interface LineNumberAware {
      */
     void setLineNumber(int lineNumber);
 
+    /**
+     * The location of the entity.
+     */
+    String getLocation();
+
+    /**
+     * Sets the location of the entity (such as classname, XML file name, etc.)
+     */
+    void setLocation(String location);
+
 }
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
index f3ae520..b1a760e 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
@@ -746,18 +746,18 @@ public abstract class RouteBuilder extends BuilderSupport 
implements RoutesBuild
     }
 
     protected void configureRest(RestDefinition rest) {
-        // noop
+        CamelContextAware.trySetCamelContext(rest, getContext());
     }
 
     protected void configureRoute(RouteDefinition route) {
-        // noop
+        CamelContextAware.trySetCamelContext(route, getContext());
     }
 
     protected void configureRouteTemplate(RouteTemplateDefinition 
routeTemplate) {
-        // noop
+        CamelContextAware.trySetCamelContext(routeTemplate, getContext());
     }
 
     protected void configureRouteConfiguration(RouteConfigurationDefinition 
routesConfiguration) {
-        // noop
+        CamelContextAware.trySetCamelContext(routesConfiguration, 
getContext());
     }
 }
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java
index ade87e3..c36cc11 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/OptionalIdentifiedDefinition.java
@@ -23,6 +23,8 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlTransient;
 import javax.xml.bind.annotation.XmlType;
 
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.NamedNode;
 import org.apache.camel.spi.IdAware;
 import org.apache.camel.spi.Metadata;
@@ -34,12 +36,26 @@ import org.apache.camel.spi.NodeIdFactory;
 @XmlType(name = "optionalIdentifiedDefinition")
 @XmlAccessorType(XmlAccessType.PROPERTY)
 // must use XmlAccessType.PROPERTY which is required by camel-spring / 
camel-blueprint for their namespace parsers
-public abstract class OptionalIdentifiedDefinition<T extends 
OptionalIdentifiedDefinition<T>> implements NamedNode, IdAware {
+public abstract class OptionalIdentifiedDefinition<T extends 
OptionalIdentifiedDefinition<T>>
+        implements NamedNode, IdAware, CamelContextAware {
 
+    private CamelContext camelContext;
     private String id;
     private Boolean customId;
     private DescriptionDefinition description;
     private transient int lineNumber = -1;
+    private transient String location;
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    @XmlTransient
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
 
     @Override
     public String getId() {
@@ -93,6 +109,17 @@ public abstract class OptionalIdentifiedDefinition<T 
extends OptionalIdentifiedD
         this.lineNumber = lineNumber;
     }
 
+    @Override
+    public String getLocation() {
+        return location;
+    }
+
+    @Override
+    @XmlTransient
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
     // Fluent API
     // 
-------------------------------------------------------------------------
 
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
index 60d3bfb..1dd3fa8 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
@@ -35,6 +35,8 @@ import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.AggregationStrategy;
 import org.apache.camel.BeanScope;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
@@ -90,7 +92,7 @@ public abstract class ProcessorDefinition<Type extends 
ProcessorDefinition<Type>
     private final int index;
 
     protected ProcessorDefinition() {
-        // every time we create a definition we should inc the COUNTER counter
+        // every time we create a definition we should inc the counter
         index = COUNTER.getAndIncrement();
     }
 
@@ -160,6 +162,23 @@ public abstract class ProcessorDefinition<Type extends 
ProcessorDefinition<Type>
 
     @Override
     public void addOutput(ProcessorDefinition<?> output) {
+        // inject context
+        CamelContextAware.trySetCamelContext(output, getCamelContext());
+
+        RouteDefinition route = ProcessorDefinitionHelper.getRoute(this);
+        if (route != null) {
+            CamelContext context = route.getCamelContext();
+            if (context != null && context.isDebugging()) {
+                // we want to capture source location:line for every output 
when debugging is enabled
+                // this is an expensive operation and therefore only used if 
debugging is enabled
+                ProcessorDefinitionHelper.prepareSourceLocation(output);
+                if (log.isDebugEnabled()) {
+                    log.debug("{} located in {}:{}", output.getShortName(), 
output.getLocation(),
+                            output.getLineNumber());
+                }
+            }
+        }
+
         if (!(this instanceof OutputNode)) {
             getParent().addOutput(output);
             return;
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java
index 3245035..2551451 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java
@@ -370,4 +370,31 @@ public final class ProcessorDefinitionHelper {
         }
     }
 
+    /**
+     * Prepares the output to gather source location:line-number if possible. 
This operation is slow as it uses
+     * StackTrace so this should only be used when Camel Debugger is enabled.
+     *
+     * @param node the node
+     */
+    public static void prepareSourceLocation(NamedNode node) {
+        // line number may already be set if parsed via XML, YAML etc.
+        int number = node.getLineNumber();
+        if (number < 0) {
+            StackTraceElement[] st = Thread.currentThread().getStackTrace();
+            // skip first stack as that is this method
+            for (int i = 1; i < st.length; i++) {
+                StackTraceElement e = st[i];
+                if (!e.getClassName().startsWith("org.apache.camel.model") &&
+                        
!e.getClassName().startsWith("org.apache.camel.builder.RouteBuilder")) {
+                    // when we are no longer in model/RouteBuilder, we have 
found the location:line-number
+                    node.setLineNumber(e.getLineNumber());
+                    if (node.getLocation() == null) {
+                        node.setLocation(e.getClassName());
+                    }
+                    return;
+                }
+            }
+        }
+    }
+
 }
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
index 91c7b66..f318336 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
@@ -729,8 +729,18 @@ public class RouteDefinition extends 
OutputDefinition<RouteDefinition> implement
             throw new IllegalArgumentException("Only one input is allowed per 
route. Cannot accept input: " + input);
         }
         // required = false: in rest-dsl you can embed an in-lined route which
-        // does not have a <from> as its implied to be the rest endpoint
+        // does not have a <from> as it is implied to be the rest endpoint
         this.input = input;
+
+        if (getCamelContext() != null && getCamelContext().isDebugging()) {
+            // we want to capture source location:line for every output when 
debugging is enabled
+            // this is an expensive operation and therefore only used if 
debugging is enabled
+            ProcessorDefinitionHelper.prepareSourceLocation(input);
+            if (log.isDebugEnabled()) {
+                log.debug("{} located in {}:{}", input.getShortName(), 
input.getLocation(),
+                        input.getLineNumber());
+            }
+        }
     }
 
     @Override
diff --git 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
index fce66a6..1ef0a31 100644
--- 
a/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
+++ 
b/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
@@ -364,6 +364,7 @@ public class RoutesDefinition extends 
OptionalIdentifiedDefinition<RoutesDefinit
     // 
-------------------------------------------------------------------------
     protected RouteDefinition createRoute() {
         RouteDefinition route = new RouteDefinition();
+        route.setCamelContext(getCamelContext());
         ErrorHandlerFactory handler = getErrorHandlerFactory();
         if (handler != null) {
             route.setErrorHandlerFactoryIfNull(handler);
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
index 53ed817..0b6e0b2 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
@@ -1978,6 +1978,16 @@ public abstract class DefaultConfigurationProperties<T> {
     }
 
     /**
+     * Sets whether debugging is enabled or not.
+     *
+     * Default is false.
+     */
+    public T withDebugging(boolean debugging) {
+        this.debugging = debugging;
+        return (T) this;
+    }
+
+    /**
      * Sets the pattern used for determine which custom MDC keys to propagate 
during message routing when the routing
      * engine continues routing asynchronously for the given message. Setting 
this pattern to * will propagate all
      * custom keys. Or setting the pattern to foo*,bar* will propagate any 
keys starting with either foo or bar. Notice
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
index 3ec68aa..94fc7b5 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedCamelContext.java
@@ -657,7 +657,11 @@ public class ManagedCamelContext extends 
ManagedPerformanceCounter implements Ti
                 if (rd != null) {
                     String id = rd.getRouteId();
                     int line = rd.getInput().getLineNumber();
-                    String location = route.getSourceLocation() != null ? 
route.getSourceLocation() : "";
+                    String location
+                            = rd.getInput().getLocation() != null ? 
rd.getInput().getLocation() : route.getSourceLocation();
+                    if (location == null) {
+                        location = "";
+                    }
                     sb.append("\n    <routeLocation")
                             .append(String.format(
                                     " routeId=\"%s\" id=\"%s\" index=\"%s\" 
sourceLocation=\"%s\" sourceLineNumber=\"%s\"/>",
@@ -667,7 +671,10 @@ public class ManagedCamelContext extends 
ManagedPerformanceCounter implements Ti
                     // the step must belong to this route
                     if (route.getRouteId().equals(processor.getRouteId())) {
                         int line = processor.getSourceLineNumber() != null ? 
processor.getSourceLineNumber() : -1;
-                        String location = route.getSourceLocation() != null ? 
route.getSourceLocation() : "";
+                        String location = processor.getSourceLocation();
+                        if (location == null) {
+                            location = "";
+                        }
                         sb.append("\n    <routeLocation")
                                 .append(String.format(
                                         " routeId=\"%s\" id=\"%s\" 
index=\"%s\" sourceLocation=\"%s\" sourceLineNumber=\"%s\"/>",
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedProcessor.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedProcessor.java
index 1acfe0d..ba06da2 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedProcessor.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedProcessor.java
@@ -56,9 +56,10 @@ public class ManagedProcessor extends 
ManagedPerformanceCounter implements Manag
             step = 
ProcessorDefinitionHelper.findFirstParentOfType(StepDefinition.class, 
definition, true);
         }
         this.stepId = step != null ? 
step.idOrCreate(context.adapt(ExtendedCamelContext.class).getNodeIdFactory()) : 
null;
-        RouteDefinition rd = ProcessorDefinitionHelper.getRoute(definition);
-        if (rd != null && rd.getResource() != null) {
-            this.sourceLocation = rd.getResource().getLocation();
+        this.sourceLocation = definition.getLocation();
+        if (sourceLocation == null) {
+            RouteDefinition rd = 
ProcessorDefinitionHelper.getRoute(definition);
+            sourceLocation = rd != null ? rd.getLocation() : null;
         }
     }
 
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java
index 7861aa8..8b38164 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java
@@ -571,7 +571,7 @@ public class ManagedRoute extends ManagedPerformanceCounter 
implements TimerList
                 // the step must belong to this route
                 if (route.getRouteId().equals(processor.getRouteId())) {
                     int line = processor.getSourceLineNumber() != null ? 
processor.getSourceLineNumber() : -1;
-                    String location = getSourceLocation() != null ? 
getSourceLocation() : "";
+                    String location = processor.getSourceLocation() != null ? 
processor.getSourceLocation() : "";
                     sb.append("\n    <routeLocation")
                             .append(String.format(
                                     " routeId=\"%s\" id=\"%s\" index=\"%s\" 
sourceLocation=\"%s\" sourceLineNumber=\"%s\"/>",
diff --git 
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedCamelContextTest.java
 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedCamelContextTest.java
index 457d2d0..53be4fd 100644
--- 
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedCamelContextTest.java
+++ 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedCamelContextTest.java
@@ -52,6 +52,8 @@ public class ManagedCamelContextTest extends 
ManagementTestSupport {
         // to force a different management name than the camel id
         context.getManagementNameStrategy().setNamePattern("19-#name#");
         context.setNameStrategy(new 
ExplicitCamelContextNameStrategy("my-camel-context"));
+        // debugger needed for source locations
+        context.setDebugging(true);
         return context;
     }
 
@@ -253,14 +255,40 @@ public class ManagedCamelContextTest extends 
ManagementTestSupport {
         Assertions.assertTrue(names.contains("reverse"));
     }
 
+    @Test
+    public void testSourceLocations() throws Exception {
+        MBeanServer mbeanServer = getMBeanServer();
+        ObjectName on = getContextObjectName();
+
+        String xml = (String) mbeanServer.invoke(on, 
"dumpRoutesSourceLocationsAsXml", null, null);
+        Assertions.assertNotNull(xml);
+        Assertions.assertTrue(xml.contains(
+                
"sourceLocation=\"org.apache.camel.management.ManagedCamelContextTest$1\" 
sourceLineNumber=\"285\"/>"));
+        Assertions.assertTrue(xml.contains(
+                
"sourceLocation=\"org.apache.camel.management.ManagedCamelContextTest$1\" 
sourceLineNumber=\"286\"/>"));
+        Assertions.assertTrue(xml.contains(
+                
"sourceLocation=\"org.apache.camel.management.ManagedCamelContextTest$1\" 
sourceLineNumber=\"287\"/>"));
+
+        Assertions.assertTrue(xml.contains(
+                
"sourceLocation=\"org.apache.camel.management.ManagedCamelContextTest$1\" 
sourceLineNumber=\"289\"/>"));
+        Assertions.assertTrue(xml.contains(
+                
"sourceLocation=\"org.apache.camel.management.ManagedCamelContextTest$1\" 
sourceLineNumber=\"290\"/>"));
+        Assertions.assertTrue(xml.contains(
+                
"sourceLocation=\"org.apache.camel.management.ManagedCamelContextTest$1\" 
sourceLineNumber=\"291\"/>"));
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
             @Override
             public void configure() throws Exception {
-                from("direct:start").delay(10).to("mock:result");
+                from("direct:start")
+                        .delay(10)
+                        .to("mock:result");
 
-                from("direct:foo").delay(10).transform(constant("Bye 
World")).id("myTransform");
+                from("direct:foo")
+                        .delay(10)
+                        .transform(constant("Bye World")).id("myTransform");
             }
         };
     }

Reply via email to