From 2ff9e11be619f13faa1a516ee5281f1c434937fc Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Mon, 29 Jun 2026 00:53:34 -0300 Subject: [PATCH] Add beginDispatch/endDispatch to VertxContext Expose context dispatch lifecycle methods so that consumers can manage thread-local context without depending on the Vert.x internal API (ContextInternal). This covers split-dispatch use cases like JCA message endpoint delivery where begin and end happen in separate method calls. --- .../smallrye/common/vertx/VertxContext.java | 50 ++++++++++++++++++ .../common/vertx/VertxContextTest.java | 22 ++++++++ .../smallrye/common/vertx/VertxContext.java | 51 +++++++++++++++++++ .../common/vertx/VertxContextTest.java | 22 ++++++++ 4 files changed, 145 insertions(+) diff --git a/vertx4-context/src/main/java/io/smallrye/common/vertx/VertxContext.java b/vertx4-context/src/main/java/io/smallrye/common/vertx/VertxContext.java index 51a35e71..cd5d5577 100644 --- a/vertx4-context/src/main/java/io/smallrye/common/vertx/VertxContext.java +++ b/vertx4-context/src/main/java/io/smallrye/common/vertx/VertxContext.java @@ -277,4 +277,54 @@ public static Context newNestedContext() { return newNestedContext(Vertx.currentContext()); } + /** + * Begins the execution of a task on the given context. + *

+ * This method makes the given context the current thread-local context, so that subsequent calls to + * {@link Vertx#currentContext()} return this context. It returns the previous context (if any), which + * must be passed to {@link #endDispatch(Context, Context)} when the task is complete. + *

+ *

+ * This is a low-level API intended for situations where the begin and end of a dispatch cannot be wrapped + * in a single {@code Runnable} (e.g., JCA message endpoint delivery where {@code beforeDelivery} and + * {@code afterDelivery} are separate calls). Prefer the Vert.x {@code Context#dispatch} methods when possible. + *

+ * + * @param context the context to begin dispatching on, must not be {@code null} + * @return the previous context that was active on this thread, or {@code null} if there was none + * @see #endDispatch(Context, Context) + */ + public static @Nullable Context beginDispatch(Context context) { + ContextInternal actual = Assert.checkNotNullParam("context", (ContextInternal) context); + return actual.beginDispatch(); + } + + /** + * Ends the execution of a task on the given context, restoring the previous context. + *

+ * This method restores the thread-local context to the {@code previous} context that was returned by + * {@link #beginDispatch(Context)}. It must be called in a {@code finally} block to ensure proper cleanup. + *

+ *

+ * Typical usage: + *

+ * + *
+     * Context previous = VertxContext.beginDispatch(myContext);
+     * try {
+     *     // ... perform work on myContext ...
+     * } finally {
+     *     VertxContext.endDispatch(myContext, previous);
+     * }
+     * 
+ * + * @param context the context on which {@link #beginDispatch(Context)} was called, must not be {@code null} + * @param previous the previous context returned by {@link #beginDispatch(Context)}, or {@code null} if there was none + * @see #beginDispatch(Context) + */ + public static void endDispatch(Context context, @Nullable Context previous) { + ContextInternal actual = Assert.checkNotNullParam("context", (ContextInternal) context); + actual.endDispatch((ContextInternal) previous); + } + } diff --git a/vertx4-context/src/test/java/io/smallrye/common/vertx/VertxContextTest.java b/vertx4-context/src/test/java/io/smallrye/common/vertx/VertxContextTest.java index 1daecbbb..423d0861 100644 --- a/vertx4-context/src/test/java/io/smallrye/common/vertx/VertxContextTest.java +++ b/vertx4-context/src/test/java/io/smallrye/common/vertx/VertxContextTest.java @@ -179,6 +179,28 @@ void testDuplicationOfDuplicate(Vertx vertx, VertxTestContext tc) { } + @Test + void testBeginAndEndDispatch(Vertx vertx, VertxTestContext tc) { + var root = vertx.getOrCreateContext(); + root.runOnContext(ignored -> { + var originalContext = Vertx.currentContext(); + assertThat(originalContext).isNotNull(); + + var duplicated = VertxContext.createNewDuplicatedContext(root); + assertThat(duplicated).isNotNull(); + + Context previous = VertxContext.beginDispatch(duplicated); + try { + assertThat(Vertx.currentContext()).isSameAs(duplicated); + assertThat(previous).isSameAs(originalContext); + } finally { + VertxContext.endDispatch(duplicated, previous); + } + assertThat(Vertx.currentContext()).isSameAs(originalContext); + tc.completeNow(); + }); + } + @Test void testDuplicationOfDuplicateUsingVertxAPI(Vertx vertx, VertxTestContext tc) { var root = vertx.getOrCreateContext(); diff --git a/vertx5-context/src/main/java/io/smallrye/common/vertx/VertxContext.java b/vertx5-context/src/main/java/io/smallrye/common/vertx/VertxContext.java index 6d9f8900..84603e69 100644 --- a/vertx5-context/src/main/java/io/smallrye/common/vertx/VertxContext.java +++ b/vertx5-context/src/main/java/io/smallrye/common/vertx/VertxContext.java @@ -311,4 +311,55 @@ public static Context newNestedContext(Context context) { public static Context newNestedContext() { return newNestedContext(Vertx.currentContext()); } + + /** + * Begins the execution of a task on the given context. + *

+ * This method makes the given context the current thread-local context, so that subsequent calls to + * {@link Vertx#currentContext()} return this context. It returns the previous context (if any), which + * must be passed to {@link #endDispatch(Context, Context)} when the task is complete. + *

+ *

+ * This is a low-level API intended for situations where the begin and end of a dispatch cannot be wrapped + * in a single {@code Runnable} (e.g., JCA message endpoint delivery where {@code beforeDelivery} and + * {@code afterDelivery} are separate calls). Prefer the Vert.x {@code Context#dispatch} methods when possible. + *

+ * + * @param context the context to begin dispatching on, must not be {@code null} + * @return the previous context that was active on this thread, or {@code null} if there was none + * @see #endDispatch(Context, Context) + */ + public static @Nullable Context beginDispatch(Context context) { + ContextInternal actual = Assert.checkNotNullParam("context", (ContextInternal) context); + return actual.beginDispatch(); + } + + /** + * Ends the execution of a task on the given context, restoring the previous context. + *

+ * This method restores the thread-local context to the {@code previous} context that was returned by + * {@link #beginDispatch(Context)}. It must be called in a {@code finally} block to ensure proper cleanup. + *

+ *

+ * Typical usage: + *

+ * + *
+     * Context previous = VertxContext.beginDispatch(myContext);
+     * try {
+     *     // ... perform work on myContext ...
+     * } finally {
+     *     VertxContext.endDispatch(myContext, previous);
+     * }
+     * 
+ * + * @param context the context on which {@link #beginDispatch(Context)} was called, must not be {@code null} + * @param previous the previous context returned by {@link #beginDispatch(Context)}, or {@code null} if there was none + * @see #beginDispatch(Context) + */ + public static void endDispatch(Context context, @Nullable Context previous) { + ContextInternal actual = Assert.checkNotNullParam("context", (ContextInternal) context); + actual.endDispatch((ContextInternal) previous); + } + } diff --git a/vertx5-context/src/test/java/io/smallrye/common/vertx/VertxContextTest.java b/vertx5-context/src/test/java/io/smallrye/common/vertx/VertxContextTest.java index 7fa9ea06..dce8dba1 100644 --- a/vertx5-context/src/test/java/io/smallrye/common/vertx/VertxContextTest.java +++ b/vertx5-context/src/test/java/io/smallrye/common/vertx/VertxContextTest.java @@ -179,6 +179,28 @@ void testDuplicationOfDuplicate(Vertx vertx, VertxTestContext tc) { } + @Test + void testBeginAndEndDispatch(Vertx vertx, VertxTestContext tc) { + var root = vertx.getOrCreateContext(); + root.runOnContext(ignored -> { + var originalContext = Vertx.currentContext(); + assertThat(originalContext).isNotNull(); + + var duplicated = VertxContext.createNewDuplicatedContext(root); + assertThat(duplicated).isNotNull(); + + Context previous = VertxContext.beginDispatch(duplicated); + try { + assertThat(Vertx.currentContext()).isSameAs(duplicated); + assertThat(previous).isSameAs(originalContext); + } finally { + VertxContext.endDispatch(duplicated, previous); + } + assertThat(Vertx.currentContext()).isSameAs(originalContext); + tc.completeNow(); + }); + } + @Test void testDuplicationOfDuplicateUsingVertxAPI(Vertx vertx, VertxTestContext tc) { var root = vertx.getOrCreateContext();