Markus Jung created OWB-1469:
--------------------------------
Summary: OwbRequestContextController is not threadsafe
Key: OWB-1469
URL: https://issues.apache.org/jira/browse/OWB-1469
Project: OpenWebBeans
Issue Type: Bug
Components: Core
Affects Versions: 4.1.0
Reporter: Markus Jung
{{org.apache.webbeans.context.control.OwbRequestContextController}} keeps its
activation state in a plain instance field:
{code:java}
private boolean enabled;
@Override
public boolean activate()
{
final Context ctx = contextsService.getCurrentContext(RequestScoped.class,
false);
enabled = ctx == null || !ctx.isActive();
if (enabled)
{
contextsService.startContext(RequestScoped.class, null);
}
return enabled;
}
@Override
public void deactivate() throws ContextNotActiveException
{
if (enabled)
{
contextsService.endContext(RequestScoped.class, null);
RequestScopedBeanInterceptorHandler.removeThreadLocals();
enabled = false;
}
}
{code}
The contexts managed by {{ContextsService}} are thread-local, but the
{{enabled}} flag is per controller instance. When one controller instance is
used from more than one thread (e.g. a {{RequestContextController}} injected
into an {{@ApplicationScoped}} bean that submits tasks to an
{{{}ExecutorService{}}}), the following interleaving occurs:
# Thread A: {{activate()}} -> {{{}enabled = true{}}}, context started on A.
# Thread B: {{activate()}} -> writes {{{}enabled = true{}}}.
# Thread A: {{deactivate()}} -> ends A's context, {{{}enabled = false{}}}.
# Thread B: reaches {{if (enabled)}} — the check *re-reads the field* instead
of using the value it just computed — reads {{{}false{}}}, so {{startContext}}
is {*}skipped{*}. {{activate()}} returns {{false}} although no request context
is active on thread B.
Thread B then runs with no request context and the first touch of any
{{@RequestScoped}} normal-scope proxy fails with:
{noformat}
jakarta.enterprise.context.ContextNotActiveException: WebBeans context with
scope type annotation @RequestScoped does not exist within current thread
at
org.apache.webbeans.container.BeanManagerImpl.getContext(BeanManagerImpl.java:345)
at
org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.getContextualInstance(NormalScopedBeanInterceptorHandler.java:89)
at
org.apache.webbeans.intercept.RequestScopedBeanInterceptorHandler.getContextualInstance(RequestScopedBeanInterceptorHandler.java:76)
at
org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.get(NormalScopedBeanInterceptorHandler.java:71)
{noformat}
Same probleme exists the other way around (and is more likely to hit silently),
a thread that activated RequestContext may not reliably end it because
{{enabled}} may have been modified by another thread calling deactivate in the
meantime
--
This message was sent by Atlassian Jira
(v8.20.10#820010)