Jake, Have you already tried using JNDI-based RepositorySelector?
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]
Ceki
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]