You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by mw...@apache.org on 2002/12/13 08:51:15 UTC
cvs commit: jakarta-log4j/src/java/org/apache/log4j/selectors ContextClassLoaderSelector.java
mwomack 2002/12/12 23:51:15
Added: src/java/org/apache/log4j/selectors
ContextClassLoaderSelector.java
Log:
Added Jacob Kjome's Log4jCRS class, renamed to ContextClassLoaderSelector.
Revision Changes Path
1.1 jakarta-log4j/src/java/org/apache/log4j/selectors/ContextClassLoaderSelector.java
Index: ContextClassLoaderSelector.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* 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.selectors;
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 java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
/**
* ContextClassLoaderSelector
*
* <p>This class is provided as an example of a <code>RepositorySelector</code>
* that uses ClassLoaders as a context to select a </code>LoggerRepository
* </code> within a J2EE container, such as Tomcat. Because the implementation
* of class loading can vary greatly between J2EE containers, this class is
* considered <bold>experimental</bold>. No guarantees are made that this
* class will work in every J2EE container, and the implementation of this
* class may change greatly in the future. While it useful, it is primarily
* provided as a "point of discussion" for creating other repository
* selectors for specific J2EE containers. It has been tested primarily
* with Tomcat 4.0.x.
*
* <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" repository selector. Each classloader provides
* a unique 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.x.x and
* probably a multitude of others. However, Tomcat 4.x.x is the only container
* currently tested.</p>
*
* @author Jacob Kjome <ho...@visi.com>
* @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());
// key: current thread's ContextClassLoader,
// value: Log4jCRS instance
final private static Map crsMap =
Collections.synchronizedMap(new WeakHashMap());
// static initializer
static {
// This should only ever be called once in this class' entire existence.
// The only way to override it is to pass in the exact same guard object
// that we set here...which is next to impossible unless we store a
// reference to it. We will not do that unless it becomes a requirement
// in the future.
Object guard = new Object();
LogManager.setRepositorySelector(new ContextClassLoaderSelector(), guard);
}
/**
* default constructor
*/
public ContextClassLoaderSelector() {}
/**
* This provides access to the hierarchy object which is associated with
* the current webapp.
*
* @param the contextual classloader of the current webapp.
*
* @return the Hierarchy instance associated with the current webapp.
* May be null.
*/
public static Hierarchy getHierarchy(ClassLoader cl) {
return (Hierarchy) hierMap.get(cl);
}
/**
* This provides access to the ContextClassLoaderSelector object which
* was used to create the hierarchy for the current web-application.
* This can be used to remove the instances of both the hierarchy and
* the Log4jCRS objects at application shutdown.
*
* @param the contextual classloader of the current webapp.
*
* @return the ContextClassLoaderSelector instance associated with the
* current webapp. May be null.
*/
public static ContextClassLoaderSelector getCRS(ClassLoader cl) {
return (ContextClassLoaderSelector) crsMap.get(cl);
}
/**
* This provides access to the LoggerRepository. Generally, this method
* isn't called directly by the developer, rather, it is called
* automatically by Log4j because setRepositorySelector was called on the
* LogManager with an instance of this class.
*
* <p>the returned value is guaranteed to be non-null</p>
*
* @return the LoggerRepository, or Hierachy, associated with the current
* webapp. Guaranteed to be non-null.
*/
public LoggerRepository getLoggerRepository() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Hierarchy hierarchy = (Hierarchy) hierMap.get(cl);
if(hierarchy == null) {
hierarchy = setGetLoggerRepository(cl);
}
return hierarchy;
}
/**
* This generates the new hierachy and stores the instances of both the
* hierarchy and ContextClassLoaderSelector in Maps in order to make
* them retrievable at a later date by each individual webapp.
*
* @param the contextual classloader of the current webapp.
*
* @return a generated Hierarchy instance
*/
private Hierarchy setGetLoggerRepository(ClassLoader cl) {
Hierarchy hierarchy = new Hierarchy(new RootCategory((Level) Level.DEBUG));
hierMap.put(cl, hierarchy);
crsMap.put(cl, this);
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 void initLoggerRepository() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
setGetLoggerRepository(cl);
}
/**
* The Container should remove the entry when the webapp is removed or
* restarted. In this case, it is controllable via each webapp.
*
* @param the contextual classloader of the current webapp.
*/
public void remove(ClassLoader cl) {
hierMap.remove(cl);
crsMap.remove(cl);
}
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>
RE: cvs commit: jakarta-log4j/src/java/org/apache/log4j/selectors ContextClassLoaderSelector.java
Posted by mw...@apache.org.
So, I checked in Jacob's selector, just renamed. I added a
warning/caveat/experimental message at the start of the javadoc. If anyone
feels that I mis-worded/mis-represented it, please feel free to modify it.
Still to do:
- Modify build.xml to build an experimental selectors.jar.
- Add a package.html to the selectors package explaining their purpose and
experimental nature.
- Add the JNDIRS example to the selectors package.
-Mark
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>