Use ThreadLocal to ease Notes Java development

When working with the Lotus Domino Java API special care has to be made not to use objects created in one (lotus.domino.)Session in another Session. When the application isn’t multi-threaded, such as normal Java agents running under Domino, this isn’t an issue but when writing servlets this can become an issue.

A much used approach is to initialize the Session in the doGet() or doPost() of the servlet and then pass the session around with you. While this approach works you’ll have to “polute” all your interfaces with a Session argument which is really bad in my opinion. When doing Domino development this Session should simply “be there” since it is the foundation you build on and hence you shouldn’t have to pass it around.

There are a number of solutions you could use to work around this. One solution is to have a Singleton that keeps track of which Session each user should use i.e. by using a HashMap and use the active username as the key to the Map mapping usernames to Sessions. While this works the approach can have issues if the same username can make multiple requests at the same it e.g. more users using the same username. Another solution would be to have the first object needing the Session create it and store it in the users javax.servlet.http.HttpSession. This is also bad since you have to pass around a pointer to the HttpSession or HttpServletRequest instead of the Session (hence you might as well pass the Session around). Using this approach there might also be issues with serialization of HttpSessions in clustered environments environments where the HttpSession is actually a facade to a database. I think Websphere use the latter approach to handle node failover.

Since I’m writing this I must have found a better approach right? Well… Yes…

java.lang.ThreadLocal is an object you can use where the JVM makes sure each thread has its own copy. Using ThreadLocal in combination with the Factory design pattern the Session becomes ubiquitous. Instead of passing the Session around you simply ask for your Session and that’s it. If it hasn’t been created yet it is initialized before it being handed of to you. Slick.

Below is an example of how such a SessionFactory using a ThreadLocal could look.

import lotus.domino.Session;

/**
 * Class for providing access to Domino sessions. The class doesn't handle
 * NotesThreads.
 *
 */
public class SessionFactory {
   // declarations
   private static final ThreadLocal pSession = new ThreadLocal();

   /**
    * Method for returning a session to Domino. The returned session
    * can be either local or remote.
    *
    * @return Session to Domino.
    */
   public static Session getSession() throws Exception {
      // declarations
      Session session = null;

      // look for a session in the thread local
      session = (Session)pSession.get();
      if (null != session) {
         // lotus.domino.Session found in ThreadLocal - returning it;
         }
         return session;
      }

      try {
         // get session from NotesFactory
         ...
         ...

      } catch (Exception e) {
         // log the error
         throw new Exception("Unable to get session for some reason", e);

         // rethrow
         throw e;
      }
   }

}

To use the SessionFactory to get the Session you simply use a snippet like this:

Session session = SessionFactory.getSession();

I left out the code that actually goes out and creates a remote CORBA Session object using the NotesFactory if it doesn’t exist. I use an approach where I hold the information that varies (server hostname, username and password) in a properties file that I consult before going ahead and creating the Session. This allows me to reuse the class easily.

I hope this approach will ease your multi-threaded Domino Java API development.

Note: I explicitly mentioned that I’m doing a remote CORBA session since they don’t require handling NotesThreads. I’ll post later about an easy solution when using local Sessions and how you could handle those nasty threads transparantly…

Note: Make sure to recycle() the Session once the thread is done using it. The simplest way is to use a servlet filter approach.

Update on 01/Feb/06: Corrected the syntax of the web.xml file and added information on how to handle recycle() the Session using a servlet filter.

4 thoughts on “Use ThreadLocal to ease Notes Java development”

  1. I have a java servlet using DIIOP to run queries against domino db’s, the servlet sometimes crashes with “object has been removed or recycled”. There are typically 15 sessions running together. Could one session be recycling objects from another, the object typically ‘disappears’ between lines of (ie not a coding problem, must be external influence ). I do not use localThread, is this my solution? Can I implement without using serlet filter , as I have no experience of Tomcat

    Like

  2. Without seeing the code it’s hard to say exactly what is happening, but if you do not use ThreadLocal objects and simply store the Domino session in a global class variable (e.g. in your servlet) you could very well run into trouble with one thread using the session from another thread. This could very well cause the kinds of problems you are seeing.

    I would definately recommend using an approach where you combine the use of ThreadLocal and a servlet filter as described here on my blog since it makes the threading (almost) transparent to the programmer.

    The problem with not using a servlet filter is that you have to make sure you manually recycle the session once your request has been processed. If the way through the code is simple this shouldn’t be too much of a problem but with complex code it’s sometimes difficult to make sure the session is correctly terminated in all situations.

    What does your servlet look like? Is it a simple doGet() method or is it complex? Do you pass the session around between methods or store it in a global variable?

    If you like you could send me the servlet code in an e-mail and I’ll take a quick look at it.

    Like

  3. Could you explain a little about your current project (web agents/servlets, EJBs, standalone program)? You do know you only use NotesThreads when using direct API access to Notes /Domino and that you don’t use them when using Corba access right?

    One approach I can give you right of the bat is using a servlet filter if you are using an external servlet container such as Tomcat. Filters are great for exactly this kind of processing. I’ve blogged about handling NotesThreads using filters previously. There are ways of achieving filter-like behaviour using the Domino servlet container as well so let me know.

    Like

Comments are closed.