This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-23616-stepid-producer-mbean
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 608d1e92b7ac870c9478bdbd100e0dfdb370dce3
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue May 26 12:58:54 2026 +0200

    CAMEL-23616: Add stepId to producer MBeans and dev console
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../java/org/apache/camel/spi/StepIdAware.java}    | 34 ++++++---
 .../camel/impl/console/ProducerDevConsole.java     |  6 ++
 .../org/apache/camel/processor/SendProcessor.java  | 18 ++++-
 .../org/apache/camel/reifier/ProcessorReifier.java | 17 +++++
 .../api/management/mbean/ManagedProducerMBean.java |  3 +
 .../camel/management/mbean/ManagedProducer.java    |  9 +++
 .../management/ManagedProducerStepIdTest.java      | 80 ++++++++++++++++++++++
 .../org/apache/camel/support/DefaultProducer.java  | 14 +++-
 8 files changed, 169 insertions(+), 12 deletions(-)

diff --git 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedProducerMBean.java
 b/core/camel-api/src/main/java/org/apache/camel/spi/StepIdAware.java
similarity index 60%
copy from 
core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedProducerMBean.java
copy to core/camel-api/src/main/java/org/apache/camel/spi/StepIdAware.java
index 11f34f096e48..17ca680fc667 100644
--- 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedProducerMBean.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/StepIdAware.java
@@ -14,19 +14,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.api.management.mbean;
+package org.apache.camel.spi;
 
-import org.apache.camel.api.management.ManagedAttribute;
+import org.jspecify.annotations.Nullable;
 
-public interface ManagedProducerMBean extends ManagedServiceMBean {
-
-    @ManagedAttribute(description = "Endpoint URI", mask = true)
-    String getEndpointUri();
+/**
+ * To allow objects to be injected with the step id
+ * <p/>
+ * This allows access to the step id at runtime, to know which step its 
associated with.
+ *
+ * @since 4.21
+ */
+public interface StepIdAware {
 
-    @ManagedAttribute(description = "Singleton")
-    boolean isSingleton();
+    /**
+     * Gets the step id
+     *
+     * @since 4.21
+     */
+    @Nullable
+    String getStepId();
 
-    @ManagedAttribute(description = "Whether this producer connects to remote 
or local systems")
-    boolean isRemoteEndpoint();
+    /**
+     * Sets the step id
+     *
+     * @param stepId the step id
+     * @since        4.21
+     */
+    void setStepId(String stepId);
 
 }
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/ProducerDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/ProducerDevConsole.java
index fa7f3121ac36..3a7af7fe5f2d 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/ProducerDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/ProducerDevConsole.java
@@ -64,6 +64,9 @@ public class ProducerDevConsole extends AbstractDevConsole {
                         if (mp.getRouteId() != null) {
                             sb.append(String.format("%n    Route Id: %s", 
mp.getRouteId()));
                         }
+                        if (mp.getStepId() != null) {
+                            sb.append(String.format("%n    Step Id: %s", 
mp.getStepId()));
+                        }
                     }
                 }
             } catch (Exception e) {
@@ -101,6 +104,9 @@ public class ProducerDevConsole extends AbstractDevConsole {
                         if (mp.getRouteId() != null) {
                             jo.put("routeId", mp.getRouteId());
                         }
+                        if (mp.getStepId() != null) {
+                            jo.put("stepId", mp.getStepId());
+                        }
                         list.add(jo);
                     }
                 }
diff --git 
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java
 
b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java
index 5433a706a14d..5745d5ec39ff 100644
--- 
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java
+++ 
b/core/camel-core-processor/src/main/java/org/apache/camel/processor/SendProcessor.java
@@ -33,6 +33,7 @@ import org.apache.camel.spi.IdAware;
 import org.apache.camel.spi.InternalProcessorFactory;
 import org.apache.camel.spi.ProducerCache;
 import org.apache.camel.spi.RouteIdAware;
+import org.apache.camel.spi.StepIdAware;
 import org.apache.camel.support.EndpointHelper;
 import org.apache.camel.support.EventHelper;
 import org.apache.camel.support.ExchangeHelper;
