rzo1 commented on code in PR #2940:
URL: https://github.com/apache/tomee/pull/2940#discussion_r3981971755
##########
container/openejb-core/src/main/java/org/apache/openejb/core/ThreadContext.java:
##########
@@ -151,13 +152,98 @@ public ThreadContext(final BeanContext beanContext, final
Object primaryKey, fin
this.currentOperation = operation;
}
+ /**
+ * Copy constructor. Must be called on the thread that owns
<code>that</code>, since a
+ * ThreadContext is confined to its thread. Use {@link #capture()} to pass
a context to
+ * another thread.
+ */
public ThreadContext(final ThreadContext that) {
this.beanContext = that.beanContext;
this.primaryKey = that.primaryKey;
- this.data.putAll(that.data);
+ synchronized (that.data) {
+ this.data.putAll(that.data);
+ }
this.oldClassLoader = that.oldClassLoader;
}
+ /**
+ * Returns an immutable copy of the calling thread's context, which may be
passed to other
+ * threads. Must be called on the thread that owns the context.
+ *
+ * @return the capture, or <code>null</code> if no context is entered on
this thread
+ */
+ public static Capture capture() {
+ final ThreadContext current = threadStorage.get();
+ return current == null ? null : new Capture(current);
+ }
+
+ /**
+ * Immutable copy of the state a {@link ThreadContext} propagates: bean
context, primary key and
+ * context data. Per-thread state such as the class loader to restore, the
entered flag and the
+ * current operation is not included.
+ * <p>
+ * A capture may be applied to any number of threads, including
concurrently.
+ * {@link #newThreadContext()} returns a separate mutable {@link
ThreadContext} for each caller,
+ * since {@link ThreadContext#enter(ThreadContext)} modifies its argument
and fails if that
+ * context was already entered.
+ */
+ public static final class Capture {
+
+ /**
+ * Context data tied to the invocation a capture is taken from, listed
by class name to avoid
+ * a dependency on the types. It is not propagated:
+ * <ul>
+ * <li><code>InvocationContext</code> is part of the interceptor
chain the calling thread is
+ * still in. It is single use, and {@link
BaseContext#getContextData()} exposes its
+ * unsynchronized map to application code.</li>
+ * <li><code>DestroyContext</code> references the captured context
and would keep it
+ * reachable for the lifetime of the capture. A new one is
created when the context is
+ * entered on another thread.</li>
+ * </ul>
+ */
+ private static final Set<String> NON_PROPAGATED = Set.of(
+ "jakarta.interceptor.InvocationContext",
+
"org.apache.openejb.cdi.RequestScopedThreadContextListener$DestroyContext");
+
+ private final BeanContext beanContext;
+ private final Object primaryKey;
+ private final Map<Class, Object> data;
+
+ private Capture(final ThreadContext that) {
+ this.beanContext = that.beanContext;
+ this.primaryKey = that.primaryKey;
+
+ final Map<Class, Object> copy = new HashMap<>();
+ synchronized (that.data) {
+ for (final Map.Entry<Class, Object> entry :
that.data.entrySet()) {
+ if (!NON_PROPAGATED.contains(entry.getKey().getName())) {
+ copy.put(entry.getKey(), entry.getValue());
+ }
+ }
Review Comment:
Thanks, applied in a728ba18a6.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]