adam bien's blog

How To Pass Context In Standard Way - Without ThreadLocal 📎

javax.transaction.TransactionSynchronizationRegistry holds a Map-like structure and can be used to pass state inside a transaction. It works perfectly since the old J2EE 1.4 days and is thread-independent. 

Because an Interceptor is executed in the same transaction as the ServiceFacade, the state can be even set in a @AroundInvoke method. The TransactionSynchronizationRegistry (TSR) can be directly injected into an Interceptor:

public class CurrentTimeMillisProvider {


    @Resource

    private TransactionSynchronizationRegistry registry;


    @AroundInvoke

    public Object injectMap(InvocationContext ic) throws Exception{

        registry.putResource(KEY, System.currentTimeMillis());

        return ic.proceed();

    }

A ServiceFacade don't even has to inject the TSR. The state is automatically propagated to the invoked service:

@Stateless

@WebService

@Interceptors(CurrentTimeMillisProvider.class)

public class ServiceFacadeBean implements ServiceFacade {


    @EJB

    private Service service;


    public void performSomeWork(){

        service.serviceInvocation();

    }

 

}

Everything, what is invoked in the scope of a ServiceFacade - and so its transaction has access to the state stored in the injected TSR:

@Stateless

public class ServiceBean implements Service {

      @Resource

    private TransactionSynchronizationRegistry tsr;


    public void serviceInvocation() {

        long timeMillis =  (Long)tsr.getResource(KEY);

        //...

        System.out.println("Content is " + timeMillis);

    }

TransactionSynchronizationRegistry works (should work) even in case you had assigned different thread pools to EJBs, which participate in the same transaction. The state would get lost with a simple ThreadLocal.

Because we are already in the lightweight Java EE 5 / 6 world - XML and other configuration plumbing are fully optional :-). 

A deployable, working example (ContextHolder) was tested with Glassfish v3 and NetBeans 6.8m2 and pushed into http://kenai.com/projects/javaee-patterns/.  

[See Context Holder pattern, page 247 in "Real World Java EE Patterns Rethinking Best Practices" book for more in-depth discussion]