Most anyone who has done Java server programming has dealt with the Session object, as well as its siblings (and I use that term in essence, not in fact) objects: ServletContext, HttpRequest and HttpResponse. Of course, if you are using a newfangled “Component” framework that tries to “shield” you from the intricacies of HTTP, you may not be familiar with these babies.
GWT is somewhat of a mélange of both Component frameworks and Request/Response frameworks. It is certainly on the component side of the spectrum, in that you are programming mainly in Java objects and using Swing-like constructs and events. But that is mainly on the client side of things. On the server side, GWT is strictly Servlet based, with some excellent marshalling thrown. The marshalling is so good that sometimes can make you forget the HTTP underpinnings. A dead giveaway, other than of course reading the documentation, is that any remote service must be defined in web.xml as a Servlet. I always found this odd, since most newer request /response frameworks(that gladly expose HTTP constructs) tend to use a single “Base” Servlet that you then must extend. Typically, you would create a single Servlet Mapping for this Base Servlet, which would handle essentially all requests. The Base Servlet, based on some xml, annotated, convention based, or a combination of the above, would pass control to a custom Java class which would handle the actual implementation. The Base Servlet and related framework will also provide much of the “plumbing” and other features, such as parameter object mapping, view integration, etc.
With GWT, every remote service you make available to the client must be defined as a distinct Servlet in web.xml (I feel like I’ve already said this, but it is worth repeating). The Servlet class defined is actually the developer’s specific java class, not a base Servlet. This class must extend RemoteServiceServlet, which is a descendent of HttpServlet. This is a key point in the discussion that will follow. Beware of a framework that forces you to extend its own classes (Ok, for the few of you in the know, XX Framework makes you do this as well, but I plead ignorance since I didn’t know better at the time. And I hadn’t seen Spring MVC yet).
Begin a Servlet, our GWT remote service implementation has access to all the HTTP goodies, specifically HttpSession, which I at one time said this post was about. To access the HTTP Session, you use the method
getThreadLocalRequest().getSession()
If this was a HttpServlet Sevice() method, you’d have access to this directly via the HttpServletRequest parameter . But since that method is long gone by the time your code is called, GWT stores this information and makes it available in a ThreadLocal object. ThreadLocal is a construct that lets each JVM thread have its own version of any class level variables. GWT needs ThreadLocal since a Servlet, as in HTTPServlet, needs to serve multiple threads. TheThreadLocal makes data available to all threads that may be accessing that Servlet.
Now remember the following point:
Each Servlet maintains its own ThreadLocal storage
There is nothing unusual with this. How else could multiple threads be served?
The problem arises when you decide to treat your Remote Service Implementation as just another Java class (POJO anyone) and not what it truly is, an HTTPServlet.
So the problem arises when any server side GWT code instantiates a GWT Remote service implementation directly.
Why is this a problem? Well in most cases, it may not be. We won’t include bad architecture in this discussion, which that most certainly is. The problem occurs when you try to access our old friend, getThreadLocalRequest().
The Remote Service Serlvet’s, which our Implemenation must extend, private ThreadLocal storage is initialized when the HTTP Service (POST, GET) happens. The HttpServletRequest, which includes the HttpSession is stored in the Servlet’s Threadlocal storage for access by the current thread.
When that Remote Service Implementation, or any other subsequent code, instantiates another Remote Service Implementation, the new Service’s ThreadLocal is created (it has to be as we are creating a new object) but it is not initialized, since no HTTP Get or Post has occurred. Therefore, any access to getThreadLocalRequest() will throw a NullPointerException, as this information has not yet been stored in ThreadLocalStorage.
I recently hit this problem while working with a client’s code. Doing an internet search and looking at some GWT books didn’t really shed any light on the problem. The only mention was a simple description, useful nonetheless, of the basic method for accessing the HttpSession and related objects. No warning or discussion of what happens when you instantiate a new Remote Service Servlet implementation object.
This is another reason why the SpringSource guys are being proved right time and time again. Please check out Spring MVC for an example of a web framework that can use pure POJO’s for most functionality. These POJO’s can be subsequently instantiated and used, as they have no dependency on the framework.