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 Ceki Gülcü <ce...@qos.ch> on 2003/02/14 16:32:26 UTC
Re: cvs commit:
jakarta-log4j-sandbox/src/java/org/apache/log4j/selector
ContextClassLoaderSelector.java
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: log4j-dev-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: log4j-dev-help@jakarta.apache.org
--
Ceki
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-dev-help@jakarta.apache.org
Re[2]: cvs commit:
jakarta-log4j-sandbox/src/java/org/apache/log4j/selector
ContextClassLoaderSelector.java
Posted by Ceki Gülcü <ce...@qos.ch>.
The promised patches are included as attachments.
Please also note the page http://qos.ch/containers/sc.html moved to
http://qos.ch/logging/sc.html
At 16:08 15.02.2003 +0100, you wrote:
>Hi Jake,
>
>Nothing prevents you from instantiating a ContextClassLoaderSelector
>instance in InitContextListener. I'll supply the patch in the next few minutes.
>
>At 11:03 14.02.2003 -0600, you wrote:
>>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();
>>
>
>--
>Ceki
Re[2]: cvs commit:
jakarta-log4j-sandbox/src/java/org/apache/log4j/selector
ContextClassLoaderSelector.java
Posted by Ceki Gülcü <ce...@qos.ch>.
Hi Jake,
Nothing prevents you from instantiating a ContextClassLoaderSelector
instance in InitContextListener. I'll supply the patch in the next few minutes.
At 11:03 14.02.2003 -0600, you wrote:
>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: log4j-dev-unsubscribe@jakarta.apache.org
> >>For additional commands, e-mail: log4j-dev-help@jakarta.apache.org
>
>CG> --
>CG> Ceki
>
>
>CG> ---------------------------------------------------------------------
>CG> To unsubscribe, e-mail: log4j-dev-unsubscribe@jakarta.apache.org
>CG> For additional commands, e-mail: log4j-dev-help@jakarta.apache.org
>
>
>
>--
>Best regards,
> Jacob mailto:hoju@visi.com
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: log4j-dev-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: log4j-dev-help@jakarta.apache.org
--
Ceki
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-dev-help@jakarta.apache.org
Re[2]: cvs commit: jakarta-log4j-sandbox/src/java/org/apache/log4j/selector ContextClassLoaderSelector.java
Posted by Jacob Kjome <ho...@visi.com>.
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: log4j-dev-unsubscribe@jakarta.apache.org
>>For additional commands, e-mail: log4j-dev-help@jakarta.apache.org
CG> --
CG> Ceki
CG> ---------------------------------------------------------------------
CG> To unsubscribe, e-mail: log4j-dev-unsubscribe@jakarta.apache.org
CG> For additional commands, e-mail: log4j-dev-help@jakarta.apache.org
--
Best regards,
Jacob mailto:hoju@visi.com
---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-dev-help@jakarta.apache.org