Monday, October 29, 2007

My problems putting RichFaces to work

There are many open source JSF component libraries in the market. So I had to choose one among them for my JSF projects. After some exhaustive exploration, I chose Ajax4jsf and RichFaces (now both projects are merged) as my component library because of the ajax-enabled components and also because I think it has enough JSF components to work with.

I read the RichFaces Developer Guide, and followed both the installation process and setting up, however I had problems getting it installed.
They got me crazy for long, but I didn't want to call off my attempt (although I might confess I was close to get rid of RichFaces). Actually I had different problems for different versions of the library, so I'm describing them hoping I can help somebody avoid this nightmare.

My Runtime Environment

Before going any further, I must explicit what my runtime environment is.
I have tried different versions and possible combinations (of course, avoiding not matching combinations such as Tomcat 5.5 and JSF 1.2):

  • JDK 5 and JDK 6 (update 1 and 2).
  • Tomcat 5.5 and Tomcat 6.
  • JSF RI (Sun's implementation), versions 1.1 and 1.2.

Configuring RichFaces 3.0.1

This is no longer the current version of RichFaces, so you will want to skip this part, but if not here is my experience with this version.

RichFaces 3.0.1 doesn't include officially Ajax4Jsf. However the lib directory seems to indicate otherwise.

RichFaces 3.0.1 included jar files:

  • ajax4jsf-1.1.1.jar
  • richfaces-3.0.1.jar

So I decided to work with this files in my web application (and not include any other version of Ajax4Jsf). As soon as I deployed my application I obtained an error. It seems to happen just when starting the ajax4jsf filter:
org.apache.catalina.core.StandardContext filterStart
java.lang.NoClassDefFoundError: org/apache/commons/collections/map/LRUMap
Soon I realized that the lib directory for Ajax4jsf 1.1.1 contained one file whereas version 1.1.0 contained two files:

Ajax4Jsf 1.1.1 included jar file:

  • ajax4jsf-1.1.1.jar

Ajax4Jsf 1.1.0 included jar files:

  • ajax4jsf-1.1.0.jar
  • oscache-2.3.2.jar

After that observation, I removed the ajax4jsf-1.1.1.jar file from RichFaces 3.0.1 and added the jar files from Ajax4Jsf-1.1.0 resulting in the following files:
  • richfaces-3.0.1.jar
  • ajax4jsf-1.1.0.jar
  • oscache-2.3.2.jar

And this is the workaround (based on a mixed jar files) that really worked out for RichFaces 3.0.1.

Configuring RichFaces 3.1.x

Finally, as of version 3.1.0, RichFaces and Ajax4JSF are put together in one single project.

It comes with three jar files. These are their names for version 3.1.2:
  • richfaces-api-3.1.2.GA.jar
  • richfaces-impl-3.1.2.GA.jar
  • richfaces-ui-3.1.2.GA.jar

However, running my web application with these files addressed another java.lang.NoClassDefFoundError error.
This time, I discovered that RichFaces has a "non documented" dependence of several apache commons libraries. The error vanished as soon as I added the latest version of these commons files.

For clarification this is the version of commons (and their jar files) I have included:

  • commons collections 3.2 (commons-collections-3.2.jar)
  • commons beanutils 1.7.0 (commons-beanutils.jar)
  • commons digester 1.8 (commons-digester-1.8.jar)
  • commons logging 1.1 (commons-logging-1.1.jar, commons-logging-adapters-1.1.jar, commons-logging-api-1.1.jar)

Sharing commons files between multiple libraries

Be aware of not including this apache commons files more than once!

So if you use these files within any other library in addition to RichFaces (e. g. Hibernate), then you need to ensure only one occurrence (the latest version) is really available otherwise you'll obtain a java.lang.NoClassDefFoundError error again.

You also need to ensure that all libraries sharing the commons files are loaded by the same class loader. For instance, if you have Hibernate jar files inside of $CATALINA_HOME/common/lib and RichFaces jar files within your war file then you have no other way but to put the apache commons files inside of $CATALINA_HOME/common/lib in order to avoid the java.lang.NoClassDefFoundError error.

As a consequence, if you're using Tomcat 5.5 you should know that this version of tomcat already includes some commons files within $CATALINA_HOME/common/lib, therefore, in this case you'll have to put the apache commons files at $CATALINA_HOME/common/lib and not within your war file, even though your RichFaces jar files are inside your war file!

As of Tomcat 6, there is no longer any use of apache commons library by Tomcat, so you can chose whether to put your last version of commons. As a rule of thumb $CATALINA_HOME/lib is the safest place though.

Due to the lack of documentation, all these conclusions have been collected from empirical tests.
I really appreciate any comments and share similar experiences. It'd be nice to know if there are people who has been through all this mess.