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
