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>