-
Notifications
You must be signed in to change notification settings - Fork 81
RequestContextController spec impossible to implement #477
Description
I'm not really happy with the RequestContextController. And it appears to me that the spec is broken.
Here is the important part from the spec:
6.5.2. Activating Built In Contexts
Certain built in contexts support the ability to be activated and deactivated. This allows developers to control built-in contexts in ways that they could also manage custom built contexts.
When activating and deactivating built in contexts, it is important to realize that they can only be activated if not already active within a given thread.
6.5.2.1. Activating a Request Context
Request contexts can be managed either programmatically or via interceptor.
To programmatically manage request contexts, the container provides a built in bean that is @dependent scoped and of type RequestContextController that allows you to activate and deactivate a request context on the current thread. The object should be considered stateful, invoking the same instance on different threads may not work properly, non-portable behavior may occur.
public interface RequestContextController {
boolean activate();
void deactivate() throws ContextNotActiveException;
}
When the activate() method is called, if the request context is not already active on the current thread then it will be activated and the method returns true. Otherwise, the method returns false.
When the deactivate() method is called, if this controller started the request context then the request context is stopped. The method does nothing if this controller did not activate the context
The problem is that there are 2 ways to use that part
a.)
boolean didActivate = reqCtxCtrl.activate();
...
if (didActivate) reqCtxCrl.deactivate();
b.)
try {
reqCtxCtrl.activate();
...
} finally {
reqCtxCrl.deactivate();
}
The problematic part is nesting.
In case a) we got maybe 7 calls to activate() but only 1 to deactivate.
In case b) we got 7 calls to activate and 7 to deactivate();
There is simply no way to implement this in a clean way. A simple boolean flag does not help because of concurrency. A ThreadLocal does not help much either. If we use a ThreadLocal we potentially leak memory in case of a). If we close immediately we potentially close way too early in case b).