Software IT-Consulting und Coaching

Activate RequestContext within (managed) executor

The specification of JEE defines, that only the ApplicationScope and DependentScope have to be activated within an executed thread (managed or non-managed). Hence, by executing asynchronous processes by ExecutorService.submit(process), an error is thrown because RequestContext is inactive, if RequestScoped beans are injected, used or produced anywhere during invocation.

Now it could be the case, that you have a CDI-producer which produces a RequestScope bean, e.g. as a result of an incoming CDI event. Instead of creating a custom scope, like ThreadScoped or something, it’s more straightforward and much more easier to activate the RequestContext in your executor process.

The drawback here is, that this is a CDI-implementation specific feature, because the RequestContext itself is not part of the standardized CDI-API. In practice, this isn’t really a problem, since the most (all?) containers are working with WELD as CDI implementation.

Since we know the theory now, let the code speak:

import org.jboss.weld.context.bound.BoundRequestContext;

public class Processor {
    @Inject
    private ExecutorService executor;
    @Inject
    private BoundRequestContext requestContext;

    public void doit(Runnable command) {
        Future<?> future = executor.submit(() -> {
          // activate RequestContext for this thread
          requestContext.associate(Maps.newHashMap());
          requestContext.activate();
          try {
              // execute the command
              command.run();
          } finally {
              // destroy context in any case (memory cleanup)
              requestContext.deactivate();
          }
        });
        // analyze future if necessary
    }    
}

BoundRequestContext is a WELD interface. The RequestContext is bound to the executed thread (due use of ThreadLocal). Hence, two concurrently invocations of doit() don’t influence each other. Each thread will get it’s own context-map, since we associate the context with a new HashMap before the real command is triggered.