Musings
muse: to turn something over in the mind meditatively and often inconclusively
Rox 0.7 released

I pushed out version 0.7 of Rox a little while ago. The changelog is included below for those looking to kill some time.

Release 0.7
=====================

  - NoSuchMethodException and NoSuchMethodError are reported by server 
    instances using a 404 (Not Found) HTTP response code.
  - Shutting a server down did not correctly close established connections.
  - Remote closure of a connection that was pooled on the client side
    resulted in a deadlock because the wrong client was notified of the closure.
  - Timeout exceptions were closing the connection the timeout occurred on
    without notifying the connection pool, resulting in a logical resource
    leak.
  - Timeout exceptions are now raised within the context of the caller
    rather than the timer thread.
  - A common base class has been introduced for both timeout exceptions so
    uniform handling can easily be applied to both cases.
  - A default request timeout can now be configured on a ClientResourcePool.
    Any client instances sharing this pool will have their request timeout
    initialized based on this value.
  - When using a resource pool connection pooling is keyed on the protocol,
    host and port rather than on individual client instances. This allows
    client instances that shared a remote destination to share connections.
  - All instances of SimpleDateFormat are now retrieved from thread local
    storage. This ensures that these instances are never accessed by
    multiple threads simultaneously while avoiding creating unnecessary 
    instances.
  - The synchronous client API will now raise a more specific IOException
    (RPCCallFailedException) if a non-timeout related error occurs invoking
    an XML-RPC method.
  - The resource pool mentioned previously is now responsible for connection
    pooling. This makes it possible restrict the number of open connections
    across a set of client instances.
  - It's now possible to associated an explicit pool of worker threads with
    a collection of client or server instances. This makes it possible to
    reuse I/O, worker and timer threads across a selected set of instances, 
    which assists when trying to scale to large numbers of client or server
    instances by keeping the thread count under control.
  - Introduced a LogFactory class. The model for logging has changed in this 
    release. Log instances are no longer associated with a particular client
    or server instance. Rather, they're "looked up" in much the same fashion
    as with Log4J. This is a slightly less flexible approach to logging since
    it effectively forces a single global logging strategy, but I don't feel 
    this limitation is too serious (for now), and this simplifies logging and
    removes one coupling point between worker threads and client/server 
    instances in anticipation of some upcoming changes.

Posted at 01:33 PM

Congrats to Sam

Who passed his thesis dissertation on Monday. Guess we'll have to start calling him Herr Doktor now.

Posted at 09:25 AM

Portfolios for programmers

I'm not even going to intimate that this is my idea. Over drinks with Ben (don't follow that link if you're looking for anything up to date) and Chris this evening, Ben raised the question of why programmers don't maintain a portfolio in the same way artists do.

It makes sense. A lot of sense. It would certainly be useful to take a look over some actual (preferably) working code. I suppose the most obviouss stumbling block is IP. But that aside the only other objection we could come up with was what's to stop someone from plagiarising code? There's certainly enough out there so that the risk of being found out is relatively small. Sure, the occasional idiot might try to pass the Tomcat codebase off as his own work (two demerits, one for plagiarism, the other for choosing such a shitty source), but for the most part we don't think this would be a problem, as long as you couple it with a few well chosen questions. Even if you didn't author the code, if you've spent enough time thinking about it so you can answer a few key questions about it then it probably doesn't matter.

I think this is something worth thinking more on. Next time I interview you, bonus points if you have a portfolio of code with you.

Posted at 09:41 PM

Strength and courage

poppy_small.jpg It's been a long road and a hard decision. I think it's the right decision but it's been your decision. This is one of those that I couldn't really help you make. The most I could do was to be there while you made it and to help you accept it afterwards. You said it best, it's a decision made with the head, not with the heart. I think that's only made it harder.

The road runs off over the horizon, and there's a fair bit of walking before we're clear of these woods. There will be ups and downs, and sometimes we'll have to retrace our steps because we took a wrong turn.

But the forest is only so wide and on the other side there are fields of green where lassie clones frolic under rays of golden sunlight. And I remembered our tickets so don't fret about them letting us in.

Don't be in a hurry to get through it because you'll only catch your foot on a tree root and hurt your knee again. And I know, having said that, that you'll rush on ahead anyway. I'll be back here anytime you need me to pick you up and dust you off.

When all is said and done the most important thing to remember is that the things I love you for are things no one can take away.

Posted at 10:43 PM

A chill in the air

simonstown_on_a_sunday_small.jpg Winter's chilly fingers wrapped themselves around the afternoon, in complete contrast with the clear blue sky and bright sunlight.

Andy and I shot out to the point for a quick run, just to turn the engines over (the bikes' and our own).

As much fun as the act of biking is, the cherry on top is dogs. Dogs seem to go nuts when they see bikers. I don't know if it's the noise, or the fact that we look like something that stepped out of a bad sci-fi show but they wet themselves in an apparent attempt to ... actually I don't really know what they're trying to accomplish. Whatever it is they really put their backs into it.

A quick run is a good reminder that there are nutters out there on our roads. Although you don't need to go out on a bike to refresh your memory. A short trip to the shops is usually sufficient.





Posted at 10:23 PM

SimpleDateFormat: a warning

If you find yourself scratching your head because you're seeing NumberFormatExceptions with weird error messages that include "multiple points" (i.e. decimal points) or empty or weird format strings then you might want to take a gander at bug 4228335 in Sun's bug parade.

It seems that SimpleDateFormat is not thread safe. This is disappointing because the docs make it clear that initialization is probably expensive (profiling tends to confirm this) and recommends creating them once and reusing them. This seems to imply thread safety. Fair enough, never assume anything. What's even more disappointing is this has been floating around on the bug parade for a decade and the only "fix" Sun has provided to date is a documentation update.

Various workarounds exist, ranging from cloning instances before using them (ouch) to synchronizing access (not great given that parsing or formatting a date is often an expensive operation in its own right).

The solution I've gone with is to make use of an implementation of ThreadLocal that clones the formatter when initializing thread local values. This avoids having to synchronize and you pay the cost of cloning upfront. If you're pooling your threads then you stop paying the latter cost pretty quickly.

To make it a little more convenient I usually hide this ThreadLocal instance inside a class that provides direct access to it. This really just avoids having to repeatedly cast the value returned by ThreadLocal.get(). Roughly speaking the code looks like this.

import java.text.DateFormat;

public class DateFormatProvider {
   private ThreadLocal threadLocal;

   public DateFormatProvider(final DateFormat formatter) {
      this.threadLocal = new ThreadLocal() {
         protected Object initialValue() {
            return formatter.clone();
         };
      };
   }

   public DateFormat getFormatter() {
      return (DateFormat) this.threadLocal.get();
   }
}

Using it is pretty straightforward. Replace any instances of DateFormat with an instance of this (passing it the formatter you were using; this will be cloned to create the thread local formatters) and then wherever you used the DateFormat just call the getFormatter() method to get hold of an instance for the calling thread. So replace something like this.

// This is broken
public class Foo {
  private static final DateFormat DATE_FORMAT = new SimpleDateFormat("...");

  public String gimmeNow() {
    return DATE_FORMAT.format(new Date());
  }
}

with this

public class Foo {
  private static final DateFormatProvider DATE_FORMATS =
        new DateFormatProvider(new SimpleDateFormat("..."));

  public String gimmeNow() {
    return DATE_FORMATS.getFormatter().format(new Date());
  }
}

Posted at 09:29 PM