Transparently handle NotesThreads for web applications using the Domino Java API

When using a local Session to Domino with the Java API you have to have an initialized NotesThread. This is automatically done for you in Notes but in standalone applications or in web applications you have to manage this yourself. A common solution is to use the static methods of the NotesThread class:

try {
   NotesThread.sinitThread();
   Session session = NotesFactory.createSession();
   System.out.println(session.getUserName());
} catch (NotesException e) {
   e.printStackTrace();
} finally {
   NotesThread.stermThread();
}

This approach isn’t really viable with web applications when using a modular approach since it may not be apparent where the first request to Domino is made (hence where the NotesThread should be initialized) and when the last request has been made (hence the NotesThread should be terminated). Using a servlet filter is an easy transparent way to solve this problem.

Note: Using servlet filters isn’t supported when using Domino as the servlet engine. To play around with servlet filters download the Tomcat (or similar) servlet engine.

For those not familiar with servlet filters it is simply a Java class implementing the javax.servlet.Filter interface and deployed using the web deployment descriptor (web.xml). Once deployed the filter becomes part of a filter chain and for each web request that matches the deployment pattern the filter is called. The filter then has the possibility of performing some tasks before, after or both before handing the request of to the next filter in the chain. This means that each request to the web application is fed through the chain of filters matching the request URL before reaching the core business component which is typically a servlet. A filter could also choose to completely handle a request hence simply avoid forwarding a request down the filter chain (useful for caching of dynamically generated content).

You can think of a servlet filter as a way to externalize functionality common to many requests and having a declarative way to deploy it. A common use for servlet filters is hence for caching or compression.

Performing a task just before and after a request is exactly what we want to achieve. The filter below initializes the NotesThread before the request is forward to the actual business code and terminates the NotesThread after the request.

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import lotus.domino.NotesThread;

/**
 * Servlet filter for making sure NotesThreads are initialized and
 * terminated correctly.
 *
 */
public class NotesThreadFilter implements Filter {

   public void init(FilterConfig config) throws ServletException {
   }

   public void destroy() {
   }


   public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
                                                        throws IOException, ServletException {
      // start thread
      NotesThread.stermThread();

      // do work from other filters
      chain.doFilter(req, res);

      // close thread
      NotesThread.stermThread();
   }

}

To deploy the filter you use the <filter /> and <filter-mapping /> tags of the web.xml. To apply the filter to all requests made in the deployed servlet context you simply specify an asterix (*) as the pattern:

<?xml version="1.0" encoding="iso-8859-1">
   <web-app>
   ...
   ...
   <filter>
      <filter-name>MyFilter</filter-name>
      <filter-class>NotesThreadFilter</filter-class>
   </filter>

   <filter-mapping>
      <filter-name>MyFilter</filter-name>
      <url-pattern>*</url-pattern>
   </filter-mapping>
</web-app>

Of cause you have to be aware that initializing a NotesThread comes at a price so you might want to think twice before simply applying the filter to all requests. You might only want to apply the filter to servlets or controllers you know will access Domino.

I have found that using the servlet filter approch for NotesThreads and the SessionFactory approach I described yesterday makes it much more fun and a lot easier to do Domino Java API development. By using the two approaches it is also easy to decide, maybe even at runtime, whether to use local or remote Sessions.