@@ -50,7 +51,8 @@ import org.slf4j.LoggerFactory;
  *
  * @see SendDynamicProcessor
  */
-public class SendProcessor extends BaseProcessorSupport implements Traceable, 
EndpointAware, IdAware, RouteIdAware {
+public class SendProcessor extends BaseProcessorSupport
+        implements Traceable, EndpointAware, IdAware, RouteIdAware, 
StepIdAware {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(SendProcessor.class);
 
@@ -66,6 +68,7 @@ public class SendProcessor extends BaseProcessorSupport 
implements Traceable, En
     protected ExchangePattern destinationExchangePattern;
     protected String id;
     protected String routeId;
+    protected String stepId;
     protected boolean extendedStatistics;
     protected final AtomicLong counter = new AtomicLong();
 
@@ -107,6 +110,16 @@ public class SendProcessor extends BaseProcessorSupport 
implements Traceable, En
         this.routeId = routeId;
     }
 
+    @Override
+    public String getStepId() {
+        return stepId;
+    }
+
+    @Override
+    public void setStepId(String stepId) {
+        this.stepId = stepId;
+    }
+
     @Override
     public String getTraceLabel() {
         if (traceLabelToString == null) {
@@ -329,6 +342,9 @@ public class SendProcessor extends BaseProcessorSupport 
implements Traceable, En
             if (this.producer instanceof RouteIdAware ria) {
                 ria.setRouteId(getRouteId());
             }
+            if (this.producer instanceof StepIdAware sia) {
+                sia.setStepId(getStepId());
+            }
             // ensure the producer is managed and started
             camelContext.addService(this.producer, true, true);
         } else {
diff --git 
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
 
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
index 81e1ff166e75..a8a145ffa767 100644
--- 
a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
+++ 
b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java
@@ -124,6 +124,7 @@ import org.apache.camel.spi.InterceptStrategy;
 import org.apache.camel.spi.NodeIdFactory;
 import org.apache.camel.spi.ProcessorFactory;
 import org.apache.camel.spi.RouteIdAware;
+import org.apache.camel.spi.StepIdAware;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.PluginHelper;
 import org.apache.camel.util.ObjectHelper;
@@ -781,6 +782,14 @@ public abstract class ProcessorReifier<T extends 
ProcessorDefinition<?>> extends
             if (processor instanceof RouteIdAware routeIdAware) {
                 routeIdAware.setRouteId(route.getRouteId());
             }
+            if (processor instanceof StepIdAware stepIdAware) {
+                StepDefinition step = 
ProcessorDefinitionHelper.findFirstParentOfType(
+                        StepDefinition.class, output, true);
+                if (step != null) {
+                    stepIdAware.setStepId(step.idOrCreate(
+                            
camelContext.getCamelContextExtension().getContextPlugin(NodeIdFactory.class)));
+                }
+            }
 
             if (output instanceof Channel && processor == null) {
                 continue;
@@ -859,6 +868,14 @@ public abstract class ProcessorReifier<T extends 
ProcessorDefinition<?>> extends
             if (processor instanceof RouteIdAware routeIdAware) {
                 routeIdAware.setRouteId(route.getRouteId());
             }
+            if (processor instanceof StepIdAware stepIdAware) {
+                StepDefinition step = 
ProcessorDefinitionHelper.findFirstParentOfType(
+                        StepDefinition.class, definition, true);
+                if (step != null) {
+                    stepIdAware.setStepId(step.idOrCreate(
+                            
camelContext.getCamelContextExtension().getContextPlugin(NodeIdFactory.class)));
+                }
+            }
 
             if (processor == null) {
                 // no processor to make
diff --git 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedProducerMBean.java
 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedProducerMBean.java
index 11f34f096e48..f39ad924467f 100644
--- 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedProducerMBean.java
+++ 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedProducerMBean.java
@@ -20,6 +20,9 @@ import org.apache.camel.api.management.ManagedAttribute;
 
 public interface ManagedProducerMBean extends ManagedServiceMBean {
 
+    @ManagedAttribute(description = "Step ID")
+    String getStepId();
+
     @ManagedAttribute(description = "Endpoint URI", mask = true)
     String getEndpointUri();
 
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedProducer.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedProducer.java
index 94ce8c0d929d..7256b913b5ef 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedProducer.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedProducer.java
@@ -20,6 +20,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.Producer;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.api.management.mbean.ManagedProducerMBean;
+import org.apache.camel.spi.StepIdAware;
 
 @ManagedResource(description = "Managed Producer")
 public class ManagedProducer extends ManagedService implements 
ManagedProducerMBean {
@@ -34,6 +35,14 @@ public class ManagedProducer extends ManagedService 
implements ManagedProducerMB
         return producer;
     }
 
+    @Override
+    public String getStepId() {
+        if (producer instanceof StepIdAware sia) {
+            return sia.getStepId();
+        }
+        return null;
+    }
+
     @Override
     public String getEndpointUri() {
         return producer.getEndpoint().getEndpointUri();
diff --git 
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedProducerStepIdTest.java
 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedProducerStepIdTest.java
new file mode 100644
index 000000000000..bb583002c01d
--- /dev/null
+++ 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedProducerStepIdTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.management;
+
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DisabledOnOs(OS.AIX)
+public class ManagedProducerStepIdTest extends ManagementTestSupport {
+
+    @Test
+    public void testProducerStepId() throws Exception {
+        getMockEndpoint("mock:foo").expectedMessageCount(1);
+        getMockEndpoint("mock:result").expectedMessageCount(1);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+
+        MBeanServer mbeanServer = getMBeanServer();
+
+        Set<ObjectName> set = mbeanServer.queryNames(new 
ObjectName("*:type=producers,*"), null);
+        assertEquals(3, set.size());
+
+        for (ObjectName on : set) {
+            boolean registered = mbeanServer.isRegistered(on);
+            assertTrue(registered, "Should be registered");
+
+            String uri = (String) mbeanServer.getAttribute(on, "EndpointUri");
+            String stepId = (String) mbeanServer.getAttribute(on, "StepId");
+
+            if ("log://foo".equals(uri) || "mock://foo".equals(uri)) {
+                assertEquals("myStep", stepId, "Producer inside step should 
have stepId");
+            } else if ("mock://result".equals(uri)) {
+                assertNull(stepId, "Producer outside step should not have 
stepId");
+            }
+        }
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start").routeId("route1")
+                        .step("myStep")
+                        .to("log:foo")
+                        .to("mock:foo")
+                        .end()
+                        .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/DefaultProducer.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/DefaultProducer.java
index cefd52139224..844c9d056471 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/DefaultProducer.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/DefaultProducer.java
@@ -19,6 +19,7 @@ package org.apache.camel.support;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.Producer;
+import org.apache.camel.spi.StepIdAware;
 import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.URISupport;
 import org.slf4j.Logger;
@@ -27,12 +28,13 @@ import org.slf4j.LoggerFactory;
 /**
  * A default implementation of {@link Producer} for implementation inheritance.
  */
-public abstract class DefaultProducer extends ServiceSupport implements 
Producer {
+public abstract class DefaultProducer extends ServiceSupport implements 
Producer, StepIdAware {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(DefaultProducer.class);
 
     private transient String producerToString;
     private final Endpoint endpoint;
+    private String stepId;
 
     protected DefaultProducer(Endpoint endpoint) {
         this.endpoint = endpoint;
@@ -63,6 +65,16 @@ public abstract class DefaultProducer extends ServiceSupport 
implements Producer
         return endpoint.isSingleton();
     }
 
+    @Override
+    public String getStepId() {
+        return stepId;
+    }
+
+    @Override
+    public void setStepId(String stepId) {
+        this.stepId = stepId;
+    }
+
     @Override
     protected void doStart() throws Exception {
         // log at debug level for singletons, for prototype scoped log at 
trace level to not spam logs

Reply via email to