logging-log4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Colin Sampaleanu" <colin...@exis.com>
Subject RE: Problem with loading the log4j.properties file
Date Thu, 09 Aug 2001 12:20:22 GMT
> -----Original Message-----
> From: Maarten Coene [mailto:MacBelgium@ToughGuy.net]
> Sent: Wednesday, August 08, 2001 4:07 AM
> To: log4j-dev@jakarta.apache.org
> Subject: Problem with loading the log4j.properties file
> there is a problem loading the default log4j.properties file when using
> J2EE (RI). My system has the following configuration:
> 1. the log4j.jar is placed into my CLASSPATH variable
> 2. my log4j.properties file is placed into the classpath of my
> J2EE Application
> Now, if I try to create a new Category, log4j complains it cannot
> find the
> log4j.properties file. This is because the log4j.jar is loaded with a
> different classloader than my J2EE application: say classloaderA
> has loaded
> my log4j.jar file and classloaderB has loaded my J2EE Application.
> ClassloaderA has no knowledge of my J2EE application and therefore cannot
> find the log4j.properties file, but classloaderB can find it
> since it is in
> it's classpath!!
> I have solved this problem the same way the "loadClass problem" has been
> solved in the org.apache.log4j.helpers.Loader class. I have replaced the
> following line of code in the Loader.class:
> // Let the class loader of clazz and parents (by the delagation
> // property) seearch for resource
> ClassLoader loader = clazz.getClassLoader();
> by:
> // Let the class loader of clazz and parents (by the delagation
> // property) seearch for resource
> ClassLoader loader = null;
> if(java1) {
>    loader = clazz.getClassLoader();
> } else {
>    loader = Thread.currentThread().getContextClassLoader();
> }
> After this replacement, log4j can succesfully load my default
> log4j.properties file! If you think it's ok, perhaps someone can
> commit it
> to cvs?

First, to clarify what is going on (subsequent messages have attempted, but
not totally, so some of thsi will be a repeat):

The System classloader is the parent of the Extension classloader, which is
the parent of the App classloader. The App classloader is used to load the
App Server. The App Server will for each Web-App or EJB loaded into it
create a container and associate a child classloader with that container.
(it will then also set the current 'Context' or thread classloader to that
classloder, whenever a thread executes inside code loaded into that

A classloader when asked to load a class/resource, will always delegate to
its parent, and that parent to its parent, etc. If the topmost classloader
can not find the class/resource, it will then ask the child which delegated
to it to look for the resource, and if that child can not find the class it
will ask whoever delegated to it, and so on, until you get back to the
initial classloader asked to load the class.

(This is fairly clear, but what usually confuses the issue for most people
is the question of which classloader actually gets used or should be used in
various situations, one related to your or a particular class (used in
implicit classloading or when you do a simple Class.forName(s)), or the
current Context (thread) classloader, which may be different, and is almost
always what you want if it is indeed different).

So in this case, we are running code inside the web-app container. Our
context classloader has been set to point to the container's classloader.
When Category needs to be static initialized, the container/web-app
classloader delegates to the Application classloader (what the app server is
running in) which finds the log4j classes. When the static init method runs,
which needs to find the property file, it does a
    url = Loader.getResource(resource, Category.class);
the Loader then tries to use the classloader (call it CL-A) which loaded
Category itself to find log4j.properties, and this fails, because the
property file is known only to the container/web-app classloader (call it
CL-B), which is a child of CL-A, and items visible to it are not visible to
its parent.

So Maarten's patch works, by forcing the current Context (thread)
classloader to be used instead. If you think about it, this should normally
always be the proper behaviour. In the case of an app server, where the app
server itself is using log4j (effectively what you have in this situation
when you drop log4j.jar on the app server's classpath), all web-apps and
EJBs running inside it need to be able to find their individual property
files, and this is the only way it will happen. Even if you were to move
log4j.jar inside the web-app classloader itself (so that the code would be
visible to the web-app's classloader), this would only work if the app
server itself was not trying to use log4j; as soon as it did you woudl be
screwed. It would now know about Category, and its classloader would always
be used instead of the web-app's. (If you think about it, this also
introduces real versioning issues. If the app server itself is running
log4j, there is nothing a Web-App can do to override this version and use a
newer one; any newer log4j.jar it has in its own classpath will be overriden
by the older version visible in the app server's classpath).

So I think Maarten's patch is ok, but needs to include a change in the
description of getResource() though, so users don't get confused. It
currently says
     <p><li>Search for <code>resource</code> using the same class
     loader that loaded <code>clazz</code>.
and should say something like
     <p><li>Search for <code>resource</code> using the current context
     classloader (Java 1.2+), or using the same class
     loader that loaded <code>clazz</code>. (Java 1.1).

If log4j ever stops being 1.1 compatible, then the usage of clazz'z
classloader should probably go away completely.



To unsubscribe, e-mail: log4j-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-dev-help@jakarta.apache.org

View raw message