Wormholes, FitNesse and the return of SetUp and TearDown links 34

Posted by Brett Schuchert Thu, 16 Apr 2009 18:33:00 GMT

Recently, I was working on adding back a feature to FitNesse that had been removed, links at the bottom of each page to add a setup or teardown page to the current page. After racking my brain and spending time in git with file histories, I had discovered a point in time where the feature was there and the next commit where it was gone. It was not obvious to me what had changed to break the feature until I talked with Bob Martin (much of this has to do with my lack of experience using git). He mentioned a change in the handling of importing header and footer pages (related to my problem) and sure enough, when I took a look in the debugger, I found out that the information I needed to reintroduce the feature had essentially be removed as a result of a bug fix.

This was, apparently, not a heavily used feature. In fact, I had not used it much until I recently started working on tutorials for FitNesse. And given the release criterion for FitNesse, removal of the feature did not break anything (no acceptance tests nor unit tests).

Anyway, the point at which the information was available that I needed and the point where I needed to use the information were may steps away from each other both in the call stack as well as the instance hierarchy (think composite pattern). I did not want to significantly change the method call hierarchy so I instead decided to hand-roll the wormhole pattern as it manifests itself in AspectJ (and not the wormhole anti-pattern).

For background on AspectJ and AOP in general, have a look at these self-study tutorials.

The wormhole pattern is well-documented in AspectJ In Action. It consists of two point cuts that combine two different, separated, parts of the system. It grabs information available at (in this case) the entry point to the system and makes that information available deeper in the system without passing the parameter directly. That’s where the name comes from, the pattern bridges information across to unconnected points via the wormhole. It is my favorite patter name (not favorite pattern, just name).

AspectJ happens to store certain runtime information in thread local storage and the wormhole pattern exploits this fact. Here’s another example that’s close to the wormhole pattern. This is actually a common technique. If you’ve read up on the recommendations on using Hibernate in a JSE environment either in “Hibernate in Action” or the more recent Javer Persistence with Hibernate, one recommendation is to pass around sessions and such in thread local variables. Under the covers, JEE containers do the same thing.

Even though this is a “common” technique, I’m not a huge fan of using thread-locals. 1. They are thread-specific global variables. 1. You better be sure there’s no threading between the two points. In this case, the threading has already happened. Once a FitNesse responder gets a hold of an HTTP request, the remaining processing is in a single thread.

On the other hand, if I did not use thread local storage, the change required to get information I needed would have either require changing one of the objects already in the parameters being passed (very ugly) or changing method signatures all over the place (somewhat less ugly but a stronger violation of LSP). So in this case, I think thread local variables are the least ugly of the available options.

(As a side note, that’s my definition of design: Select the solution that sucks the least.)

If you’re like me, you don’t use thread locals very often. I wanted to make sure that the thread local information would get properly cleaned up and I wanted to hide all of the magic in one place, so I created a simple class called ThreadLocalUtil. I used TDD to create the class and when I though I was done, I wanted to make sure that I had written the clear() method correctly. I knew that for a single thread the clear() method worked as expected, but I wanted to make sure it did not affect other threads.

So my problem was I needed 2 threads and I wanted a particular ordering of events:
  • T1: Store value in thread-local storage.
  • T2: Clear its local storage.
  • T1: Read its local storage, value stored should still be available.
This really isn’t a hard test to write other than the ordering of events. To make that work, I used latches and I had the threads manually single each other. Here’s the test:
package fitnesse.threadlocal;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import java.util.concurrent.CountDownLatch;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class ThreadLocalUtilTest {
  private String valueFound;

  // snip - several other tests removed to focus on this test

  CountDownLatch t1Latch = new CountDownLatch(1);
  CountDownLatch t2Latch = new CountDownLatch(1);

  class T1 implements Runnable {
    public void run() {
      try {
        ThreadLocalUtil.setValue("t1", "value");
        t2Latch.countDown();
        Thread.yield();
        t1Latch.await();
        valueFound = ThreadLocalUtil.getValue("t1");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  class T2 implements Runnable {
    public void run() {
      try {
        t2Latch.await();
        ThreadLocalUtil.clear();
        t1Latch.countDown();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  @Test
  public void assertThatClearInOneThreadDoesNotMessUpAnotherThread()
      throws InterruptedException {
    Thread t1 = new Thread(new T1());
    Thread t2 = new Thread(new T2());
    t1.start();
    t2.start();
    t1.join();
    t2.join();
    assertEquals("value", valueFound);
  }
}

This example illustrates using the java.util.concurrent.CountDownLatch class to signal between threads.

Main Test Method
  • Creates two threads and start them.
  • Wait for both threads to complete.
T1.run(), T2.run()
  • If T2 starts running before T1, no problem it waits on the countdown latch.
  • When T1 starts, it stores a value in a thread local using the util class.
  • T1 then counts down, releasing T2.
  • T1 then yields, it is done until its countdown latch is signaled.
  • T1 waits for a signal.
  • T2 is released from its countdown latch.
  • T2 sends clear to the thread local util class (there’s a test that verifies clear() works as named in a single thread.
  • T2 then signals T1 to continue by calling its countdown latch.
  • T2 completes at some point later.
  • T1 starts running again, grabs the value out of thread local storage and puts it in the valueFound.
  • T1 completes.
Main Test Method
  • The completion of T1 and T2 make the join methods called in the original test method to return, whereupon the test can complete.
  • Verifies that the variable valueFound, set in T1.run, stores the expected result.

This kind of hand-rolled synchronization is certainly error prone. This is where having a second pair of eyes can really help. However, this seemed to verify that the clear method as written worked in multiple threads as expected.

If you’re interested in seeing the ThreadLocalUtil class or ThreadLocalUtilTest class, grab a copy of FitNesse from github.