Use ThreadLocal to propagate identity information

On June 10, 2009, in new, by Pieter

Often in our web applications we need to pass the logged in user identity down to business and data layers. This is mostly required when the business processes need to behave differently for different users/roles.

Straight forward mechanism would be to pass user identity as a parameter for every business process method, but can quickly become verbose and painful.

Use of thread local variables presents a viable alternative design to achieve the requirement. The thread locals stores information local to a particular thread. Variables placed by one thread is can be accessed only by the same thread (Each thread can have a separate value for the variable).

Following section of the post looks in to the details of a thread local variable implementation for achieving the user identity propagation in Java. Mainly there are two parts of the implementation, a servlet filter and custom ‘ThreadContext’ class.

We use the servlet filter to attach a user’s identity (and maybe other user context related properties) to the thread:

[java]

public class AuthFilter implements Filter {
 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
      HttpServletRequest httpServletRequest = (HttpServletRequest) request;
      HttpServletResponse httpServletResponse = (HttpServletResponse) response;
      // get the userContext from session/principal,…
      UserContext userContext = …
      if (user == null ) {
          //user is not in the session, not authenticated
          httpServletResponse.sendRedirect("login.jsp");
      } else {
             //Authenticated, lets store the user in the thread context
          ThreadContext.setUserContext(userContext);
          try {
                // call rest of the filters
               chain.doFilter(request, response);
          }finally {
            // remove the thread local variable
            ThreadContext.setUserContext(null);
          }
       }
 }
 public void init(FilterConfig filterConfig) throws ServletException {}
 public void destroy() {}
}
[/java]

In the above code if the user is authenticated then we call “ThreadContext.setUserContext(userContext)” to save the user information to the current thread local store. Once the processing is over (i.e after chain.doFilter()) we remove the userContext from the current thread by calling “ThreadContext.setUserContext(null)”.

Now lets look in to the other part of the implementation, i.e ThreadContext class. Not much of coding is required here.

[java]

public class ThreadContext {
 private static ThreadLocal<UserContext> threadLocalUserContext = new ThreadLocal<UserContext>();

 public static UserContext getUserContext() {
  return threadLocalUserContext.get();
 }

 public static void setUserContext(UserContext userContext) {
  if (userContext == null) {
   threadLocalUserContext.remove();
  }
  threadLocalUserContext.set(userContext);
 }
}
[/java]

You can see the static variable “threadLocalUserContext” is responsible of storing and managing the user identity info for all the threads. Depending on the thread which calls the methods of the above class, appropriate UserContext instances are selected by the “ThreadLocal” class.

Even though the thread local variables are really powerful construct you need to be very careful in using them. If the variables are not cleared at the end of the process (finally block) that memory can be leaked. Also this should not be used as an alternative to parameter passing but should only be used for contextual information propagation.

Finally the code for the UserContext object:

[java]

public class UserContext {
 private String username;
 private Integer servicecode;
 private Integer moduleCode;

 public String getUsername() {
  return username;
 }

 public void setUsername(String username) {
  this.username = username;
 }

 public Integer getServicecode() {
  return servicecode;
 }

 public void setServicecode(Integer servicecode) {
  this.servicecode = servicecode;
 }

 public Integer getModuleCode() {
  return moduleCode;
 }

 public void setModuleCode(Integer moduleCode) {
  this.moduleCode = moduleCode;
 }
}
[/java]

If we need user info in our data access layer (e.g. username, service code, …) it’s very easy to retrieve it using the ThreadContext:

[java]

public class ClientFileDAO {
 public Integer create(ClientFile newInstance) {
  //retrieving user context info is as simple as this:
  UserContext userContext = ThreadContext.getUserContext();
  
  //do some data access stuff, using user info
  …
  …
 }
}
[/java]

This way, the method signatures of our service/dao layers is not polluted with user/context information…

Did you like this? Share it:
 

Leave a Reply