dataFaber 5.0

Stop the pollution in WEB-INF/classes

Of the 12 or so Java libraries used in this site, 6 of them by default have their configuration files in the CLASSPATH:

  • log4j (log4j.properties / log4j.xml)
  • commons-logging (commons-logging.properties)
  • XWork (xwork.xml)
  • WebWork (webwork.properties, validators.xml plus all the <action>-validator.xml)
  • OSCache (oscache.properties)
  • iBATIS (the sql map configuration and definition)

Various resource bundle also litter the CLASSPATH, thanks mainly to WebWork action messages and global resource bundle. Enough of that for me, time to end that incestuous relationship, stop wasting time with .cvsignore and svn:ignore: I want Java classes in the CLASSPATH and nothing else. I could convince at least log4j and Ibatis to look elsewhere:

  • log4j has PropertyConfigurator.configureAndWatch(), where the argument is the full path of WEB-INF/config/log4j/log4j.properties
  • Ibatis has SqlMapClientBuilder.buildSqlMapClient(), where the argument is a java.io.Reader from the full path of WEB-INF/config/ibatis/sqlMapConfig.xml (nice side effect, I can freely reload my Sql map definitions at runtime)

For resource bundles I now use a database, a simple table with (key, language, message) and a class that implements ResourceBundle, no more .properties and native2ascii to deal with.
As you see, I've started to use WEB-INF/config and subdirectories, whose full paths are determined via ServletContext.getRealPath("/") + "/WEB-INF/config". The benefits:

  • the files won't be served to HTTP clients
  • very easy to put under source control, no gymnastics with .cvsignore or svn:ignore required

There is one disadvantage, it won't work if the web application runs from a compressed WAR file: my guess that WEB-INF/classes became a popular dumping ground because other than Thread.getContextClassLoader().getResource() there is no portable way of reading files in a web application. How many web application actually run from a compressed WAR file? What's the rationale for having it in the Servlet spec?

2 Comments

  1. Brian McCallister

    WAR files are used a lot, in my experience, far more than exploded directories.

  2. Craig McClanahan

    Your assertion that there is no standard way to access static resources in a webapp deployed as a WAR is not correct. See ServletContext.getResource(), which gives you back a URL that you can open, or ServletContext.getResourceAsStream(), which gives you back an InputStream to the resource data. Both of these work againat a context relative path that starts with a slash (“/WEB-INF/config/myconfig.properties” for example), and they don’t care whether your app is exploded or not – it’s up to the servlet container to give you back a URL that it knows how to interpret.

    That being said, don’t forget that resources in /WEB-INF/lib JAR files are on the classpath too :-). Your stance of only wanting classes is definitely not a mainstream approach.