Ceki Gülcü <[EMAIL PROTECTED]> wrote on 02/07/2005 01:32:26 PM:

<snip>

> >The idea of having separate jar files has been floated about for a few 
> >years, for various reasons.  I believe it's only recently been 
associated 
> >with the idea that such would help alleviate classloader problems in 
the 
> >hierarchy [but only if certain rules are followed, as discussed in the 
> >original thread you referenced].
> 
> Sorry for my obtuseness but which rules are you referring to?
> 

Oh boy... ask a simple question...

One problem that we encounter, in one form or another, is when we look for 
a resource that "may or may not" be visible.  For example, a configuration 
file.

As delivered, the JCL jar files do *not* include a configuration file.

     Parent [commons-logging-api.jar, Log4J.jar]
        ^
        |
     Child

This works as expected, for the most part [other ClassLoader problems 
aside].  So how do you configure the child application, in this case, to 
use a different logger?  You might introduce a configuration file.

     Parent [commons-logging-api.jar, Log4J.jar]
        ^
        |
     Child  [commons-logging.properties, LogKit.jar]


So... what happens if/when the parent changes to move from "default" 
behavior to specific configuration behavior?

     Parent [commons-logging-api.jar,
             commons-logging.properties,
             MyLocalLoggerImpl.jar]
        ^
        |
     Child  [commons-logging.properties, LogKit.jar]


Naturally, that drives down into the child, the parent effectively 
"mandates" the logger for the children.  This is a very natural scenario. 
So, of course... sooner or later in our not-so-mythical universe, we get a 
user who wants to return "control" back to the client application [EJB's]. 
 They would typically do this by setting [or the system is preset] the 
ClassLoader to do child-first resource resolution:

     Parent [commons-logging-api.jar,
             commons-logging.properties,
             MyLocalLoggerImpl.jar]
        ^
        |
     Child, child-first loading
            [commons-logging.properties, LogKit.jar]


Now we locate the proper config for the child, and all works as expected. 
But equally viable and frequently seen in this situation is a "self 
contained EAR file": the EAR file contains a copy of the commons-logging 
jar file, and depends on the "default" behavior built into the LogFactory, 
i.e. NO config file:

     Parent [commons-logging-api.jar,
             commons-logging.properties,
             MyLocalLoggerImpl.jar]
        ^
        |
     Child, child-first loading
            [commons-logging-api.jar, LogKit.jar]


In this case, the child's LogFactory is going to locate the 
commons-logging.properties file from the parent, and attempt to load 
MyLocalLoggerImpl [which extends Parent's Log interface] and return it 
through the Child's LogFactory as a Child Log interface... and of course 
we get an Exception.

A guideline ['rule'] that was floated about was that a parent class loader 
must never contain a configuration file, whether it be 
commons-logging.properties or 
META-INF/services/org.apache.commons.logging.Log*.  This is not something 
we enforce today, and it's really counter to the "expected" 
use/configuration of JCL.  So instead, we try the guideline that all 
children *must* provide a configuration file, noting that it may be 
ignored with parent-first search behavior.  This is a small improvement, 
but again unenforcable.

However, I've put more thought into this since my proposal of a few months 
back. :-)

There are really THREE independent things that need to be done:

a. Based on the discussion of ClassLoading issues from the other day, this 
is more properly handled by a discovery process that does NOT look higher 
in the hierarchy than the ClassLoader used to load the target interface 
(Log, in this case).  This would prevent discovery of a configuration that 
does not apply to the "local" Log.

b. Step completely away from "default" behavior [auto discovery]. 
Everything should be configured explicitely, either by placing a config 
file in every variant of the distributable jar files or possibly by 
hard-coding the logger impl for each variant [needs more thought].

c. Configuration discovery must enforce the rule that only ONE 
configuration may exist in any one ClassLoader.  This doesn't mean we 
can't have diff configs in each ClassLoader in a hierarchy, or different 
*ways* to configure within a ClassLoader instance: it means that we must 
*must* have a clear understanding of which configuration is appropriate at 
a single *point* in the hierarchy.

For example, the following *could* legal [though we could take a hard-line 
stance against it also]:

     Parent [A.jar(commons-logging.properties)]
        ^
        |
     Child  [B.jar(commons-logging.properties),
             C.jar(META-INF/services/org.apache.commons.logging.Log)]


This might be considered legal because the discovery process places a 
precidence on the two different ways to configure the logger... one will 
win out.

However, the following scenario must be detected, an error logged, and a 
fall-back to a SimpleLogger [i.e. ignore BOTH configurations for the Child 
loader]:


     Parent [A.jar(commons-logging.properties)]
        ^
        |
     Child  [B.jar(commons-logging.properties),
             C.jar(commons-logging.properties)]

I consider this invalid, because we have no precidence rules available to 
determine which to use.  And YES, I'm claiming that "order of declaration 
in CLASSPATH" is NOT good enough.  More sophisticated ClassLoaders are 
just to smart for their own good, and don't always allow good ways to 
determine this type of behavior.

> ><ras>
> 
> -- 
> Ceki Gülcü
> 
>    The complete log4j manual: http://www.qos.ch/log4j/
> 
> 

*******************************************
Richard A. Sitze
IBM WebSphere WebServices Development

Reply via email to