views:

126

answers:

3

I have a web application that uses a library which resides in TOMCAT_HOME/common/lib. This library looks for a properties file at the root of the classpath (in a class called ApplicationConfig):

ApplicationConfig.class.getResourceAsStream("/hv-application.properties");

My Tomcat web application contains this properties file. It is in WEB-INF/classes, which is the root of the classpath right? However, at runtime, when it tries to load the properties file, it throws an exception because it can't find it (getResourceAsStream returns null).

Everything works fine if my application is a simple, standalone Java application. Does Tomcat cause the getResourceAsStream method to act differently? I know there's a lot of similar questions out there, but none of them have helped unfortunately. Thanks.

+3  A: 

Try Thread.currentThread().getContextClassLoader().getResourceAsStream("/hv-application.properties") instead.

binil
Thanks binil. This works, but I'd rather not have to make any changes to the library. Will mark as answer if no other solutions are found.
Michael Angstadt
+1  A: 

The Tomcat security manager generally won't let you access webapp classes and resources from libraries in the Tomcat root libraries. This is meant to give separation between the web applications running in a container.

You should be able to get around this by updating the security policy, but it's generally better to not put your libs into the Tomcat container, which I assume you are doing.

stevedbrown
The question pretty clearly says that the resource is located in the WEB-INF/classes directory ...
Pointy
@stevedbrown, the OP says that the file is packaged along with the WAR, inside WEB-INF/classes.
binil
Did you read the first sentence? "I have a web application that uses a library which resides in TOMCAT_HOME/common/lib. This library looks for a properties file at the root of the classpath (in a class called ApplicationConfig):"
stevedbrown
My countrymen! Thine quarreling doth hurteth my ears! The resource is in the webapp, but it's the library that needs to access the resource.
Michael Angstadt
@stevedbrown, I am confused - if libraries in Tomcat root libs are unable to locate classes within a deployed webapp, how does the container load servlets?
binil
@binil It's not class it's looking for in this case, but a resource that's located in the classpath.
Michael Angstadt
@mangst Agreed, but I think the process is the same. I think when looking for the class some.package.FooServlet, it first looks up a resource some/package/FooServlet.class and then loads the bytecode in that file.
binil
Andy Gherna took the time to link the Tomcat doc - it explains how Tomcat class loading works. +1'd him, it's a bit more of a full explanation than mine.
stevedbrown
+2  A: 

This looks like it might be related to how Tomcat classloaders work. If you have something in one class loader (your config file in the webapp classloader) that's used by something in another (the jar in common/lib), the result could be a big headache.

This document explains how Tomcat delegates to class loaders. If possible, could you try one of the following:

  1. Move the jar file in common/lib into your web application (WEB-INF/lib). This is not always possible I know, but sometimes jars (e.g. log4j) can coexist peacefully across classloaders (*).
  2. Move your configuration file into common/classes. This is effectively the same thing (puts the configuration item into the same classloader as the jar that needs it). Again, this is not ideal, but if you have control over your environment, it would work.

Either way, having resources in different classloaders can be a pain. I hope this helps.

(*) log4j has the -log4j.ignoreTCL option which makes this possible though

Andy Gherna
Thanks Andy, I tried moving my config file into common/classes, but it didn't work. My webapp is the only webapp that uses this library, so maybe I'll move it into WEB-INF/lib (although would sort of be a pain because I'd have to modify my Maven pom to have it include the JAR).
Michael Angstadt
It's better to keep all the jars in your webapp. Most of the time this is possible, but there are circumstances where moving things into common/lib (like if you're making a resource that's intended to be available across the server).
Andy Gherna