Monday, January 12, 2009

The joys of Websphere 6.1 and Commons Logging

My latest project uses libraries that use Jakarta Commons Logging (JCL) and logging works great using Log4J, until we deploy to Websphere which is our target environment. This blog post is a war story in getting it to work.

The Problem

First I'll mention that there seems to be known problems with JCL and Websphere. IBM have some documentation on their website as well as some helpful tips to resolve the issue, and many folk have blogged their experiences with this issue. The Commons Logging Wiki also has some good info. While all of them were really helpful, none completely solved my problem.

Before explaining my solution, lets understand that the root cause of this pain is IBM bundling up a Commons Logging distribution inside one of their server JAR's, and not only that, placing a configuration file in there too that overrides Commons Logging's default behavior. You can see the JCL classes and commons-logging.properties file in the jar ${WAS_INSTALL_ROOT}/plugins/com.ibm.ws.runtime_6.1.0.jar. That means that without fiddling with the class loading order, you are stuck with IBM's version and default configuration of JCL. I'm in a corporate environment and messing too much with classloaders raises red flags, so fiddling with the classloader was something I wanted to avoid, if possible.

The version of WAS and it's embedded JCL implementation are crucial to this discussion. Firstly, my WAS version is 6.1.0.17. The version of JCL is hard to determine but is seems to be 1.0.3. I understand different fixpacks of WAS handle this slightly differently but no doubt they are all variations on the same theme.

The Solution

The obvious solution to this is to configure JCL to use Log4J instead of the default defined in WAS's commons-logging.properties. There are a number of ways to do this, I chose to use the JDK 1.3 Services Discovery mechanism (as described bn the Commons Logging Javadoc which explains the various config options). Using information gleaned from other blog posts, I made my org.apache.commons.logging.LogFactory file and added a single line, "org.apache.commons.logging.impl.Log4jFactory". I redeployed the application, held my breath, and ....

... nothing happened. It didn't work! Here is why.

First problem was that my application bundled JCL v1.1.1, and the org.apache.commons.logging.impl.Log4jFactory class was removed in the 1.1.x stream. So, JCL was actually throwing a ClassNotFoundException when attempting to load the class and then falling back to the default (as specified in that wretched properties file bundled deep in WAS's server jar). No Bingo!

But doesn't WAS bundle up JCL 1.0.3, which does have that class? Apparently not. Having a look in that Websphere JAR file shows lots of JCL classes but not that one. So, the answer is to ensure you do the following:
  • ensure you deploy Jakarta Commons Logging 1.0.3 with your application, and
  • add the org.apache.commons.logging.LogFactory file to META-INF/services.
Once I did that, it all worked. Half a day wasted.

Why IBM chose to bundle such a common library (it even has "common" in the name) and put it first on the classpath is baffling. By doing that, it forces applications to use that version of the library, regardless of whether they package it up or not. JavaEE applications should (actually, they must) include JAR's that are not part of the JDK or JavaEE stack, and as application developers we should expect third-party libraries to work without having to mess around with classpath or server settings. By no means are IBM the only ones guilty of this but it is frustrating to waste half a day chasing a problem caused by classpath hell.

2 comments:

  1. Do you know if there is an ticket logged with IBM for this issue. I've been trying to navigate their mammoth site in a vain attempt to establish the existence/non-existence of such a ticket.

    Failing that do you know where the starting point is to log such a ticket.

    Sorry to be asking you this - I really have tried to RTFM on this but the IBM portal is vast and not the easiest to use.

    ReplyDelete
  2. I was just having a hunch that the version of commons-logging was conflicting with IBM's version when I came across this post. Very helpful in understanding what's going on, thanks!

    I am actually using Websphere 6.0 (don't know the dot version) and this approach works there too.

    ReplyDelete