You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@openwebbeans.apache.org by "Markus Jung (Jira)" <ji...@apache.org> on 2026/07/21 09:27:00 UTC
[jira] [Created] (OWB-1469) OwbRequestContextController is not threadsafe
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)