Fun with the ThreadLocal class in Java..

This is an interesting class, one that is probably a building block to many Java based architecture implementations that perform “state” management.

Recently I came across a scenario where I needed a reference to an HTTPServletRequest object but it was not readily available due to prior architectural decisions. When I say “architectural decisions” I use the term loosely the architecture I was supporting was pretty much a disaster with too many contributing factors to mention but the application has survived for years and is still in use today.

The application is a Flex 1.5 app (yes there are some still out in the Wild) there were pieces of code that required a reference to the HttpServletRequest instance. Often this reference was required from within a Remote Object call so the HttpServletRequest object was not readily available.

The following code sample provided a reference to the existing HttpServletRequest. This app contained code that made back end calls from Flex 1.5 as well as Flex 3 so it handled both instances.

... class named RequestManager
public static HttpServletRequest getHttpRequest() throws Exception
  {
    Class cls;
    try{
      cls = Class.forName("flex.messaging.FlexContext");
    }catch(Exception e){
      cls = Class.forName("flashgateway.Gateway");
    }
     Method meth = cls.getMethod("getHttpRequest", new Class[0]);
     Object retobj = meth.invoke(null);
     if ( retobj == null )
     {
       cls = Class.forName("flashgateway.Gateway");
       meth = cls.getMethod("getHttpRequest", new Class[0]);
       retobj = meth.invoke(null);
     }
     HttpServletRequest req = (HttpServletRequest) retobj;
     return req;
  }

Specifically what this was used for was the management of Session variables. A session Manager class was utilizing the above-mentioned method to get a reference to the existing Servlet Request object. The code in the SessionManager class that utilized this method looked like this.

...
HttpServletRequest req = RequestManager.getHttpRequest();
return req.getSession().getAttribute("MYSessionKey").toString();

This technique worked fine when making Flex Remote Calls but when a Servlet was introduced that needed to utilize the same method calls there was a problem gaining a reference to the HttpServletRequest. Intermediary method calls that existed elsewhere in the code did not contain an argument of HttpServletRequest they utilized the RequestManager to gain this access. This posed a problem when the Servlet wanted to make the method calls that the Remote Object calls relied upon.

So how can the methods called by the Servlet get a reference to the HttpServletRequest?

There where a few possibilities

  • Overload methods to accept an HttpServletRequest, in this case there where too many methods.
  • Create a process that utilized a Static class that synchronized a request to guarantee one got a reference to the correct HttpServletRequest.. Its an option but an ugly one.
  • Utilize the same method Adobe had written to grab a reference to the HttpServletRequest

I was able to reference the source for Adobe’s FlexContext class to see how they did it.

The solution was surprisingly simple.. utilizing the ThreadLocal class.

Here is a quick run down of what i did

1. Define a static class that represents a reference to the HttpServletRequest. This class will be populated by the Servlet.

package dtii.util;
import javax.servlet.http.HttpServletRequest;
public class MyRequest
{
  private static ThreadLocal requests = new ThreadLocal();
  public static void setRequest(HttpServletRequest req) {
     requests.set(req);
  }

  public static HttpServletRequest getRequest() {
    return requests.get();
  }

  public static void removeRequest(){
    requests.remove();
  }
}

2. Edit the RequestManager to look for this class. Feel free to implement in a safer way..

... RequestManager
public static HttpServletRequest getHttpRequest() throws Exception
{
  Class cls;
  try{
    cls = Class.forName("flex.messaging.FlexContext");
  }catch(Exception e){
    cls = Class.forName("flashgateway.Gateway");
  }

  Method meth = cls.getMethod("getHttpRequest", new Class[0]);
  Object retobj = meth.invoke(null);
	if ( retobj == null )
  {
    cls = Class.forName("flashgateway.Gateway");
    meth = cls.getMethod("getHttpRequest", new Class[0]);
    retobj = meth.invoke(null);
  }
  if ( retobj == null )
  {
    retobj = (HttpServletRequest) MyRequest.getRequest();
  }
   HttpServletRequest req = (HttpServletRequest) retobj;
   return req;
}

3. In the Executing Servlet define the Class at the begining and than remove it at the end

import dtii.util.MyRequest;
.. some servlet

public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
	MyRequest.setRequest(req);
	SomeMethod(.. );
	MyRequest.removeRequest();
}

This technique worked well for what i needed.. its not pretty but it worked.

Would love to hear a suggestion on a better method.