adam bien's blog

How To Pass Context Between Layers With ThreadLocal And EJB 3.(1) 📎

TransactionSynchronizationRegistry is the way to go - you don't have to worry about the existence of multiple thread pools. However it only works inside a transaction. If you need to pass the context from the web layer (before a transaction is initiated), to the EJB container, where the transaction actually starts, you cannot use TransactionSynchronizationRegistry.

Additional data can be easily attached to the current request, using ThreadLocal. You can use again Interceptors / Servlet Filters for that purpose: 

import javax.interceptor.AroundInvoke;

import javax.interceptor.InvocationContext;

import static com.abien.patterns.kitchensink.contextholder.RegistryKey.*;

import static com.abien.patterns.kitchensink.contextholder.threadlocal.ThreadLocalContextHolder.*;

public class CurrentTimeMillisProvider {

    @AroundInvoke

    public Object injectMap(InvocationContext ic) throws Exception{

        put(KEY.name(), System.currentTimeMillis());

        return ic.proceed();

    }

 The ThreadLocalContextHolder is just a utility class with static methods, which can be statically imported:

import java.util.HashMap;

import java.util.Map;

public class ThreadLocalContextHolder {


    private static final ThreadLocal<Map<String,Object>> THREAD_WITH_CONTEXT = new ThreadLocal<Map<String,Object>>();


    private ThreadLocalContextHolder() {}


    public static void put(String key, Object payload) {

        if(THREAD_WITH_CONTEXT.get() == null){

            THREAD_WITH_CONTEXT.set(new HashMap<String, Object>());

        }

        THREAD_WITH_CONTEXT.get().put(key, payload);

    }


    public static Object get(String key) {

        return THREAD_WITH_CONTEXT.get().get(key);

    }


    public static void cleanupThread(){

        THREAD_WITH_CONTEXT.remove();

    }

The interface can be declared on a boundary / service facade:

@Stateless

@WebService

@Interceptors(CurrentTimeMillisProvider.class)

public class ServiceFacadeThreadLocalBean implements ServiceFacadeThreadLocal {

    @EJB

    private ServiceThreadLocal service;

    public void performSomeWork(){

        service.serviceInvocation();

    }

}

 The context will be passed along to the service and can be accessed from every method:

import javax.ejb.Stateless;

import static com.abien.patterns.kitchensink.contextholder.threadlocal.ThreadLocalContextHolder.*;

import static com.abien.patterns.kitchensink.contextholder.RegistryKey.*;

@Stateless

public class ServiceThreadLocalBean implements ServiceThreadLocal{


    public void serviceInvocation() {

        Long millis = (Long) get(KEY.name());

        System.out.println("Content is: " + millis);

    }

}

The ContextHolder pattern is only valuable, in case you have to pass the context in majority of all methods. You could of course extend DTOs with the additional context data, or enhance every method with an additional parameter. 

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.8beta 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]