logging-log4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mwom...@apache.org
Subject cvs commit: jakarta-log4j-sandbox/src/java/org/apache/log4j/servlet ConfigurationServlet.java CookieMDCFilter.java InitContextListener.java InitServlet.java
Date Tue, 04 Feb 2003 06:28:16 GMT
mwomack     2003/02/03 22:28:16

  Added:       .        HOWTOBUILD.txt LICENSE.txt README.txt
                        build.properties.sample build.xml
               src/java/org/apache/log4j/filter LevelMatchFilter.java
                        LevelRangeMatchFilter.java MDCMatchFilter.java
                        MatchFilterBase.java MessageMatchFilter.java
                        NDCMatchFilter.java SetLocationInfoFilter.java
               src/java/org/apache/log4j/selector
                        ContextClassLoaderSelector.java
               src/java/org/apache/log4j/servlet ConfigurationServlet.java
                        CookieMDCFilter.java InitContextListener.java
                        InitServlet.java
  Log:
  Initial check in for log4j-sandbox cvs repository.  Contains filter, selector, and servlet packages.
  
  Revision  Changes    Path
  1.1                  jakarta-log4j-sandbox/HOWTOBUILD.txt
  
  Index: HOWTOBUILD.txt
  ===================================================================
  [placeholder that will describe the steps to set up the build environment and 
  compile the code]
  
  
  1.1                  jakarta-log4j-sandbox/LICENSE.txt
  
  Index: LICENSE.txt
  ===================================================================
  /*
   * ============================================================================
   *                   The Apache Software License, Version 1.1
   * ============================================================================
   * 
   *    Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
   * 
   * Redistribution and use in source and binary forms, with or without modifica-
   * tion, are permitted provided that the following conditions are met:
   * 
   * 1. Redistributions of  source code must  retain the above copyright  notice,
   *    this list of conditions and the following disclaimer.
   * 
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   * 
   * 3. The end-user documentation included with the redistribution, if any, must
   *    include  the following  acknowledgment:  "This product includes  software
   *    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
   *    Alternately, this  acknowledgment may  appear in the software itself,  if
   *    and wherever such third-party acknowledgments normally appear.
   * 
   * 4. The names "log4j" and  "Apache Software Foundation"  must not be used to
   *    endorse  or promote  products derived  from this  software without  prior
   *    written permission. For written permission, please contact
   *    apache@apache.org.
   * 
   * 5. Products  derived from this software may not  be called "Apache", nor may
   *    "Apache" appear  in their name,  without prior written permission  of the
   *    Apache Software Foundation.
   * 
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   * FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   * APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   * DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   * OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   * ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   * (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   * 
   * This software  consists of voluntary contributions made  by many individuals
   * on  behalf of the Apache Software  Foundation.  For more  information on the 
   * Apache Software Foundation, please see <http://www.apache.org/>.
   *
   */
  
  
  
  1.1                  jakarta-log4j-sandbox/README.txt
  
  Index: README.txt
  ===================================================================
  Log4j sandbox is a collection of useful code and classes that extend or support
  the use of log4j.  Many of the classes are ready for immediate use in your
  log4j environment.  Some are considered "experimental" and should be used with
  that knowledge in mind.  And others serve as useful examples or "springboards"
  for adding features to your own code.
  
  These classes are maintained and packaged separate from the core log4j release,
  but as classes "prove" themselves worthy and evolve, they may be moved into the
  core log4j release.
  
  If you have any suggestions, improvements, patches, or new submissions you
  would like to contribute to the log4j-sandbox, please post a message to the
  log4j-dev@apache.org email list.
  
  Please see the HOWTOBUILD.txt file for information about how to compile and
  build the log4j-sandbox project.
  
  Enjoy!
  
  
  1.1                  jakarta-log4j-sandbox/build.properties.sample
  
  Index: build.properties.sample
  ===================================================================
  # This property file is used by build.xml to located resource needed to build
  # the log4j-sandbox code.  Duplicate this file and rename to "build.properties"
  # and locate it in the same directory as the build.xml file.  Then modify the
  # properties below to reflect the locations of the resources in your
  # development environment.
  
  # log4j jar REQUIRED
  log4j.jar=./build-libs/log4j-1.2.7.jar
  
  # Servlet 2.3 OPTIONAL; required to build the org.apache.log4j.servlet package
  servlet.jar=./build-libs/servlet.jar
  
  # Checkstyle jar OPTIONAL; required to execute checkstyle target
  checkstyle.jar=d:/development/code-opensource/other/checkstyle-2.4/checkstyle-all-2.4.jar
  
  
  
  
  1.1                  jakarta-log4j-sandbox/build.xml
  
  Index: build.xml
  ===================================================================
  
  <!-- This file is an ANT build script. ANT is a Java based build tool. -->
  <!-- It is availale from http://ant.apache.org                         -->
  
  
  <!-- ================================================================= -->
  <!-- NOTE: all directories are relative to jakarta-log4j-sandbox/      -->
  <!-- the parent of build/                                              -->
  <!-- ================================================================= -->
  <project name="log4j" default="build" basedir="." >
  
  
    <!-- The build.properties file defines the parth to local jar files -->
    <property file="build.properties"/>
  
    <property name="version" value="0.1alpha"/>
  
    <!-- The base directory relative to which most targets are built -->
    <property name="base" value="."/>
  
    <!-- The directory where source files are stored. -->
    <property name="java.source.dir" value="./src/java/"/>
  
    <property name="build.home" value="./build"/>
    
    <!-- Destination for compiled files -->
    <property name="javac.dest" value="${build.home}/classes"/>
  
    <!-- Destination for generated jar files -->
    <property name="jar.dest" value="${build.home}/lib"/>
  
    <!-- Destination for documentation files -->
    <property name="docs.dest" value="${build.home}/docs"/>
  
    <!-- Destination for javadoc generated files -->
    <property name="javadoc.dest" value="${build.home}/docs/api"/>
  
    <!-- The jar file that the jar task will generate -->
    <property name="log4j-sandbox.jar" value="log4j-sandbox-${version}.jar"/>
  
    <!-- Construct compile classpath -->
    <path id="compile.classpath">
      <pathelement location="${build.home}/classes"/>
      <pathelement location="${log4j.jar}"/>
      <pathelement location="${servlet.jar}"/>
    </path>
  
  
    <!-- ================================================================= -->
    <!-- Default target                                                    -->
    <!-- ================================================================= -->
  
    <target name="usage">
      <echo>
  
      These are the targets supported by this ANT build scpript:
  
      build   - compile all project files, if a certain library is missing,
  	          then the compilation of its dependents are skipped.
  
      javadoc - build project javadoc files
  
      jar     - build log4j-core and log4j jar files
      
      </echo>
    </target>
  
  	<target name="servlet23Check">
  		<available classname="javax.servlet.Filter" property="servlet23-present">
  			<classpath>
  				<pathelement location="${servlet.jar}"/>
  			</classpath>
  		</available>
  	</target>
    
    <target name="servlet" depends="servlet23Check" if="servlet23-present">
      <echo message="Servlet 2.3 is present."/>
    </target>
  
    <target name="init">
      <tstamp />
    </target>
  
    <target name="build" depends="init, build.core, build.servlet"/>
  
  	<target name="build.core" depends="init">
  		<mkdir dir="${javac.dest}" />
  		<javac srcdir="${java.source.dir}"
  			     destdir="${javac.dest}"
  			     includes="**/*.java"
  			     excludes="**/servlet/*.java"
  			     deprecation="${deprecation}"
  			     debug="on">
        <classpath refid="compile.classpath"/>
      </javac>
    </target>
  
    <target name="build.servlet" depends="init, servlet" if="servlet23-present">
      <javac deprecation="${deprecation}"
             srcdir="${java.source.dir}"
  	         destdir="${javac.dest}"
  	         includes="**/servlet/*.java">
  			<classpath refid="compile.classpath"/>
      </javac>
    </target>
  
    <!-- ================================================================= -->
    <!-- Remove all build generated files.                                 -->
    <!-- ================================================================= -->
    <target name="clean" depends="init">
      <delete dir="${build.home}" />
    </target>
  
    <!-- ================================================================= -->
    <!-- Runs checkstyle. Available from http://checkstyle.sf.net          -->
    <!-- ================================================================= -->
    <target name="checkstyle" depends="init">
      <taskdef resource="checkstyletask.properties"
               classpath="${checkstyle.jar}"/>
  
  		<property name="checkstyle.lcurly.method" value="nlow" />
  		<property name="checkstyle.lcurly.type" value="nlow" />
  		<property name="checkstyle.lcurly.other" value="nlow" />
  		<property name="checkstyle.maxmethodlen" value="500" />
  		<property name="checkstyle.maxconstructorlen" value="500" />
  		<property name="checkstyle.ignore.public.in.interface" value="true" />
  		
      <!-- by default checkstyle supports the Sun coding standard. -->
      <checkstyle>
        <fileset dir="src/java/org/apache/log4j/" includes="**/*.java"/>
      </checkstyle>
    </target>
  
    <!-- ================================================================= -->
    <!-- Actual work is done in the dependencies.                         -->
    <!-- ================================================================= -->
    <target name="jar" depends="log4j-sandbox.jar">
    </target>
  
   <!-- ================================================================= -->
   <!-- Create log4j-sandbox.jar, excluding tests and other odds and ends.        -->
   <!-- ================================================================= -->
    <target name="log4j-sandbox.jar" depends="build">
      <mkdir dir="${jar.dest}"/>
  		<delete>
        <fileset dir="${jar.dest}">
  				<include name="${log4j-sandbox.jar}"/>
        </fileset>
      </delete>
  
      <jar jarfile="${jar.dest}/${log4j-sandbox.jar}"
           basedir="${javac.dest}"
           includes="**/*.class">
  			<manifest>
  				<attribute name="Manifest-version" value="1.0"/>
  					<section name="org/apache/log4j/">
  					  <attribute name="Implementation-Title" value="log4j-sandbox"/>
  					  <attribute name="Implementation-Version" value="${version}"/> 
  					  <attribute name="Implementation-Vendor" value="Apache Software Foundation"/>
  					</section>
        </manifest>
      </jar>
    </target>
  
  
    <!-- ================================================================= -->
    <!-- This target builds the javadoc files.                             -->
    <!-- ================================================================= -->
    <target name="javadoc" depends="init" unless="env.NO_JAVADOC">
  
      <mkdir dir="${javadoc.dest}" />
  
      <javadoc sourcepath="${java.source.dir}"
  						 destdir="${javadoc.dest}"
  	           packagenames="org.apache.log4j.filter,
  	                         org.apache.log4j.selector,
  	                         org.apache.log4j.servlet"
  						 version="true"
  						 protected="true"
  						 author="true"
  						 use="true"
  						 overview="${docs.dest}/overview.html"
  						 doctitle="log4j version ${version}&lt;br&gt;API Specification"
  						 windowtitle="Log4j-sandbox Version ${version}"
  						     header="&lt;b&gt;Log4j-sandbox ${version}&lt;/b&gt;"
  						 bottom="Copyright 2000-2003 Apache Software Foundation.">
  
  			<link href="http://java.sun.com/products/jdk/1.3/docs/api"/>
  			<link href="http://java.sun.com/j2ee/sdk_1.3/techdocs/api/"/>
        <classpath refid="compile.classpath"/>
      </javadoc>
    </target>
  
  </project>
  
  
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/filter/LevelMatchFilter.java
  
  Index: LevelMatchFilter.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.filter;
  
  import org.apache.log4j.Level;
  import org.apache.log4j.spi.LoggingEvent;
  import org.apache.log4j.helpers.OptionConverter;
  
  /**
    LevelMatchFilter is a very simple filter that matches a
    configured log level against the log level of a logging event.
    If they levels are the same, then the match() method returns
    true, else it returns false.
    
    <p>If a LevelMatchFilter is not configured with a level to match,
    then the canMatch() method will return false.
    
    <p>For more information about how the logging event will be
    passed to the appender for reporting, please see 
    the {@link MatchFilterBase} class.
    
    @author Ceki G&uuml;lc&uuml;
    @author Mark Womack;
  
    @since 1.3
  */
  public class LevelMatchFilter extends MatchFilterBase {
  
    /**
      The level to match against. */
    Level levelToMatch;
  
    /**
      Sets the level to match against. */
    public void setLevelToMatch(String level) {
      levelToMatch = OptionConverter.toLevel(level, null);
    }
    
    /**
      Gets the level that will be matched against. */
    public String getLevelToMatch() {
      return levelToMatch == null ? null : levelToMatch.toString();
    }
  
    /**
      Overrides the implementation from the base class to return
      false if the levelToMatch has not been configured. */
    protected boolean canMatch() {
      return (levelToMatch != null);
    }
    /**
      Returns true if the levelToMatch matches the level of the
      logging event. */
    protected boolean match(LoggingEvent event) {
      return (levelToMatch.equals(event.getLevel()));
    }
  }
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/filter/LevelRangeMatchFilter.java
  
  Index: LevelRangeMatchFilter.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.filter;
  
  import org.apache.log4j.Level;
  import org.apache.log4j.spi.LoggingEvent;
  
  /**
    LevelMatchFilter is a very simple filter based on level matching, 
    which can be used to reject logging events with levels outside a 
    certain range. If they levels are within the range, then the 
    match() method returns true, else it returns false.
      
    <p>If <code>LevelMin</code> is not defined, then there is no
    minimum acceptable level (ie a level is never rejected for
    being too "low"/unimportant).  If <code>LevelMax</code> is not
    defined, then there is no maximum acceptable level (ie a
    level is never rejected for being too "high"/important).
    
    <p>Refer to the {@link
    org.apache.log4j.AppenderSkeleton#setThreshold setThreshold} method
    available to <code>all</code> appenders extending {@link
    org.apache.log4j.AppenderSkeleton} for a more convenient way to
    filter out events by level.
  
    <p>For more information about how the logging event will be
    passed to the appender for reporting, please see 
    the {@link MatchFilterBase} class.
    
    @author Simon Kitching
    @author based on code by Ceki G&uuml;lc&uuml; 
    @author Mark Womack;
  
    @since 1.3
  */
  public class LevelRangeMatchFilter extends MatchFilterBase {
  
    /**
      Minimum level to match against. */
    Level levelMin;
    
    /**
      Maximum level to match against. */
    Level levelMax;
  
    /**
      Set the <code>LevelMax</code> option. */
    public void setLevelMax(Level levelMax) {
      this.levelMax = levelMax;
    }
  
    /**
      Get the value of the <code>LevelMax</code> option. */
    public Level getLevelMax() {
      return levelMax;
    }
  
    /**
      Set the <code>LevelMin</code> option. */
    public void setLevelMin(Level levelMin) {
      this.levelMin = levelMin;
    }
  
    /**
      Get the value of the <code>LevelMin</code> option. */
    public Level getLevelMin() {
      return levelMin;
    }
    
    /**
      Returns true if the the level of the logging event is in
      the configured range of <code>LevelMin</code> and
      <code>LevelMax</code>. */
    protected boolean match(LoggingEvent event) {
      if(this.levelMin != null) {
        if (event.getLevel().isGreaterOrEqual(levelMin) == false) {
          // level of event is less than minimum
          return false;
        }
      }
  
      if(this.levelMax != null) {
        if (event.getLevel().toInt() > levelMax.toInt()) {
          // level of event is greater than maximum
          // Alas, there is no Level.isGreater method. and using
          // a combo of isGreaterOrEqual && !Equal seems worse than
          // checking the int values of the level objects..
          return false;
        }
      }
  
      // return true match
      return true;
    }
  }
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/filter/MDCMatchFilter.java
  
  Index: MDCMatchFilter.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.filter;
  
  import org.apache.log4j.MDC;
  import org.apache.log4j.spi.Filter;
  import org.apache.log4j.spi.LoggingEvent;
  
  /**
    The MDCMatchFilter matches a configured value against the
    value of a configured key in the MDC of a logging event.
  
    <p>The filter admits three options <b>KeyToMatch</b>, 
    <b>ValueToMatch</b>, and <b>ExactMatch</b>.
    
    <p>The value of <b>KeyToMatch</b> property determines which
    key is used to match against in the MDC. The value of that
    key is used to test against the <b>ValueToMatch</b property.
    The <b>KeyToMatch</b> property must be set before this filter
    can function properly.
    
    <p>The value of <b>ValueToMatch</b> property determines the 
    string value to match against. If <b>ExactMatch</b> is set
    to true, a match will occur only when <b>ValueToMatch</b> exactly
    matches the MDC value of the logging event.  Otherwise, if the
    <b>ExactMatch</b> property is set to <code>false</code>, a match
    will occur if <b>ValueToMatch</b> is contained anywhere within the
    MDC value. The <b>ExactMatch</b> property is set to
    <code>false</code> by default.
    
    <p>Note that by default the value to match is set to
    <code>null</code> and will only match if the key is not contained
    or the value is null in the MDC.
  
    <p>For more information about how the logging event will be
    passed to the appender for reporting, please see 
    the {@link MatchFilterBase} class.
  
    @author Mark Womack
    
    @since 1.3
  */
  public class MDCMatchFilter extends MatchFilterBase {
    
    /**
      The key to match in the MDC of the LoggingEvent. */
    String keyToMatch;
    
    /**
      The value to match in the MDC value of the LoggingEvent. */
    String valueToMatch;
    
    /**
      Do we look for an exact match or just a "contains" match? */
    boolean exactMatch = false;
  
    /**
      Sets the key to match in the MDC of the LoggingEvent. */
    public void setKeyToMatch(String key) {
      keyToMatch = key;
    }
    
    /**
      Gets the key to match in the MDC of the LoggingEvent. */
    public String getKeyToMatch() {
      return keyToMatch;
    }
  
    /**
      Sets the value to match in the NDC value of the LoggingEvent. */
    public void setValueToMatch(String value) {
      valueToMatch = value;
    }
    
    /**
      Gets the value to match in the NDC value of the LoggingEvent. */
    public String getValueToMatch() {
      return valueToMatch;
    }
  
    /**
      Set to true if configured value must exactly match the MDC
      value of the LoggingEvent. Set to false if the configured
      value must only be contained in the MDC value of the
      LoggingEvent. Default is false. */
    public void setExactMatch(boolean exact) {
      exactMatch = exact;
    }
    
    public boolean getExactMatch() {
      return exactMatch;
    }
    
    protected boolean canMatch() {
      return (keyToMatch != null);
    }
    
    /**
      If <b>ExactMatch</b> is set to true, returns true only when
      <b>ValueToMatch</b> exactly matches the MDC value of the 
      logging event. If the <b>ExactMatch</b> property
      is set to <code>false</code>, returns true when 
      <b>ValueToMatch</b> is contained anywhere within the MDC
      value. Otherwise, false is returned. */
    protected boolean match(LoggingEvent event) {
        
      // get the mdc value for the key from the event
      // use the toString() value of the value object
      Object mdcObject = event.getMDC(keyToMatch);
      String mdcValue;
      if (mdcObject != null) {
        mdcValue = mdcObject.toString();
      } else {
        mdcValue = null;
      }
      
      // check for a match
      if (mdcValue == null) {
        if (valueToMatch == null) {
          return true;
        } else {
          return false;
        }
      } else {
        if (valueToMatch != null) {
          if (exactMatch) {
            return mdcValue.equals(valueToMatch);
          } else {
            return (mdcValue.indexOf(valueToMatch) != -1);
          }
        } else {
          return false;
        }
      }
    }
  }
  
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/filter/MatchFilterBase.java
  
  Index: MatchFilterBase.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.filter;
  
  import org.apache.log4j.spi.Filter;
  import org.apache.log4j.spi.LoggingEvent;
  import org.apache.log4j.helpers.LogLog;
  
  /**
    This is the abstract base class for many useful filters implemented
    in the log4j.filter package. It extends the base {@link Filter} 
    class to allow a different return value for a match or a nomatch. 
    What is specifically tested for matching is implemented in specific
    subclasses.
    
    <p>Properties matchReturnValue and noMatchReturnValue can be
    set programmitcally or from a configuration file. They set
    the value that will be returned when there is match or when there
    is not a match, respectively.  By default matchReturnValue is
    set to Filter.ACCEPT and noMatchReturnValue is set to Filter.DENY.
    
    <p>In addition to being able to set the match and nomatch return
    values directly, one can instead use the chainPolicy property.
    Log4j allows for filters to be chained together, each filter
    deciding whether the logging event should be accepted, denied,
    or passed on to the next filter.  However, for the event to passed
    to the next filter, one of the return values must be set to 
    Filter.NEUTRAL. One can use chainPolicy to accomplish this, passing
    it one of the four valid policies: ACCEPT_ON_MATCH (match = 
    Filter.ACCEPT/nomatch = Filter.NEUTRAL), DENY_ON_MATCH (match = 
    Filter.DENY/nomatch = Filter.NEUTRAL), ACCEPT_ON_NOMATCH
    (match = Filter.NEUTRAL/nomatch = Filter.ACCEPT), and 
    DENY_ON_NOMATCH (match = Filter.NEUTRAL/nomatch = Filter.DENY).
    Which policy is used can be set programmatically or from a
    configuration file.  If more than one filter will be attached
    to a single appender, all but the last one should probably be
    configured via the chainPolicy property.
    
    <p>Subclasses are required to implement the match() method. The
    implementation should test for a match, returning true if there
    is a match and false if there is nomatch.  Subclasses can also
    implement their own version of the canMatch() method, but should
    only do so if they will be unable to perform the match code
    due to misconfiguration.  By default, canMatch() will always
    return true.
    
    <p>Developers are encouraged to extend this base class when
    implementing their own filters. For examples of how
    to use and extend this base class, please see the various 
    filters implemented in the log4j.filters package.
    
    @author Mark Womack
    
    @since 1.3
  */
  public abstract class MatchFilterBase extends Filter {
    
    /** Chain policy constant = AcceptOnMatch. */
    public static final String ACCEPT_ON_MATCH    = "AcceptOnMatch";
  
    /** Chain policy constant = DenyOnMatch. */
    public static final String DENY_ON_MATCH      = "DenyOnMatch";
  
    /** Chain policy constant = AcceptOnNomatch. */
    public static final String ACCEPT_ON_NOMATCH  = "AcceptOnNomatch";
  
    /** Chain policy constant = DenyOnNomatch. */
    public static final String DENY_ON_NOMATCH    = "DenyOnNomatch";
  
    /** Chain policy constant = UnknownPolicy. */
    public static final String UNKNOWN_POLICY     = "UnknownPolicy";
    
    /**
      The value that will be returned upon a successful match. */
    protected int matchReturnValue = ACCEPT;
    
    /** 
      The value that will be returned upon an unsuccessful match */
    protected int noMatchReturnValue = DENY;
    
    /**
      Set the value to return upon a successful match. Valid
      string values are "ACCEPT", "DENY", and "NEUTRAL". */
    public void setMatchReturnValue(String filterReturnValue) {
      if (filterReturnValue.equalsIgnoreCase("accept")) {
        matchReturnValue = ACCEPT;
      } else if (filterReturnValue.equalsIgnoreCase("deny")) {
        matchReturnValue = DENY;
      } else if (filterReturnValue.equalsIgnoreCase("neutral")) {
        matchReturnValue = NEUTRAL;
      } else {
        LogLog.error("invalid matchReturnValue: " + filterReturnValue);
      }
    }
      
    /**
      Gets the value that will be returned upon a successful
      match. */
    public String getMatchReturnValue() {
      if (matchReturnValue == ACCEPT)
        return "accept";
      else if (matchReturnValue == DENY)
        return "deny";
      else if (matchReturnValue == NEUTRAL)
        return "neutral";
      else
        return "unknown"; // this one should never happen
    }
  
    /**
      Set the value to return upon a successful match. Valid
      string values are "ACCEPT", "DENY", and "NEUTRAL". */
    public void setNoMatchReturnValue(String filterReturnValue) {
      if (filterReturnValue.equalsIgnoreCase("accept")) {
        noMatchReturnValue = ACCEPT;
      } else if (filterReturnValue.equalsIgnoreCase("deny")) {
        noMatchReturnValue = DENY;
      } else if (filterReturnValue.equalsIgnoreCase("neutral")) {
        noMatchReturnValue = NEUTRAL;
      } else {
        LogLog.error("invalid noMatchReturnValue: " + filterReturnValue);
      }
    }
      
    /**
      Gets the value that will be returned upon an unsuccessful
      match. */
    public String getNoMatchReturnValue() {
      if (noMatchReturnValue == ACCEPT)
        return "accept";
      else if (noMatchReturnValue == DENY)
        return "deny";
      else if (noMatchReturnValue == NEUTRAL)
        return "neutral";
      else
        return "unknown"; // this one should never happen
    }
    
    /**
      Sets the match and nomatch return values based on a "policy"
      string.  Valid values for the policy string are defined as
      constants for this class: ACCEPT_ON_MATCH, DENY_ON_MATCH, 
      ACCEPT_ON_NOMATCH, DENY_ON_NOMATCH. */
    public void setChainPolicy(String policyStr) {
      if (policyStr.equalsIgnoreCase(ACCEPT_ON_MATCH)) {
        matchReturnValue = ACCEPT;
        noMatchReturnValue = NEUTRAL;
      } else if (policyStr.equalsIgnoreCase(DENY_ON_MATCH)) {
        matchReturnValue = DENY;
        noMatchReturnValue = NEUTRAL;
      } else if (policyStr.equalsIgnoreCase(ACCEPT_ON_NOMATCH)) {
        matchReturnValue = NEUTRAL;
        noMatchReturnValue = ACCEPT;
      } else if (policyStr.equalsIgnoreCase(DENY_ON_NOMATCH)) {
        matchReturnValue = NEUTRAL;
        noMatchReturnValue = DENY;
      } else {
        LogLog.error("invalid chainPolicy: " + policyStr);
      }
    }
  
    /**
      Gets the chain policy string value that matches the current
      settings of matchReturnValue and noMatchReturn value. If the
      current values do not match a known policy setting, then the
      value of UNKNOWN_PLOCY is returned.
      Valid return values for the policy string are defined as
      constants for this class: ACCEPT_ON_MATCH, DENY_ON_MATCH, 
      ACCEPT_ON_NOMATCH, DENY_ON_NOMATCH, and UNKNOWN_POLICY. */
    public String getChainPolicy() {
      if (matchReturnValue == ACCEPT && noMatchReturnValue == NEUTRAL) {
        return ACCEPT_ON_MATCH;
      } else if (matchReturnValue == DENY && noMatchReturnValue == NEUTRAL) {
        return DENY_ON_MATCH;
      } else if (matchReturnValue == NEUTRAL && noMatchReturnValue == ACCEPT) {
        return ACCEPT_ON_NOMATCH;
      } else if (matchReturnValue == NEUTRAL && noMatchReturnValue == DENY) {
        return DENY_ON_NOMATCH;
      } else {
        return UNKNOWN_POLICY;
      }
    }
   
    /**
      Implementation that calls the canMatch() and match() methods
      of subclasses. If a match test can be performed (canMatch()
      returned true), then either the configured matchReturnValue
      or noMatchReturnValue will be returned. If no match test can
      be performed (canMatch() returned false), then Filter.NEUTRAL
      is returned. */
    public int decide(LoggingEvent event) {
      if (canMatch()) {
        if (match(event)) {
          return matchReturnValue;
        } else {
          return noMatchReturnValue;
        }
      }
      else
        return NEUTRAL;
    }
  
    /**
      Subclasses can override this method with their own version if
      it is possible that no match test can/should be performed due
      to a misconfiguration. This method should return true if a match
      test can be performed, and false if it cannot be performed. The
      default version always returns true. */
    protected boolean canMatch() {
      return true;
    }
    
    /**
      Subclasses must implement this method to perform the specific
      match test that they require. This method should return true
      if a match is made, and false if no match is made. */
    abstract protected boolean match(LoggingEvent event);
  }
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/filter/MessageMatchFilter.java
  
  Index: MessageMatchFilter.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.filter;
  
  import org.apache.log4j.Level;
  import org.apache.log4j.spi.LoggingEvent;
  import org.apache.log4j.helpers.OptionConverter;
  
  /**
    MessageMatchFilter is a very simple filter that matches a 
    configured value against the message value of a logging event.
    
    <p>The filter admits two options <b>MessageToMatch</b> and
    <b>ExactMatch</b>.
    
    <p>As the name indicates, the value of <b>MessageToMatch</b> property
    determines the string value to match. If <b>ExactMatch</b> is set
    to true, a match will occur only when <b>MessageToMatch</b> exactly
    matches the message value of the logging event.  Otherwise, if the
    <b>ExactMatch</b> property is set to <code>false</code>, a match
    will occur when <b>MessageToMatch</b> is contained anywhere within the
    message value. The <b>ExactMatch</b> property is set to
    <code>false</code> by default.
    
    <p>Note that by default <b>MessageToMatch</b> is set to
    <code>null</code> and will only match a null message.
  
    <p>For more information about how the logging event will be
    passed to the appender for reporting, please see 
    the {@link MatchFilterBase} class.
  
    @author Mark Womack;
  
    @since 1.3
  */
  public class MessageMatchFilter extends MatchFilterBase {
  
    /**
      The message match against. */
    String messageToMatch;
  
    /**
      Do we look for an exact match or just a "contains" match? */
    boolean exactMatch = false;
  
    /**
      Sets the string to match against the logging event message. */
    public void setMessageToMatch(String _message) {
      messageToMatch = _message;
    }
    
    public String getMessageToMatch() {
      return messageToMatch;
    }
  
    /**
      Set to true if configured value must exactly match the message
      value of the LoggingEvent. Set to false if the configured
      value must only be contained in the message value of the
      LoggingEvent. Default is false. */
    public void setExactMatch(boolean exact) {
      exactMatch = exact;
    }
    
    public boolean getExactMatch() {
      return exactMatch;
    }
    
    /**
      If <b>ExactMatch</b> is set to true, returns true only when
      <b>MessageToMatch</b> exactly matches the message value of the 
      logging event. If the <b>ExactMatch</b> property
      is set to <code>false</code>, returns true when 
      <b>MessageToMatch</b> is contained anywhere within the message
      value. Otherwise, false is returned. */
    protected boolean match(LoggingEvent event) {
      String msg = event.getRenderedMessage();
      if (msg == null) {
        return (messageToMatch == null);
      } else {
        if (messageToMatch != null) {
          if (exactMatch) {
            return messageToMatch.equals(msg);
          } else {
            return (msg.indexOf(messageToMatch) != -1);
          }
        }
      }
      
      return false;
    }
  }
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/filter/NDCMatchFilter.java
  
  Index: NDCMatchFilter.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.filter;
  
  import org.apache.log4j.NDC;
  import org.apache.log4j.spi.Filter;
  import org.apache.log4j.spi.LoggingEvent;
  import org.apache.log4j.helpers.OptionConverter;
  
  /**
    The NDCMatchFilter matches a configured value against the
    NDC value of a logging event.
    
    <p>The filter admits two options <b>ValueToMatch</b> and
    <b>ExactMatch</b>.
    
    <p>As the name indicates, the value of <b>ValueToMatch</b> property
    determines the string value to match. If <b>ExactMatch</b> is set
    to true, a match will occur only when <b>ValueToMatch</b> exactly
    matches the NDC value of the logging event.  Otherwise, if the
    <b>ExactMatch</b> property is set to <code>false</code>, a match
    will occur when <b>ValueToMatch</b> is contained anywhere within the
    NDC value. The <b>ExactMatch</b> property is set to
    <code>false</code> by default.
    
    <p>Note that by default <b>ValueToMatch</b> is set to
    <code>null</code> and will only match an empty NDC stack.
  
    <p>For more information about how the logging event will be
    passed to the appender for reporting, please see 
    the {@link MatchFilterBase} class.
  
    @author Mark Womack
    
    @since 1.3
  */
  public class NDCMatchFilter extends MatchFilterBase {
    
    /**
      The value to match in the NDC value of the LoggingEvent. */
    String valueToMatch;
    
    /**
      Do we look for an exact match or just a "contains" match? */
    boolean exactMatch = false;
  
    /**
      Sets the value to match in the NDC value of the LoggingEvent. */
    public void setValueToMatch(String value) {
      valueToMatch = value;
    }
    
    /**
      Gets the value to match in the NDC value of the LoggingEvent. */
    public String getValueToMatch() {
      return valueToMatch;
    }
  
    /**
      Set to true if configured value must exactly match the NDC
      value of the LoggingEvent. Set to false if the configured
      value must only be contained in the NDC value of the
      LoggingEvent. Default is false. */
    public void setExactMatch(boolean exact) {
      exactMatch = exact;
    }
    
    public boolean getExactMatch() {
      return exactMatch;
    }
    
    /**
      If <b>ExactMatch</b> is set to true, returns true only when
      <b>ValueToMatch</b> exactly matches the NDC value of the 
      logging event. If the <b>ExactMatch</b> property
      is set to <code>false</code>, returns true when 
      <b>ValueToMatch</b> is contained anywhere within the NDC
      value. Otherwise, false is returned. */
    protected boolean match(LoggingEvent event) {
      
      // get the ndc value for the event
      String eventNDC = event.getNDC();
      
      // check for a match
          
      // if the NDC stack is empty
      if (eventNDC == null) {
        // return true if are we matching a null
        if (valueToMatch == null) {
          return true;
        // else return false
        } else {
          return false;
        }
      } else {
        // try to match the configured non-null value
        if (valueToMatch != null) {
          if (exactMatch) {
            return eventNDC.equals(valueToMatch);
          } else {
            return (eventNDC.indexOf(valueToMatch) != -1);
          }
        // else the value to match is null, so return false
        } else {
          return false;
        }
      }
    }
  }
  
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/filter/SetLocationInfoFilter.java
  
  Index: SetLocationInfoFilter.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.filter;
  
  import org.apache.log4j.spi.Filter;
  import org.apache.log4j.spi.LoggingEvent;
  
  /**
    SetLocationInfoFilter is pass through filter that simply calls
    {@link LoggingEvent#getLocationInformation} method of every 
    LoggingEvent that is sent to it. After calling the method, it 
    returns {@link Filter#NEUTRAL} to send the event to the next 
    filter.
    
    <p><bold>Use of this filter is probably not typical.</bold>
    Its primary purpose is to increase throughput performance for 
    appenders like SocketAppender and SocketHubAppender that send
    logging events to remote clients. These appenders have the option 
    to set the location info for every event appended to them so that
    the client can see where the event was logged in the code. 
    However, resolving the location info for every event can be costly 
    performance-wise, and will reduce the number of events per second 
    that can be appended. This can affect performance in the 
    application that is logging the event. Chances are that one does 
    not want the location info for every event, but rather for a smaller
    set of events that are of interest.
    
    <p>SetLocationInfoFilter can be placed at the end of a filter
    chain configured for an appender. After the event has been 
    filtered through the chain, it will pass through the 
    SetLocationInfoFilter, thus setting the location info for just 
    that event (this assumes that the location info setting of the 
    appender has been set to false).  Using subclasses of the 
    MatchFilterBase class, one can configure the filter chain to 
    accept all events sent to the appender, while only setting the 
    location info for a select set of events. Please see the examples
    for information on how to do this.
    
    <p>Please review the available filters in the 
    org.apache.log4j.filters package. Most of these subclass the
    MatchFilterBase class and are easily configurable for use in
    log4j filter chains. 
    
    <p>(Note that any log4j filter can be used in an appender filter 
    chain, but it needs to support the return of the
    {@link Filter#NEUTRAL} value from its decide method.
    MatchFilterBase subclasses simply expose this functionality 
    directly as part of their configuration.)
    
    @author Mark Womack
    
    @since 1.3
  */
  public class SetLocationInfoFilter extends Filter {
    
    /**
      Sets the LocationInfo for the event and returns 
      {@link Filter#NEUTRAL} to pass the event to the next filter. */
    public int decide(LoggingEvent event) {
      event.getLocationInformation();
      return Filter.NEUTRAL;
    }
  }
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/selector/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.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 java.util.Collections;
  import java.util.Map;
  import java.util.WeakHashMap;
  
  /**
   * @author  Jacob Kjome 
   */
  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
        }
      }
    }
  
  }
  
  
  
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/servlet/ConfigurationServlet.java
  
  Index: ConfigurationServlet.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.servlet;
  
  import java.io.IOException;
  import java.io.PrintWriter;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.Enumeration;
  import java.util.Iterator;
  import java.util.List;
  
  import javax.servlet.ServletException;
  import javax.servlet.SingleThreadModel;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  import org.apache.log4j.Logger;
  import org.apache.log4j.LogManager;
  import org.apache.log4j.Level;
  
  
  /**
   * A servlet used to dynamically adjust package logging levels
   * while an application is running.  NOTE: This servlet is 
   * only aware of pre-configured packages and packages that contain objects 
   * that have logged at least one message since application startup.
   *
   * @author <a href="mailto:lebirdzell@yahoo.com">Luther E. Birdzell</a>
   * @since 1.3
   */
  public class ConfigurationServlet extends HttpServlet implements SingleThreadModel 
  {
      /**
       * The response content type: text/html
       */
      public static final String CONTENT_TYPE = "text/html";
  
      /**
       * The root appender.
       */
      public static final String ROOT         = "Root";
  
      /**
       * The name of the class / package.
       */
      public static final String CLASS        = "CLASS";
      
      /**
       * The logging level.
       */
      public static final String PRIORITY     = "PRIORITY";
  
      /**
       * Print the status of all current <code>Logger</code>s and 
       * an option to change their respective logging levels.
       *
       * @param request a <code>HttpServletRequest</code> value
       * @param response a <code>HttpServletResponse</code> value
       * @exception ServletException if an error occurs
       * @exception IOException if an error occurs
       */
      public void doGet(HttpServletRequest request, HttpServletResponse response) 
          throws ServletException, IOException  
      {
          response.setContentType(CONTENT_TYPE);
  
          PrintWriter out        = response.getWriter();
          List        loggers    = getSortedLoggers();
          Logger      logger     = null;
          String      loggerName = null;
          int         loggerNum  = 0;
          
          // print title and header
          out.println("<html><head><title>Log4J Control Console</title></head>" +
                      "<body><H3>Log4J Control Console</H3>");
          out.println("<A href=\"" + request.getRequestURI() + "\">Refresh</A><HR>");
          out.println("<table width=\"50%\" border=\"1\">");
          out.println("<tr BGCOLOR=\"#5991A6\">");
          out.println("<td><FONT  COLOR=\"BLACK\" FACE=\"Helvetica\"><B>Class</B></FONT></td>");
          out.println("<td><FONT  COLOR=\"BLACK\" FACE=\"Helvetica\"><B>Priority</B></FONT></td>");
          out.println("</tr>");
  
          // print the root Logger
          displayLogger(out, Logger.getRootLogger(), loggerNum++, request);
  
          // print the rest of the loggers
          Iterator ii = loggers.iterator();
          while( ii.hasNext() ) 
          {
              displayLogger(out, (Logger) ii.next(), loggerNum++, request);
          }
  
          out.println("</table>");
          out.println("<FONT SIZE=\"-3\" COLOR=\"BLACK\" FACE=\"Helvetica\">* "+
                      "Inherits Priority From Parent.</FONT><BR>");
          out.println("<A href=\"" + request.getRequestURI() + "\">Refresh</A><HR>");
  
          // print set options
          out.println("<FORM action=\"" +  request.getRequestURI() + "\" method=\"post\">");
          out.println("<FONT  SIZE=\"+2\" COLOR=\"BLACK\" FACE=\"Helvetica\"><U>"+
                      "Set Log4J Option</U><BR><BR></FONT>");
          out.println("<FONT COLOR=\"BLACK\" FACE=\"Helvetica\">");
          out.println("<table width=\"50%\" border=\"1\">");
          out.println("<tr BGCOLOR=\"#5991A6\">");
          out.println("<td><FONT COLOR=\"BLACK\" "+
                      "FACE=\"Helvetica\"><B>Class Name:</B></FONT></td>");
          out.println("<td><SELECT name=\"CLASS\">");
          out.println("<OPTION VALUE=\"" + ROOT + "\">" + ROOT + "</OPTION>");
          
          ii = loggers.iterator();
          while( ii.hasNext() ) 
          {
              logger     = (Logger) ii.next();
              loggerName = (logger.getName().equals("") ? "Root" : logger.getName());
              out.println("<OPTION VALUE=\"" + loggerName + "\">" + loggerName + "</OPTION>");
          }
          out.println("</SELECT><BR></td></tr>");
  
          // print logging levels
          out.println("<tr BGCOLOR=\"#5991A6\"><td><FONT COLOR=\"BLACK\" "+
                      "FACE=\"Helvetica\"><B>Priority:</B></FONT></td>");
          out.println("<td><SELECT name=\"PRIORITY\">");
          out.println("<OPTION VALUE=\"" + Level.OFF   + "\">" + Level.OFF   + "</OPTION>");
          out.println("<OPTION VALUE=\"" + Level.FATAL + "\">" + Level.FATAL + "</OPTION>");
          out.println("<OPTION VALUE=\"" + Level.ERROR + "\">" + Level.ERROR + "</OPTION>");
          out.println("<OPTION VALUE=\"" + Level.WARN  + "\">" + Level.WARN  + "</OPTION>");
          out.println("<OPTION VALUE=\"" + Level.INFO  + "\">" + Level.INFO  + "</OPTION>");
          out.println("<OPTION VALUE=\"" + Level.DEBUG + "\">" + Level.DEBUG + "</OPTION>");
          out.println("<OPTION VALUE=\"" + Level.ALL   + "\">" + Level.ALL   + "</OPTION>");
          out.println("</SELECT><BR></td></tr>");
          out.println("</table></FONT>");
          out.println("<input type=\"submit\" name=\"Submit\" value=\"Set Option\"></FONT>");
          out.println("</FORM>");
          out.println("</body></html>");
  
          out.flush();
          out.close();
      }
  
      /**
       * Change a <code>Logger</code>'s level, then call <code>doGet</code>
       * to refresh the page.
       *
       * @param request a <code>HttpServletRequest</code> value
       * @param response a <code>HttpServletResponse</code> value
       * @exception ServletException if an error occurs
       * @exception java.io.IOException if an error occurs
       */
      public void doPost(HttpServletRequest request, HttpServletResponse response) 
          throws ServletException, IOException  
      {
          String className = (String) request.getParameter(CLASS);
          String priority  = (String) request.getParameter(PRIORITY);
  
          if (className != null) 
          {
              setClass(className, priority);
          }
      
          doGet(request, response);
      }
  
      // print a Logger and its current level
      private void displayLogger(PrintWriter out, Logger logger, 
                                 int row, HttpServletRequest request) 
      {
          String color      = null;
          String loggerName = (logger.getName().equals("") ? ROOT : logger.getName());
      
          color = (row%2 == 1) ? "#E1E1E1" : "#FBFBFB";
      
          out.println("<tr BGCOLOR=\"" + color + "\">");
          out.println("<td><FONT SIZE=\"-2\" COLOR=\"BLACK\" FACE=\"Helvetica\">" + 
                      loggerName + "</FONT></td>");
          out.println("<td><FONT SIZE=\"-2\" COLOR=\"BLACK\" FACE=\"Helvetica\">" + 
                      ( (logger.getLevel() == null) ? logger.getEffectiveLevel().toString() +
                        "*" : logger.getLevel().toString()) + "</FONT></td>");
          out.println("</tr>");
      }
      
      // set a logger's level
      private synchronized String setClass(String className, String level) 
      {
          Logger logger  = null;
          String message = null;
          
          try 
          {
              logger = (className.equals(ROOT)) ? logger.getRootLogger() : 
                  logger.getLogger(className);
  
              logger.setLevel(Level.toLevel(level));
          } 
      
          catch (Exception e) 
          {
              System.out.println("ERROR Setting LOG4J Logger:" + e);
          }
      
          return "Message Set For " + (logger.getName().equals("") ? ROOT : logger.getName());
      }
  
      // get a sorted list of all current loggers
      private List getSortedLoggers()
      {
          Logger      logger = null;
          Enumeration enum   = LogManager.getCurrentLoggers();
          Comparator  comp   = new LoggerComparator();
          ArrayList   list   = new ArrayList();
  
          // Add all current loggers to the list
          while(enum.hasMoreElements()) 
          {
              list.add(enum.nextElement());
          }
          
          // sort the loggers
          Collections.sort(list, comp);
      
          return list;
      }
  
      /**
       * Compare the names of two <code>Logger</code>s.  Used
       * for sorting.
       */
      private class LoggerComparator implements Comparator
      {
      
          /**
           * Compare the names of two <code>Logger</code>s.
           *
           * @param o1 an <code>Object</code> value
           * @param o2 an <code>Object</code> value
           * @return an <code>int</code> value
           */
          public int compare(Object o1, Object o2)
          {
              Logger logger1 = (Logger) o1;
              Logger logger2 = (Logger) o2;;
          
              String logger1Name = null;
              String logger2Name = null;
          
              if ( logger1 != null )
                  logger1Name = (logger1.getName().equals("") ? ROOT : logger1.getName());
          
              if ( logger2 != null )
                  logger2Name = (logger2.getName().equals("") ? ROOT : logger2.getName());
                  
              return logger1Name.compareTo(logger2Name); 
          }
      
          /**
           * Return <code>true</code> if the <code>Object</code> is a
           * <code>LoggerComparator</code> instance.
           * 
           *
           * @param o an <code>Object</code> value
           * @return a <code>boolean</code> value
           */
          public boolean equals(Object o)
          {
          
              if (o instanceof LoggerComparator) 
                  return true;
          
              else
                  return false;
          }
      }
  
  }//EOF
  
  
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/servlet/CookieMDCFilter.java
  
  Index: CookieMDCFilter.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.servlet;
  
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.StringTokenizer;
  import java.io.IOException;
  
  import javax.servlet.Filter;
  import javax.servlet.FilterChain;
  import javax.servlet.FilterConfig;
  import javax.servlet.ServletException;
  import javax.servlet.ServletRequest;
  import javax.servlet.ServletResponse;
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletRequest;
  
  import org.apache.log4j.Logger;
  import org.apache.log4j.MDC;
  
  /**
    A useful Servlet 2.3 compatible filter which will search for a predefined 
    set of cookies in the request and place their values into the log4j MDC. 
    The key used in the MDC is the name of the cookie.  The value placed in
    the MDC is the value of the cookie in the request.
    
    @author Mark Womack <mwomack@apache.org>
    @since 1.3
    */
    
  //  An example of the web.xml configuration:
  //
  //    <!-- looks for cookies named "JSESSIONID" and "USERID" -->
  //    <filter>
  //      <filter-name>trace-cookie-context-filter</filter-name>
  //      <filter-class>
  //        org.apache.log4j.servlet.CookieMDCFilter
  //      </filter-class>
  //      <init-param>
  //        <param-name>cookie-list</param-name>
  //        <param-value>
  //          JSESSIONID
  //          USERID
  //        </param-value>
  //      </init-param>
  //    </filter>
  //    
  //    <!-- any jsp will have this filter execute first -->
  //    <filter-mapping>
  //      <filter-name>trace-cookie-context-filter</filter-name>
  //      <url-pattern>*/*.jsp</url-pattern>
  //    </filter-mapping>
  //  
  //  An example of the log4j xml configuration using PatternLayout:
  //  
  //    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
  //      <layout class="org.apache.log4j.PatternLayout">
  //        <param name="ConversionPattern"
  //           value="%d{ABSOLUTE} %-5p %X{JSESSIONID} %X{USERID} %c{1} : %m%n"/>
  //      </layout>
  //    </appender>
  public class CookieMDCFilter implements Filter {
      private static final Logger _TRACE =
          Logger.getLogger(CookieMDCFilter.class);
      
      /**
        The set of cookies names we want to look for. */
      private HashMap cookieMap;
      
      /**
        Uses filter init parameter to initialize a list of cookies that will be
        retrieved from the request and placed into the log4j MDC context. */
      public void init(FilterConfig filterConfig) throws ServletException {
          
          // check for existense of init param
          String cookieParam = filterConfig.getInitParameter("cookie-list");
          if (cookieParam == null || cookieParam.length() == 0)
              return;
          
          // parse the list of cookies
          StringTokenizer tokenizer = new StringTokenizer(cookieParam);
          while (tokenizer.hasMoreTokens()) {
              if (cookieMap == null) {
                  cookieMap = new HashMap();
              }
              cookieMap.put(tokenizer.nextToken(), null);
          }
          
          // report the configuration
          if (cookieMap != null && _TRACE.isDebugEnabled()) {
              Iterator iter = cookieMap.keySet().iterator();
              while (iter.hasNext()) {
                  _TRACE.debug("configured to search for cookie with name " + 
                      iter.next());
              }
          }
      }
      
      /**
        Search the request cookies for the cookies whose value we want to
        stuff into the log4j MDC. */
      public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) throws IOException, ServletException {
          
          // if this filter configured and request has cookies, search
          if (cookieMap != null) {
              Cookie[] cookies = ((HttpServletRequest)request).getCookies();
              if (cookies != null) {
                  for (int x = 0; x < cookies.length; x++) {
                      
                      // if request has a cookie we are lookig for, put its
                      // value into the MDC
                      String name = cookies[x].getName();
                      if (cookieMap.containsKey(cookies[x].getName())) {
                          MDC.put(name, cookies[x].getValue());
                          if (_TRACE.isDebugEnabled())
                              _TRACE.debug("put into MDC cookie with name " + 
                                  name + " and value " + cookies[x].getValue());
                      }
                      else {
                          if (_TRACE.isDebugEnabled())
                              _TRACE.debug("ignoring cookie with name " + name);
                          
                      }
                  }
              }
          }
          
          // pass control to the next filter
          chain.doFilter(request, response);
      }
      
      /**
        Not used. */
      public void destroy() {
          // do nothing
      }
  }
  
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/servlet/InitContextListener.java
  
  Index: InitContextListener.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.servlet;
  
  import javax.servlet.ServletContext;
  import javax.servlet.ServletContextListener;
  import javax.servlet.ServletContextEvent;
  
  import java.io.File;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.Properties;
  
  import org.apache.log4j.helpers.LogLog;
  import org.apache.log4j.PropertyConfigurator;
  import org.apache.log4j.xml.DOMConfigurator;
  
  import org.apache.log4j.selector.ContextClassLoaderSelector;
  
  /**
   * A servlet context listener for initializing and shutting down Log4j. See
   * <a href="http://jakarta.apache.org/log4j/docs/documentation.html">Log4j documentation</a>
   * for how to use Log4j.
   * <p>
   * This is a <code>ServletContextListener</code> as defined by the servlet 2.3
   * specification.  It gets called immediately before full application startup
   * and immediately before full application shutdown.  Unlike servlets, which
   * may be destroyed at the will of the container at any time during the
   * application lifecycle, a servlet context listener is guaranteed to be
   * called exactly twice within the application's lifecycle.  As such, we can
   * use it to initialize things once at application startup and clean things
   * up at application shutdown.</p>
   * <p>
   * Initialization is described below in the discussion of the various parameters
   * available for configuring this context listener.  In the case of shutdown we are
   * concerned with cleaning up loggers and appenders within the
   * <code>Hierarchy</code> that the current application is using for
   * logging.  If we didn't do this, there is a chance that, for instance, file
   * appenders won't have given up handles to files they are logging to which
   * would leave them in a locked state until the current JVM is shut down.  This
   * would entail a full shutdown of the application server in order to release
   * locks on log files.  Using this servlet context listener ensures that locks
   * will be released without requiring a full server shutdown.</p>
   * </p>
   * <p>
   * The following needs to be added to the webapp's web.xml file to configure this listener:
   * <blockquote>
   * <pre>
   * &lt;context-param&gt;
   *     &lt;!-- relative path to config file within current webapp --&gt;
   *     &lt;param-name&gt;log4j-config&lt;/param-name&gt;
   *     &lt;param-value&gt;WEB-INF/log4j.xml&lt;/param-value&gt;
   * &lt;/context-param&gt;
   * &lt;context-param&gt;
   *     &lt;!-- config file re-reading specified in milliseconds...
   *              Note that if the webapp is served directly from the
   *              .war file, configureAndWatch() cannot be used because
   *              it requires a system file path. In that case, this
   *              param will be ignored.  Set to 0 or don't specify this
   *              param to do a normal configure(). --&gt;
   *     &lt;param-name&gt;log4j-cron&lt;/param-name&gt;
   *     &lt;param-value&gt;5000&lt;/param-value&gt;
   * &lt;/context-param&gt;
   * &lt;!-- Below is an optional param for use with a File Appender.
   *          Specifies a path to be read from a log4j xml
   *          config file as a system property. The property name is
   *          dynamically generated and takes on the following pattern:
   *              [webapp name].log.home
   *          If the app has a path of &quot;/Barracuda&quot;, the system
   *          variable name would be &quot;Barracuda.log.home&quot;.  So,
   *          the FileAppender in log4j.xml would contain a param which looks like:
   *              &lt;param name=&quot;File&quot; value=&quot;${Barracuda.log.home}/arbitraryLogFileName.log&quot; /&gt;
   *          If the &quot;log4j-log-home&quot; context param is not specified, the
   *          path associated with the generated system variable defaults to
   *          the WEB-INF/logs directory of the current webapp which is created
   *          if it doesn't exist... unless the webapp is running directly
   *          from a .war file.  In the latter case, this context param
   *          *must* be specified if using a FileAppender.
   *          Note that, if specified, the value is treated as an absolute
   *          system path which is not relative to the webapp. --&gt;
   * &lt;!-- &lt;context-param&gt;
   *     &lt;param-name&gt;log4j-log-home&lt;/param-name&gt;
   *     &lt;param-value&gt;/usr/local/logs/tomcat&lt;/param-value&gt;
   * &lt;/context-param&gt; --&gt;
   *
   * &lt;listener&gt;
   *     &lt;listener-class&gt;
   *      org.apache.log4j.servlet.InitContextListener
   *     &lt;/listener-class&gt;
   * &lt;/listener&gt;
   * </pre>
   * </blockquote>
   * </p>
   * <h4>Below is some more information on each of the configuration properties</h4>
   * <p>
   * <dl>
   * <dt><code>log4j-config</code></dt>
   * <dd>
   * The <code>log4j-config</code> init parameter specifies the location of the
   * Log4j configuration file relative to the current webapp.
   * If the <code>log4j-config</code> init parameter is omitted, this class
   * will just let Log4j configure itself since, upon first use of Log4j, if it
   * has not yet been configured, it will search for a config file named log4j.xml
   * or log4j.properties in the classpath. If it can't find one, it falls back to using the
   * <code>BasicConfigurator.configure()</code> to initialize Log4j.
   * </dd>
   * <dt><code>log4j-cron</code></dt>
   * <dd>
   * The <code>log4j-cron</code> init parameter specifies the number of milliseconds
   * to wait in between reads of the config file using <code>configureAndWatch()</code>.
   * If omitted, given a value of 0, or given a value that is other than something that
   * which can be converted to a Java long value a normal <code>configure()</code> is used.
   * </dd>
   * <dt><code>log4j-log-home</code></dt>
   * <dd>
   * The <code>log4j-log-home</code> init parameter is optional. It specifies a
   * custom path to a directory meant to contain log files for the current webapp
   * when using a <code>FileAppender</code>. If not specified, it will default to
   * using the location WEB-INF/logs to contain log files. If the directory doesn't
   * exist, it is created. A system parameter is then created in the following format:
   * <blockquote>
   *     <code>[webapp name].log.home</code>
   * </blockquote>
   * This can be referenced in an xml config file (not sure if it works for a properties
   * config file?) in the following fashion for a webapp with the context path &quot;/Barracuda&quot;:
   * <blockquote>
   *     <code>&lt;param name=&quot;File&quot; value=&quot;${Barracuda.log.home}/main.log&quot; /&gt;</code>
   * </blockquote>
   * In this case, we are running in the &quot;Barracuda&quot; context and the &quot;main.log&quot; file
   * will get created in whatever directory path is specified by the system property
   * &quot;Barracuda.log.home&quot;.
   * <p>
   * <strong>Note</strong> that if the webapp is being run directly from a .war file, the automatic creation
   * of the WEB-INF/logs directory and [webapp name].log.home system property will *not* be
   * performed. In this case, you would have to provide a custom directory path for the
   * this to work. Also note that <code>configureAndWatch()</code> will not be used in the case
   * that the webapp is running directly from a .war file. <code>configure()</code> will be used
   * instead.
   * </p>
   * </dd>
   * </dl>
   *
   * @author  Jacob Kjome <hoju@visi.com>
   * @since   1.3
   */
  public class InitContextListener implements ServletContextListener {
  
      // store the time at which the current application became fully initialized
      public static long applicationInitialized = 0L;
  
      private final static String PARAM_LOG4J_CONFIG_PATH = "log4j-config";
      private final static String PARAM_LOG4J_WATCH_INTERVAL = "log4j-cron";
      private final static String PARAM_LOG4J_LOG_HOME = "log4j-log-home";
      private final static String DEFAULT_LOG_HOME = "WEB-INF" + File.separator + "logs";
  
  
      /**
       * Application Startup Event
       */
      public void contextInitialized(ServletContextEvent sce) {
          applicationInitialized = System.currentTimeMillis();
  
          ServletContext context = sce.getServletContext();
  
          initializeLog4j(context);
      }
  
      /**
       * Application Shutdown Event
       */
      public void contextDestroyed(ServletContextEvent sce) {
          ServletContext context = sce.getServletContext();
  
          cleanupLog4j(context);
      }
  
  
  
      /**
       * Log4j specific cleanup.  Shuts down all loggers and appenders and
       * removes the hierarchy associated with the current classloader.
       */
      private void cleanupLog4j(ServletContext context) {
          //shutdown this webapp's logger repository
          context.log("Cleaning up Log4j resources for context: " + context.getServletContextName() + "...");
          context.log("Shutting down all loggers and appenders...");
          org.apache.log4j.LogManager.shutdown();
          context.log("Log4j cleaned up.");
      }
  
      /**
       * Log4j specific initialization.  Shuts down all loggers and appenders and
       * removes the hierarchy associated with the current classloader.
       */
      private void initializeLog4j(ServletContext context) {
  
          String configPath = context.getInitParameter(PARAM_LOG4J_CONFIG_PATH);
          // if the log4j-config parameter is not set, then no point in trying
          if (configPath!=null) {
              if (configPath.startsWith("/")) configPath = (configPath.length() > 1) ? configPath.substring(1) : "";
              // if the configPath is an empty string, then no point in trying
              if (configPath.length() >= 1) {
                  // set up log path System property
                  String logHome = context.getInitParameter(PARAM_LOG4J_LOG_HOME);
                  if (logHome!=null) {
                      // set up custom log path system property
                      setFileAppenderSystemProperty(logHome, context);
                  }
                  boolean isXMLConfigFile = (configPath.endsWith(".xml")) ? true : false;
                  String contextPath = context.getRealPath("/");
                  if (contextPath!=null) {
                      // The webapp is deployed directly off the filesystem,
                      // not from a .war file so we *can* do File IO.
                      // This means we can use configureAndWatch() to re-read
                      // the the config file at defined intervals.
                      // Now let's check if the given configPath actually exists.
                      if (logHome==null) {
                          // no log path specified in web.xml. Setting to default
                          logHome = contextPath+DEFAULT_LOG_HOME;
                          setFileAppenderSystemProperty(logHome, context);
                      }
                      String systemConfigPath = configPath.replace('/', File.separatorChar);
                      File log4jFile = new File(contextPath+systemConfigPath);
                      if (log4jFile.canRead()) {
                          log4jFile = null;
                          String timerInterval = context.getInitParameter(PARAM_LOG4J_WATCH_INTERVAL);
                          long timerIntervalVal = 0L;
                          if (timerInterval!=null) {
                              try {
                                  timerIntervalVal = Integer.valueOf(timerInterval).longValue();
                              }
                              catch (NumberFormatException nfe) {}
                          }
                          initLoggerRepository();
                          context.log("Configuring Log4j from File: "+contextPath+systemConfigPath);
                          if (timerIntervalVal > 0) {
                              context.log("Configuring Log4j with watch interval: "+timerIntervalVal+"ms");
                              if (isXMLConfigFile) {
                                  DOMConfigurator.configureAndWatch(contextPath+systemConfigPath, timerIntervalVal);
                              }
                              else {
                                  PropertyConfigurator.configureAndWatch(contextPath+systemConfigPath, timerIntervalVal);
                              }
                          }
                          else {
                              if (isXMLConfigFile) {
                                  DOMConfigurator.configure(contextPath+systemConfigPath);
                              }
                              else {
                                  PropertyConfigurator.configure(contextPath+systemConfigPath);
                              }
                          }
                      }
                      else {
                          // The given configPath does not exist.  So, let's just let Log4j look for the
                          // default files (log4j.properties or log4j.xml) on its own.
                          displayConfigNotFoundMessage();
                      } //end log4jFile.canRead() check
                  }
                  else {
                      // The webapp is deployed from a .war file, not directly
                      // off the file system so we *cannot* do File IO.
                      // Note that we *won't* be able to use configureAndWatch() here
                      // because that requires an absolute system file path.
                      // Now let's check if the given configPath actually exists.
                      URL log4jURL = null;
                      try {
                          log4jURL = context.getResource("/"+configPath);
                      }
                      catch (MalformedURLException murle) {}
                      if (log4jURL!=null) {
                          initLoggerRepository();
                          context.log("Configuring Log4j from URL at path: /"+configPath);
                          if (isXMLConfigFile) {
                              try {
                                  DOMConfigurator.configure(log4jURL);
                              }
                              //catch (javax.xml.parsers.FactoryConfigurationError fce) {}
                              catch (Exception e) {
                                  //report errors to server logs
                                  LogLog.error(e.getMessage());
                              }
                          }
                          else {
                              Properties log4jProps = new Properties();
                              try {
                                  log4jProps.load(log4jURL.openStream());
                                  PropertyConfigurator.configure(log4jProps);
                              }
                              //catch (java.io.IOException ioe) {}
                              catch (Exception e) {
                                  //report errors to server logs
                                  LogLog.error(e.getMessage());
                              }
                          }
                      }
                      else {
                          // The given configPath does not exist.  So, let's just let Log4j look for the
                          // default files (log4j.properties or log4j.xml) on its own.
                          displayConfigNotFoundMessage();
                      } //end log4jURL null check
                  } //end contextPath null check
              }
              else {
                  LogLog.error("Zero length Log4j config file path given.");
                  displayConfigNotFoundMessage();
              } //end configPath length check
          }
          else {
              LogLog.error("Missing log4j-config servlet parameter missing.");
              displayConfigNotFoundMessage();
          } //end configPath null check
      }
  
      private void displayConfigNotFoundMessage() {
          LogLog.warn("No Log4j configuration file found at given path. Falling back to Log4j auto-configuration.");
      }
  
      private void setFileAppenderSystemProperty(String logHome, ServletContext context) {
          File logHomeDir = new File(logHome);
          if (logHomeDir.exists() || logHomeDir.mkdirs()) {
              String tempdir = ""+context.getAttribute("javax.servlet.context.tempdir");
              int lastSlash = tempdir.lastIndexOf(File.separator);
              if ((tempdir.length()-1) > lastSlash) {
                  String logHomePropertyName = tempdir.substring(lastSlash+1) + ".log.home";
                  context.log("Setting system property [ " + logHomePropertyName + " ] to [ " + logHome + " ]");
                  System.setProperty(logHomePropertyName, logHome);
              }
          }
      }
  
      private void initLoggerRepository() {
          ContextClassLoaderSelector.doIdempotentInitialization();
      }
  }
  
  
  
  1.1                  jakarta-log4j-sandbox/src/java/org/apache/log4j/servlet/InitServlet.java
  
  Index: InitServlet.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.servlet;
  
  import javax.servlet.ServletConfig;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  import java.io.File;
  import java.io.IOException;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.util.Properties;
  
  import org.apache.log4j.helpers.LogLog;
  import org.apache.log4j.PropertyConfigurator;
  import org.apache.log4j.xml.DOMConfigurator;
  
  import org.apache.log4j.selector.ContextClassLoaderSelector;
  
  /**
   * A servlet for initializing Log4j. See
   * <a href="http://jakarta.apache.org/log4j/docs/documentation.html">Log4j documentation</a>
   * for how to use Log4j.
   * <p>
   * <strong>Note:</strong> This log4j initialization servlet should be used *only* when
   * running under a container which doesn't support servlet-2.3. A far better choice for
   * servlet-2.3 configuration exists in {@link Log4jApplicationWatch}. Use it instead of
   * this class for initialization.  If you really need to use this class, read on...</p>
   * <p>
   * This servlet is never called by a client, but should be called during
   * web application initialization, i.e. when the servlet engine starts. The
   * following code should be inserted in the web.xml file for the web
   * application:
   * <p>
   * <pre>
   *  &lt;servlet&gt;
   *      &lt;servlet-name&gt;log4j-init&lt;/servlet-name&gt;
   *      &lt;servlet-class&gt;org.apache.log4j.servlet.InitServlet&lt;/servlet-class&gt;
   *      &lt;init-param&gt;
   *           &lt;param-name&gt;log4j-config&lt;/param-name&gt;
   *           &lt;param-value&gt;WEB-INF/log4j.xml&lt;/param-value&gt;
   *      &lt;/init-param&gt;
   *      &lt;init-param&gt;
   *           &lt;param-name&gt;log4j-cron&lt;/param-name&gt;
   *           &lt;param-value&gt;5000&lt;/param-value&gt;
   *      &lt;/init-param&gt;
   *      &lt;init-param&gt;
   *           &lt;param-name&gt;log4j-log-home&lt;/param-name&gt;
   *           &lt;param-value&gt;/usr/local/logs/tomcat&lt;/param-value&gt;
   *      &lt;/init-param&gt;
   *      &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
   *  &lt;/servlet&gt;
   * </pre>
   * </p>
   * <p>
   * See {@link Log4jApplicationWatch} for detailed information about these parameters.
   * </p>
   *
   * @author  Jacob Kjome <hoju@visi.com>
   * @since   1.3
   */
  public class InitServlet extends HttpServlet {
  
      private final static String PARAM_LOG4J_CONFIG_PATH = "log4j-config";
      private final static String PARAM_LOG4J_WATCH_INTERVAL = "log4j-cron";
      private final static String PARAM_LOG4J_LOG_HOME = "log4j-log-home";
      private final static String DEFAULT_LOG_HOME = "WEB-INF" + File.separator + "logs";
  
      private static Boolean CONFIGURED = Boolean.FALSE;
  
      public void init() throws ServletException {
          if (CONFIGURED.equals(Boolean.FALSE)) {
              String configPath = getInitParameter(PARAM_LOG4J_CONFIG_PATH);
              // if the log4j-config parameter is not set, then no point in trying
              if (configPath!=null) {
                  if (configPath.startsWith("/")) configPath = (configPath.length() > 1) ? configPath.substring(1) : "";
                  // if the configPath is an empty string, then no point in trying
                  if (configPath.length() >= 1) {
                      // set up log path System property
                      String logHome = getInitParameter(PARAM_LOG4J_LOG_HOME);
                      if (logHome!=null) {
                          // set up custom log path system property
                          setFileAppenderSystemProperty(logHome, this);
                      }
                      boolean isXMLConfigFile = (configPath.endsWith(".xml")) ? true : false;
                      String contextPath = getServletContext().getRealPath("/");
                      if (contextPath!=null) {
                          // The webapp is deployed directly off the filesystem,
                          // not from a .war file so we *can* do File IO.
                          // This means we can use configureAndWatch() to re-read
                          // the the config file at defined intervals.
                          // Now let's check if the given configPath actually exists.
                          if (logHome==null) {
                              // no log path specified in web.xml. Setting to default
                              logHome = contextPath+DEFAULT_LOG_HOME;
                              setFileAppenderSystemProperty(logHome, this);
                          }
                          String systemConfigPath = configPath.replace('/', File.separatorChar);
                          File log4jFile = new File(contextPath+systemConfigPath);
                          if (log4jFile.canRead()) {
                              log4jFile = null;
                              String timerInterval = getInitParameter(PARAM_LOG4J_WATCH_INTERVAL);
                              long timerIntervalVal = 0L;
                              if (timerInterval!=null) {
                                  try {
                                      timerIntervalVal = Integer.valueOf(timerInterval).longValue();
                                  }
                                  catch (NumberFormatException nfe) {}
                              }
                              synchronized (CONFIGURED) {
                                  if (CONFIGURED.equals(Boolean.FALSE)) {
                                      initLoggerRepository();
                                      log("Configuring Log4j from File: "+contextPath+systemConfigPath);
                                      if (timerIntervalVal > 0) {
                                          log("Configuring Log4j with watch interval: "+timerIntervalVal+"ms");
                                          if (isXMLConfigFile) {
                                              DOMConfigurator.configureAndWatch(contextPath+systemConfigPath, timerIntervalVal);
                                          }
                                          else {
                                              PropertyConfigurator.configureAndWatch(contextPath+systemConfigPath, timerIntervalVal);
                                          }
                                      }
                                      else {
                                          if (isXMLConfigFile) {
                                              DOMConfigurator.configure(contextPath+systemConfigPath);
                                          }
                                          else {
                                              PropertyConfigurator.configure(contextPath+systemConfigPath);
                                          }
                                      }
                                      CONFIGURED = Boolean.TRUE;
                                  } //end CONFIGURED check
                              } //end syncronized block
                          }
                          else {
                              // The given configPath does not exist.  So, let's just let Log4j look for the
                              // default files (log4j.properties or log4j.xml) on its own.
                              displayConfigNotFoundMessage();
                          } //end log4jFile.canRead() check
                      }
                      else {
                          // The webapp is deployed from a .war file, not directly
                          // off the file system so we *cannot* do File IO.
                          // Note that we *won't* be able to use configureAndWatch() here
                          // because that requires an absolute system file path.
                          // Now let's check if the given configPath actually exists.
                          URL log4jURL = null;
                          try {
                              log4jURL = getServletContext().getResource("/"+configPath);
                          }
                          catch (MalformedURLException murle) {}
                          if (log4jURL!=null) {
                              synchronized (CONFIGURED) {
                                  if (CONFIGURED.equals(Boolean.FALSE)) {
                                      initLoggerRepository();
                                      log("Configuring Log4j from URL at path: /"+configPath);
                                      if (isXMLConfigFile) {
                                          try {
                                              DOMConfigurator.configure(log4jURL);
                                              CONFIGURED = Boolean.TRUE;
                                          }
                                          //catch (javax.xml.parsers.FactoryConfigurationError fce) {}
                                          catch (Exception e) {
                                              //report errors to server logs
                                              LogLog.error(e.getMessage());
                                          }
                                      }
                                      else {
                                          Properties log4jProps = new Properties();
                                          try {
                                              log4jProps.load(log4jURL.openStream());
                                              PropertyConfigurator.configure(log4jProps);
                                              CONFIGURED = Boolean.TRUE;
                                          }
                                          //catch (IOException ioe) {}
                                          catch (Exception e) {
                                              //report errors to server logs
                                              LogLog.error(e.getMessage());
                                          }
                                      }
                                  } //end CONFIGURED check
                              } //end syncronized block
                          }
                          else {
                              // The given configPath does not exist.  So, let's just let Log4j look for the
                              // default files (log4j.properties or log4j.xml) on its own.
                              displayConfigNotFoundMessage();
                          } //end log4jURL null check
                      } //end contextPath null check
                  }
                  else {
                      LogLog.error("Zero length Log4j config file path given.");
                      displayConfigNotFoundMessage();
                  } //end configPath length check
              }
              else {
                  LogLog.error("Missing log4j-config servlet parameter missing.");
                  displayConfigNotFoundMessage();
              } //end configPath null check
          } //end CONFIGURED check
      } //end init() method
  
      private void displayConfigNotFoundMessage() {
          LogLog.warn("No Log4j configuration file found at given path. Falling back to Log4j auto-configuration.");
      }
  
      private void setFileAppenderSystemProperty(String logHome, ServletConfig config) {
          File logHomeDir = new File(logHome);
          if (logHomeDir.exists() || logHomeDir.mkdirs()) {
              ServletContext context = config.getServletContext();
              String tempdir = ""+context.getAttribute("javax.servlet.context.tempdir");
              int lastSlash = tempdir.lastIndexOf(File.separator);
              if ((tempdir.length()-1) > lastSlash) {
                  String logHomePropertyName = tempdir.substring(lastSlash+1) + ".log.home";
                  context.log("Setting system property [ " + logHomePropertyName + " ] to [ " + logHome + " ]");
                  System.setProperty(logHomePropertyName, logHome);
              }
          }
      }
  
      private void initLoggerRepository() {
          ContextClassLoaderSelector.doIdempotentInitialization();
      }
  
      /**
       * Throws a ServletException.
       */
      public void doGet(HttpServletRequest req, HttpServletResponse res)
                                      throws ServletException, IOException {
          throw new ServletException("Servlet only used for Log4j initialization");
      }
  
      public void doPost(HttpServletRequest req, HttpServletResponse res)
                                      throws ServletException, IOException {
          doGet(req, res);
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: log4j-dev-help@jakarta.apache.org


Mime
View raw message