Hello Ceki, No, I haven't as of yet. I'll try that this weekend.
BTW, before you mentioned that doIdempotentInitialization() should be moved from the ContextClassLoaderSelector to whatever code that is performing initializatiion, such as the InitContextListener. However, I don't see how this is possible given the contents of the initialization method... public static void doIdempotentInitialization() { if (!initialized) { try { Object guard = new Object(); LogManager.setRepositorySelector(SINGLETON, guard); initialized = true; } catch (IllegalArgumentException iae) { // either ignore the exception or log the fact that the // setting of this custom repository selector failed because // another had been set previously and maybe we should set // "initialized" to "true" in here so this exception doesn't // occur again in this class } } } Note the "SINGLETON" variable sent into setRepositorySelector. This is a private variable that is the singleton instance of the ContextClassLoader... /** * singleton instance for this class */ private static final ContextClassLoaderSelector SINGLETON = new ContextClassLoaderSelector(); How could this be moved into an outside class performing initialization? This is why I suggested that doIdempotentInitialization() be added to the RepositorySelector interface. However, I do realize that there are implications in backward compatibility with other classes implementing this interface. The issue is that we need to provide a standard way to install custom repository selectors without referring to any specific repository selector in the initialization class as is being done with ContextClassLoaderSelector inside InitContextListener. It would make it easier if I could count on doIdempotentInitialization() existing in each and every class that implements RepositorySelector. If this was done, then we could create a factory class which any particular initialization class could use and pass in a variable defining the preferred repository selector. The value of the passed-in variable could be set as a system variable, passed in as a context-parameter, or whatever. The factory would then invoke doIdempotentInitialization() on the preferred repository selector and everything would be set up. The above is what I am looking for, ideally. I need some advice as to what will be possible given the design goals of Log4j, and then within those constraints, how would I genericize the installation of repository selectors? thanks, Jake Friday, February 14, 2003, 9:32:26 AM, you wrote: CG> Jake, CG> Have you already tried using JNDI-based RepositorySelector? CG> At 05:58 14.02.2003 +0000, you wrote: >>hoju 2003/02/13 21:58:56 >> >> Modified: src/java/org/apache/log4j/selector >> ContextClassLoaderSelector.java >> Log: >> Updated Javadoc. Also, modified code to conform to checkstyle. >> >> Jake >> >> Revision Changes Path >> 1.2 +94 >> -45 >> >jakarta-log4j-sandbox/src/java/org/apache/log4j/selector/ContextClassLoaderSelector.java >> >> Index: ContextClassLoaderSelector.java >> =================================================================== >> RCS file: >> >/home/cvs/jakarta-log4j-sandbox/src/java/org/apache/log4j/selector/ContextClassLoaderSelector.java,v >> retrieving revision 1.1 >> retrieving revision 1.2 >> diff -u -r1.1 -r1.2 >> --- ContextClassLoaderSelector.java 4 Feb 2003 06:28:16 -0000 1.1 >> +++ ContextClassLoaderSelector.java 14 Feb 2003 05:58:56 -0000 1.2 >> @@ -4,64 +4,113 @@ >> * This software is published under the terms of the Apache Software >> * License version 1.1, a copy of which has been included with this >> * distribution in the LICENSE.txt file. */ >> - >> package org.apache.log4j.selector; >> >> -import org.apache.log4j.spi.RepositorySelector; >> -import org.apache.log4j.spi.LoggerRepository; >> -import org.apache.log4j.spi.RootCategory; >> import org.apache.log4j.Hierarchy; >> import org.apache.log4j.Level; >> import org.apache.log4j.LogManager; >> +import org.apache.log4j.spi.LoggerRepository; >> +import org.apache.log4j.spi.RepositorySelector; >> +import org.apache.log4j.spi.RootCategory; >> + >> import java.util.Collections; >> import java.util.Map; >> import java.util.WeakHashMap; >> >> + >> /** >> - * @author Jacob Kjome >> + * Log4j Contextual ClassLoader Selector >> + * >> + * <p>based primarily on Ceki Gülcü's article <h3>Supporting the Log4j >> + * <code>RepositorySelector</code> in Servlet Containers</h3> at: >> + * http://qos.ch/containers/sc.html</p> >> + * >> + * <p>By default, the class static <code>RepositorySelector</code> >> variable >> + * of the <code>LogManager</code> class is set to a trivial >> + * <code>RepositorySelector</code> implementation which always >> + * returns the same logger repository, which also happens to be a >> + * <code>Hierarchy</code> instance. In other words, by default log4j >> will use >> + * one hierarchy, the default hierarchy. This behavior can be >> overridden via >> + * the <code>LogManager</code>'s >> + * <code>setRepositorySelector(RepositorySelector, Object)</code> >> method.</p> >> + * >> + * <p>That is where this class enters the picture. It can be used to >> define a >> + * custom logger repository. It makes use of the fact that each >> webapp runs >> + * in its own classloader. This means we can track hierachies using the >> + * webapp classloader as the key to each individual hierarchy. That >> is what >> + * is meant by "contextual classloader" selector. Each classloader >> provides a >> + * unique logging context.</p> >> + * >> + * <p>Of course, this means that this class will only work in >> containers which >> + * provide for separate classloaders, so that is something to keep in >> mind. >> + * This methodology will certainly work in containers such as Tomcat >> 4/5 and >> + * probably a multitude of others. However, Tomcat 4.x.x and 5.x.x >> are the only >> + * containers currently tested.</p> >> + * >> + * @author Jacob Kjome >> + * @since 1.3 >> */ >> public class ContextClassLoaderSelector implements RepositorySelector { >> - >> - // key: current thread's ContextClassLoader, >> - // value: Hierarchy instance >> - final private static Map hierMap = Collections.synchronizedMap(new >> WeakHashMap()); >> - >> - final private static ContextClassLoaderSelector singleton = new >> ContextClassLoaderSelector(); >> - private static boolean initialized = false; >> - >> - private ContextClassLoaderSelector() {} >> - >> - public LoggerRepository getLoggerRepository() { >> - ClassLoader cl = Thread.currentThread().getContextClassLoader(); >> - Hierarchy hierarchy = (Hierarchy) hierMap.get(cl); >> - >> - if(hierarchy == null) { >> - hierarchy = new Hierarchy(new RootCategory((Level) Level.DEBUG)); >> - hierMap.put(cl, hierarchy); >> - } >> - return hierarchy; >> - } >> - >> - /** >> - * The Container should initialize the logger repository for each >> - * webapp upon startup or reload. In this case, it is controllable >> - * via each webapp. >> - */ >> - public static void doIdempotentInitialization() { >> - if(!initialized) { >> - try { >> - Object guard = new Object(); >> - LogManager.setRepositorySelector(singleton, guard); >> - initialized = true; >> - } catch (IllegalArgumentException iae) { >> - //either ignore the exception or log the fact that the setting >> of this >> - //custom repository selector failed because another had been >> set previously >> - // and maybe we should set "initialized" to "true" in here so >> this exception doesn't >> - // occur again in this class >> - } >> + /** >> + * key: current thread's ContextClassLoader, >> + * value: Hierarchy instance >> + */ >> + private static final Map HIER_MAP = >> + Collections.synchronizedMap(new WeakHashMap()); >> + >> + /** >> + * singleton instance for this class >> + */ >> + private static final ContextClassLoaderSelector SINGLETON = >> + new ContextClassLoaderSelector(); >> + >> + /** >> + * remember idempotent initialization status >> + */ >> + private static boolean initialized = false; >> + >> + /** >> + * private no-args constructor to guarantee no outside code can >> create an >> + * instance >> + */ >> + private ContextClassLoaderSelector() { >> } >> - } >> >> -} >> + /** >> + * implemented RepositorySelector interface method. >> + * >> + * @return the appropriate classloader-keyed >> Hierarchy/LoggerRepository >> + */ >> + public LoggerRepository getLoggerRepository() { >> + ClassLoader cl = Thread.currentThread().getContextClassLoader(); >> + Hierarchy hierarchy = (Hierarchy) HIER_MAP.get(cl); >> + >> + if (hierarchy == null) { >> + hierarchy = new Hierarchy(new RootCategory((Level) >> Level.DEBUG)); >> + HIER_MAP.put(cl, hierarchy); >> + } >> >> + return hierarchy; >> + } >> >> + /** >> + * The Container should initialize the logger repository for each >> + * webapp upon startup or reload. In this case, it is controllable >> + * via each webapp. >> + */ >> + public static void doIdempotentInitialization() { >> + if (!initialized) { >> + try { >> + Object guard = new Object(); >> + LogManager.setRepositorySelector(SINGLETON, guard); >> + initialized = true; >> + } catch (IllegalArgumentException iae) { >> + // either ignore the exception or log the fact that the >> + // setting of this custom repository selector failed >> because >> + // another had been set previously and maybe we should set >> + // "initialized" to "true" in here so this exception >> doesn't >> + // occur again in this class >> + } >> + } >> + } >> +} >> >> >> >> >>--------------------------------------------------------------------- >>To unsubscribe, e-mail: [EMAIL PROTECTED] >>For additional commands, e-mail: [EMAIL PROTECTED] CG> -- CG> Ceki CG> --------------------------------------------------------------------- CG> To unsubscribe, e-mail: [EMAIL PROTECTED] CG> For additional commands, e-mail: [EMAIL PROTECTED] -- Best regards, Jacob mailto:[EMAIL PROTECTED] --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]