Saturday, March 15, 2008

Propagating Identity Information with Thread Local Variables

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.

Another option is to use 'session based singleton' to store the user identity. Once the user is authenticated we use this session based singleton to store the user identity. Business processes can access this session based singleton to obtain the same. Even though this works, the bi-directional dependency introduced (as explained below) limits the usefulness of this approach.

Session based singleton uses the http-session for storing/retrieving information. i.e it has a dependency upon the web ui libraries. The business processes depends on the session based singleton to obtain the user identity. This makes the business processes to be dependent on web ui libraries. As naturally web uis are dependent on the business layer this causes a bi-directional dependency between web ui and the business layer.

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).

Remaining 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.

Servlet filter is responsible of protecting the web application from unauthenticated access. Any request without a user identity (IUser instance) in the session are directed to "login.jsp" which places a user identity in the session after successful authentication. What is important for our discussion is the fact that this filter is also responsible of attaching the user identity to the request thread (see below).
public class AuthFilter implements Filter {

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;

  // get the user from session
IUser user=(IUser)httpServletRequest.getSession().getAttribute(IUser.class.getName());
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.setUser(user);
try {
                // call rest of the filters
chain.doFilter(request, response);
}finally {
                // remove the thread local variable
ThreadContext.setUser(null);
}
}
}

public void init(FilterConfig filterConfig) throws ServletException {}
public void destroy() {}
}

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

Now lets look in to the other part of the implementation, i.e ThreadContext class. Not much of coding is required here.
public class ThreadContext {
private static ThreadLocal threadLocalUser = new ThreadLocal();

public static IUser getUser() {
return threadLocalUser.get();
}
public static void setUser(IUser user) {
if (user == null ) {
threadLocalUser.remove();
}
threadLocalUser.set(user);
}
}
You can see the static variable "threadLocalUser" is responsible of storing and managing the user identity for all the threads. Depending on the thread which calls the methods of the above class, appropriate IUser 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.

One other cool use of this would be to propagate transactions in declarative transaction management frameworks. I'm planning to release an new version of "Easy Data Access Framework" which makes use of thread local variables that completely hide the transaction instances from the developers.

Microsoft .NET framework has built-in support for passing the user identity through the thread. "System.Threading.Thread.CurrentPrincipal" can be used to get or set the user identity to the current thread.

[tag: 99xt ]