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();