Tuesday, August 19, 2008

Problems with the webapp.root system property when using Tomcat & Log4J.

java.lang.IllegalStateException: Web app root system property already set to different value:

I've been developing a web application that uses Log4J for logging. Recently I started a new web app, using essentially the same framework.
(By the way, the framework - which uses Hibernate Annotations and Spring MVC - is based on the one descrbed in this tutorial)

Anyway, in creating this new web app and starting Tomcat, I immediately encountered the following error:

SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.util.Log4jConfigListener
java.lang.IllegalStateException: Web app root system property already set to different value: 'webapp.root' = [MyPath\EclipseProjects\.metadata\.plugins\com.genuitec.eclipse.easie.tomcat.myeclipse\tomcat\webapps\app1Name\] instead of [MyPath\EclipseProjects\.metadata\.plugins\com.genuitec.eclipse.easie.tomcat.myeclipse\tomcat\webapps\app2Name\] - Choose unique values for the 'webAppRootKey' context-param in your web.xml files!
at org.springframework.web.util.WebUtils.setWebAppRootSystemProperty(WebUtils.java:132)
at org.springframework.web.util.Log4jWebConfigurer.initLogging(Log4jWebConfigurer.java:117)


Ok - so why is this??? Well, I'm glad you asked...

First things first, I should note that the L4JWebConfigurer class is:

"A convenience class that performs custom Log4J initialization for web environments, support 2 init parameters..." that are set as context-param in web.xml.

See: http://opensource.objectsbydesign.com/spring-1.1.4/org/springframework/web/util/Log4jWebConfigurer.html
and
http://static.springframework.org/spring/docs/1.2.x/api/org/springframework/web/util/Log4jWebConfigurer.html


However, this convenience class comes with a warning:

"WARNING: Some containers (like Tomcat) do not keep system properties separate per web app. You have to use unique "webAppRootKey" context-params per web app then, to avoid clashes. Other containers like Resin do isolate each web app's system properties: Here you can use the default key (i.e. no "webAppRootKey" context-param at all) without worrying. "

So... given I'm using Tomcat, what does this mean?

It turns out that the webAppRootKey is a Spring context parameter. It exposes the web application's root directory as a system property. So, it is the value of the webAppRootKey that provides the name for the system property to use. That's fine if you've just got one webapp in Tomcat. Spring will just choose a default value for this (app.root) and off you go. However, as the warning above notes, Tomcat does not keep system properties separate per webApp. This means that when we get to the second application, the same system property (app.root) is being set to a new value (our second application's root directory, rather than the first!)

The reason this is occurring at all is that Log4JConfigListener is trying to set the webAppRootKey in both cases. This allows log4J to place log and config files in directories relative to the application root directory, rather than in a fixed path.

Anyway, the real question is how to fix this. One option would be to remove the Log4JConfigListener, or re-configure Log4J so that this doesn't happen - that is by setting 'log4JExposeWebAppRoot' to false. (This is a servlet context parameter that eliminates the use of log file locations relative to the web application's root directory.)

However, in my case, I decided the easiest thing was just to use a non-default name for the webAppRootKey for each of my applications.

That is, I fixed this by placing the following context-parameter into each of the web application's web.xml files:

<context-param>
<param-name>webAppRootKey</param-name>
<param-value>uniqueAppRootNamee</param-value>
</context-param>

This fixed the problem, and everything's working again... Hoorah!

15 comments:

Ajar Vashisth said...

Thanks Glenn

Anonymous said...

Thank you so much. Exactly what I needed.

kunal said...

thanks Glenn...this saved me alot of time ;)

three_sixty said...

Thanks, it's a very good post!

Anonymous said...

Good One!!!

Anonymous said...

great tips

thanks :)

Eduardo QuirĂ³s-Campos said...

Thanks for the tip!!! A real time saver.

Matthew said...

Thanks Glenn. A really clear-cut article.

Anonymous said...

Thanks your the man

Anonymous said...

Thanks, Glenn !

Unknown said...

Thanks, that was my savior!!!

Anonymous said...

Great article, really helped me out. I would just like to point out a little typo: log4JExposeWebAppRoot should be log4jExposeWebAppRoot when using the property in your web.xml file

Anonymous said...

Great job. Exactly what we needed

Paulie said...

Thanks mate! Well written too...

Chhorn Ponleu said...

This post was long long ago, but I still find it useful. Thank Glennn