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