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.

Lotusphere 2006: Copenhagen Airport has been closed down due to snow

I’m supposed to leave for Lotusphere 2006 tomorrow morning but Copenhagen Airport has been closed due to snow and wind. Hopefully the airport will reopen in the morning – at least for international flights. Not really what I wanted to hear and it doesn’t make it better when Rocky Oliver is leaving on an airplane… ๐Ÿ™‚

Cross your fingers please… Only comfort is that I’m not alone with worries of this sort…

Comment-SPAM getting out of control

I have started getting massive amounts of comment-SPAM so last night I toggled off comments and trackbacks for all existing posts using a combination of regex and Perl. This seems to have stopped the flooding. I’m looking into two more permanent solutions:

  1. Using a hack to Pebble by Glen Smith where the user has to answer a simple math problem before submitting a comment.
  2. Leaving comments open and having a scheduler (such as Quartz) toggle the possibility of comments off after a week or so.

While option 1 is by far the easiest to implement it will mean changing the codebase for Pebble itself. Option number two could be implemented by using a ContextListener which would mean that the existing codebase could be left unaltered (simply an extra jar, a class and a small change to web.xml).

I’m leaning towards option number 2 for now.

Event-generator filling up the logs

I had an incident the other day where the server logs were being filled with log statements from the Event-task after upgrading a server from Domino 5.0.x to Domino 6.5.4FP1. Once the Event-task started the server console, and hence the log, was filled with log statements saying “Event Failed to send mail to .Notes.Administrator.IHI: User %a not listed in Domino Directory”. There would be around 10 lines per second in the log until the task was terminated.

The quick fix was to quit the Event-task until we could figure out what was happening. After some research it turned out to be an Event-handler document where the Notification type field was empty. It should have been set to “Mail” but for some reason it was empty.

After recreating the event-handler document the issue dissapeared and we could start the Event-task again. A simple fix but not the most obvious error message I have seen.

Wierd Domino server port setting in notes.ini

Normally when a TCPIP port is configured at the server the TCPIP line in notes.ini looks like

TCPIP=TCP,0,15,0

but in this case it looks like

TCPIP=TCP,0,15,0,,12288,

I was unable to find information about the port notes.ini setting in the Administration help so I did a search at Lotus Developer Domain (LDD). Here I found the following post on LDD from a guy who apparently knows. There are no reference as to where he got he data he posted:

0x8000 if secured channel
0x4000 driver is internal
0x2000 no-op
0x1000 always for V2 and V3
0x0002 set to log modem I/O
0x0004 set to enable RTS/CTS

In hex 12288 is 0x3000 which could mean that the driver is “no-op” and “always for V2 and V3” whatever that means.

I still wasn’t convinced so I also did a search at lotus.com/support where I found technote 145131. According to that technote the port is in “post Lotus Notes version 1.x format” whatever that means.

Anyways I can’t really see anything wrong in removing the “,,12288,” from the port entry. It still doesn’t explain the Live Console timing out though…

Getting out of the woods

After two weeks of non-stop work I’m eyeing the light at the end of the tunnel a.k.a. getting out of the woods. At the office we are handing a Domino website project over to a customer tomorrow and we are done in time. Great!

The next week is all about clearing out my inbox and getting the first part of my LotusScript.doc article for The VIEW done. It is currently in the layout and final proof reading stage and it’s scheduled for the Jan/Feb issue. Starting of it was supposed to be a single article but it has been split into an article on how to use LotusScript.doc and an article on the inner workings. The next part will be out in the Mar/Apr issue.

Apart from that it’s time to get ready for Lotusphere 2006!
According to the DK Lotusphere QuickPlace members page 64 people will be attending Lotusphere from Denmark. That’s a lot! Apparently a couple of guys I know is also going to attend so that’s great. It’s my first time going so I am reading up on all the newbie FAQ’s out there.

I’m leaving for Orlando on Saturday morning transiting in Washington DC, arriving at 8PM which I guess is a little late to catch in ESPN party which seems to be an event worth attending. I’m going to go anyway I think.

I’m really looking forward to going but I haven’t really had any time to check out the session database yet, but I guess I then will have something to do on the way over there. The goals for the week are:

  • Attend a lot of cool session and learn new stuff
  • Meet a lot of new people
  • Meet some fellow bloggers and put a face to the URL
  • Have a lot of fun
  • Get my picture taken with Mickey Mouse… ๐Ÿ™‚
  • Catch the NFC and AFC championship games live (as I’m writing this Indianapolis Colts has just completed a 2-points conversion and now only trail the Steelers by a field goal)

Does anyone know of a blogger meet-up during the week?

Getting index values with @Formula

I’m doing quite a lot of @Formula coding these days and I’m finding the “new” index capability of @Formula very helpfull. I know it was introduced in release 6 but I’m just starting to use it – old habits die hard.

In that connection I frequently have two arrays of data where I need to find the index of a key value (“Key”) in the first array (“keys”) and get then get the entry at the same index in the other array (“data”). I have found no ArrayGetIndex-like function in @Formula so I’m resorting to a @For-loop to find the correct index and then getting the value from the other array.

keys := @GetProfileField("MyProfile"; "Keys");
data := @GetProfileField("MyProfile"; "Data");
result := "";
@For(n:=1; n<=@Elements(keys); n:=n+1;
   @If(keys[n] = Key;
      @Set("result"; profile_kortlink[n]);
      ""
   )
);
result

Anyone who knows of an easier way?

A patch for the “Windows image-file 0-day exploit” has been released

Ilfak Guilfanov has released a patch for the Windows metafile exploit that was reported last week. Technically the patch works by intercepting the calls to the user32.dll that causes the exploit to work. More information can be found at the beforementioned link.

While the patch isn’t released by Microsoft and since I have no prior knowledge of Ilfak Guilfanov I have chosen to install the patch anyway since it has been vouched for by Steve Gibson (of the Security Now! podcast) who I trust. Steves comments to the patch can be found at his website.

Please note: I had to reregister the DLL (“regsvr32 shimgvw.dll”) that I had previously unregistered to avoid the exploit before installing the patch.