This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch CAMEL-26607-multi-hook in repository https://gitbox.apache.org/repos/asf/camel.git
commit e4ab519cae0f6820c4b9d191e73b5d4ff890616d Author: Claus Ibsen <[email protected]> AuthorDate: Sat Nov 7 17:30:49 2026 +0100 CAMEL-26607: camel-core - getStepHooks and getSendHooks list the installed hooks, as getStepListeners does The getters a step and a send ask stay one hook (the hook itself, or the composite), so the hot path is one null check. The new getters list the hooks in the order they are asked, for tools. The step listener tests of CAMEL-26688 install their hook with addStepHook. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../org/apache/camel/ExtendedCamelContext.java | 22 +++++++++++++++++++ .../impl/engine/DefaultCamelContextExtension.java | 25 ++++++++++++++++++++++ .../apache/camel/processor/MultipleHooksTest.java | 25 ++++++++++++++++++++++ .../apache/camel/processor/StepListenerTest.java | 2 +- .../camel/management/ManagedStepListenerTest.java | 2 +- 5 files changed, 74 insertions(+), 2 deletions(-) diff --git a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java index 05892874356b..c7c3bd577c07 100644 --- a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java +++ b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java @@ -531,6 +531,17 @@ public interface ExtendedCamelContext { return null; } + /** + * Gets the {@link StepHook}s that are installed, in the order they are asked (see {@link #addStepHook(StepHook)}), + * for the tools that list them; a step asks {@link #getStepHook()}. + * + * @return the hooks, empty if none is installed (an unmodifiable snapshot) + * @since 4.24 + */ + default List<StepHook> getStepHooks() { + return Collections.emptyList(); + } + /** * Installs a {@link StepHook} that is asked before every processing step of a route. More than one hook can be * installed: they are asked in their {@link Ordered order} (a hook that does not implement {@link Ordered} has @@ -668,6 +679,17 @@ public interface ExtendedCamelContext { return null; } + /** + * Gets the {@link SendHook}s that are installed, in the order they run (see {@link #addSendHook(SendHook)}), for + * the tools that list them; a send asks {@link #getSendHook()}. + * + * @return the hooks, empty if none is installed (an unmodifiable snapshot) + * @since 4.24 + */ + default List<SendHook> getSendHooks() { + return Collections.emptyList(); + } + /** * Installs a {@link SendHook} that runs around the sends to the producer of an endpoint that fire the * {@link org.apache.camel.spi.CamelEvent.ExchangeSendingEvent}. More than one hook can be installed: they are asked diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java index 776be4df8db4..25fafec3d447 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelContextExtension.java @@ -90,6 +90,7 @@ import org.apache.camel.support.CompositeSendHook; import org.apache.camel.support.CompositeStepHook; import org.apache.camel.support.EndpointHelper; import org.apache.camel.support.NormalizedUri; +import org.apache.camel.support.OrderedComparator; import org.apache.camel.support.PluginHelper; import org.apache.camel.support.service.ServiceHelper; import org.apache.camel.support.startup.DefaultStartupStepRecorder; @@ -133,6 +134,7 @@ class DefaultCamelContextExtension implements ExtendedCamelContext { private volatile SendHook sendHook; // the installed hooks, in the order they were added (guarded by the lock) private final List<SendHook> sendHooks = new ArrayList<>(); + private volatile List<SendHook> sendHooksInOrder = List.of(); private volatile CamelContextNameStrategy nameStrategy; private volatile ManagementNameStrategy managementNameStrategy; private volatile PropertiesComponent propertiesComponent; @@ -150,6 +152,7 @@ class DefaultCamelContextExtension implements ExtendedCamelContext { private volatile StepHook stepHook; // the installed hooks, in the order they were added (guarded by the lock) private final List<StepHook> stepHooks = new ArrayList<>(); + private volatile List<StepHook> stepHooksInOrder = List.of(); private volatile TransformerRegistry transformerRegistry; private volatile ValidatorRegistry validatorRegistry; private volatile TypeConverterRegistry typeConverterRegistry; @@ -543,6 +546,19 @@ class DefaultCamelContextExtension implements ExtendedCamelContext { return stepHook; } + @Override + public List<StepHook> getStepHooks() { + return stepHooksInOrder; + } + + /** The hooks in the order they are asked: by their order, and as they were added for the same order. */ + private static <T> List<T> inOrder(List<T> hooks) { + List<T> answer = new ArrayList<>(hooks); + // a stable sort, as the composite hooks sort + answer.sort(OrderedComparator.get()); + return Collections.unmodifiableList(answer); + } + @Override public void addStepHook(StepHook stepHook) { ObjectHelper.notNull(stepHook, "stepHook"); @@ -551,6 +567,7 @@ class DefaultCamelContextExtension implements ExtendedCamelContext { if (stepHooks.stream().noneMatch(h -> h == stepHook)) { stepHooks.add(stepHook); this.stepHook = CompositeStepHook.of(stepHooks); + this.stepHooksInOrder = inOrder(stepHooks); } } finally { lock.unlock(); @@ -563,6 +580,7 @@ class DefaultCamelContextExtension implements ExtendedCamelContext { try { if (stepHooks.removeIf(h -> h == stepHook)) { this.stepHook = CompositeStepHook.of(stepHooks); + this.stepHooksInOrder = inOrder(stepHooks); } } finally { lock.unlock(); @@ -623,6 +641,11 @@ class DefaultCamelContextExtension implements ExtendedCamelContext { return sendHook; } + @Override + public List<SendHook> getSendHooks() { + return sendHooksInOrder; + } + @Override public void addSendHook(SendHook sendHook) { ObjectHelper.notNull(sendHook, "sendHook"); @@ -631,6 +654,7 @@ class DefaultCamelContextExtension implements ExtendedCamelContext { if (sendHooks.stream().noneMatch(h -> h == sendHook)) { sendHooks.add(sendHook); this.sendHook = CompositeSendHook.of(sendHooks); + this.sendHooksInOrder = inOrder(sendHooks); } } finally { lock.unlock(); @@ -643,6 +667,7 @@ class DefaultCamelContextExtension implements ExtendedCamelContext { try { if (sendHooks.removeIf(h -> h == sendHook)) { this.sendHook = CompositeSendHook.of(sendHooks); + this.sendHooksInOrder = inOrder(sendHooks); } } finally { lock.unlock(); diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/MultipleHooksTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/MultipleHooksTest.java index 999418413b15..e831f38b2650 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/MultipleHooksTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/MultipleHooksTest.java @@ -24,6 +24,7 @@ import org.apache.camel.CamelContext; import org.apache.camel.ContextTestSupport; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; +import org.apache.camel.ExtendedCamelContext; import org.apache.camel.Ordered; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.spi.SendHook; @@ -31,6 +32,10 @@ import org.apache.camel.spi.StepHook; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Two step hooks and two send hooks active together (CAMEL-26607): a hook that fails the first attempt, as chaos does, @@ -89,6 +94,26 @@ class MultipleHooksTest extends ContextTestSupport { recorded); } + @Test + void testTheHooksAreListedInTheirOrder() { + ExtendedCamelContext ecc = context.getCamelContextExtension(); + // added failing first, listed last: as they are asked + assertEquals(List.of(RecordingStepHook.class, FailingStepHook.class), + ecc.getStepHooks().stream().map(Object::getClass).toList()); + assertEquals(List.of(RecordingSendHook.class, FailingSendHook.class), + ecc.getSendHooks().stream().map(Object::getClass).toList()); + assertThrows(UnsupportedOperationException.class, () -> ecc.getStepHooks().clear()); + + StepHook failing = ecc.getStepHooks().get(1); + ecc.removeStepHook(failing); + assertEquals(List.of(RecordingStepHook.class), ecc.getStepHooks().stream().map(Object::getClass).toList()); + // one hook left: the step asks it, not a composite of one + assertSame(ecc.getStepHooks().get(0), ecc.getStepHook()); + ecc.removeStepHook(ecc.getStepHooks().get(0)); + assertTrue(ecc.getStepHooks().isEmpty()); + assertNull(ecc.getStepHook()); + } + private final class RecordingStepHook implements StepHook { @Override diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/StepListenerTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/StepListenerTest.java index a9f089bc1cf0..f1ccd5d1e149 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/StepListenerTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/StepListenerTest.java @@ -78,7 +78,7 @@ class StepListenerTest extends ContextTestSupport { // the failing listener first, so its failures come before the recorder is called context.getCamelContextExtension().addStepListener(failing); context.getCamelContextExtension().addStepListener(recorder); - context.getCamelContextExtension().setStepHook(this::beforeStep); + context.getCamelContextExtension().addStepHook(this::beforeStep); return context; } diff --git a/core/camel-management/src/test/java/org/apache/camel/management/ManagedStepListenerTest.java b/core/camel-management/src/test/java/org/apache/camel/management/ManagedStepListenerTest.java index 1dcbf901c992..b6b14e28bde1 100644 --- a/core/camel-management/src/test/java/org/apache/camel/management/ManagedStepListenerTest.java +++ b/core/camel-management/src/test/java/org/apache/camel/management/ManagedStepListenerTest.java @@ -77,7 +77,7 @@ class ManagedStepListenerTest extends ManagementTestSupport { events.add("callback " + state); } }); - context.getCamelContextExtension().setStepHook(this::beforeStep); + context.getCamelContextExtension().addStepHook(this::beforeStep); return context; }
