JAL-3032 adds Java 8 functionality (1/2)
[jalview.git] / srcjar / org / apache / log4j / PropertyConfigurator.java
diff --git a/srcjar/org/apache/log4j/PropertyConfigurator.java b/srcjar/org/apache/log4j/PropertyConfigurator.java
deleted file mode 100644 (file)
index 3e5cc26..0000000
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-// Contributors: "Luke Blanshard" <Luke@quiq.com>
-//              "Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>
-//               Anders Kristensen <akristensen@dynamicsoft.com>
-
-package org.apache.log4j;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-import java.net.URLConnection;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Properties;
-import java.util.StringTokenizer;
-import java.util.Vector;
-import java.util.Iterator;
-import java.util.Map;
-
-import org.apache.log4j.config.PropertySetter;
-import org.apache.log4j.helpers.FileWatchdog;
-import org.apache.log4j.helpers.LogLog;
-import org.apache.log4j.helpers.OptionConverter;
-import org.apache.log4j.or.RendererMap;
-import org.apache.log4j.spi.Configurator;
-import org.apache.log4j.spi.Filter;
-import org.apache.log4j.spi.LoggerFactory;
-import org.apache.log4j.spi.LoggerRepository;
-import org.apache.log4j.spi.OptionHandler;
-import org.apache.log4j.spi.RendererSupport;
-import org.apache.log4j.spi.ThrowableRenderer;
-import org.apache.log4j.spi.ThrowableRendererSupport;
-import org.apache.log4j.spi.ErrorHandler;
-
-/**
-   Allows the configuration of log4j from an external file.  See
-   <b>{@link #doConfigure(String, LoggerRepository)}</b> for the
-   expected format.
-
-   <p>It is sometimes useful to see how log4j is reading configuration
-   files. You can enable log4j internal logging by defining the
-   <b>log4j.debug</b> variable.
-
-   <P>As of log4j version 0.8.5, at class initialization time class,
-   the file <b>log4j.properties</b> will be searched from the search
-   path used to load classes. If the file can be found, then it will
-   be fed to the {@link PropertyConfigurator#configure(java.net.URL)}
-   method.
-
-   <p>The <code>PropertyConfigurator</code> does not handle the
-   advanced configuration features supported by the {@link
-   org.apache.log4j.xml.DOMConfigurator DOMConfigurator} such as
-   support custom {@link org.apache.log4j.spi.ErrorHandler ErrorHandlers},
-   nested appenders such as the {@link org.apache.log4j.AsyncAppender
-   AsyncAppender}, etc.
-
-   <p>All option <em>values</em> admit variable substitution. The
-   syntax of variable substitution is similar to that of Unix
-   shells. The string between an opening <b>&quot;${&quot;</b> and
-   closing <b>&quot;}&quot;</b> is interpreted as a key. The value of
-   the substituted variable can be defined as a system property or in
-   the configuration file itself. The value of the key is first
-   searched in the system properties, and if not found there, it is
-   then searched in the configuration file being parsed.  The
-   corresponding value replaces the ${variableName} sequence. For
-   example, if <code>java.home</code> system property is set to
-   <code>/home/xyz</code>, then every occurrence of the sequence
-   <code>${java.home}</code> will be interpreted as
-   <code>/home/xyz</code>.
-
-
-   @author Ceki G&uuml;lc&uuml;
-   @author Anders Kristensen
-   @since 0.8.1 */
-public class PropertyConfigurator implements Configurator {
-
-  /**
-     Used internally to keep track of configured appenders.
-   */
-  protected Hashtable registry = new Hashtable(11);  
-  private LoggerRepository repository;
-  protected LoggerFactory loggerFactory = new DefaultCategoryFactory();
-
-  static final String      CATEGORY_PREFIX = "log4j.category.";
-  static final String      LOGGER_PREFIX   = "log4j.logger.";
-  static final String       FACTORY_PREFIX = "log4j.factory";
-  static final String    ADDITIVITY_PREFIX = "log4j.additivity.";
-  static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
-  static final String ROOT_LOGGER_PREFIX   = "log4j.rootLogger";
-  static final String      APPENDER_PREFIX = "log4j.appender.";
-  static final String      RENDERER_PREFIX = "log4j.renderer.";
-  static final String      THRESHOLD_PREFIX = "log4j.threshold";
-  private static final String      THROWABLE_RENDERER_PREFIX = "log4j.throwableRenderer";
-  private static final String LOGGER_REF       = "logger-ref";
-  private static final String ROOT_REF         = "root-ref";
-  private static final String APPENDER_REF_TAG         = "appender-ref";  
-  
-
-  /** Key for specifying the {@link org.apache.log4j.spi.LoggerFactory
-      LoggerFactory}.  Currently set to "<code>log4j.loggerFactory</code>".  */
-  public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
-
-    /**
-     * If property set to true, then hierarchy will be reset before configuration.
-     */
-  private static final String RESET_KEY = "log4j.reset";
-
-  static final private String INTERNAL_ROOT_NAME = "root";
-
-  /**
-    Read configuration from a file. <b>The existing configuration is
-    not cleared nor reset.</b> If you require a different behavior,
-    then call {@link  LogManager#resetConfiguration
-    resetConfiguration} method before calling
-    <code>doConfigure</code>.
-
-    <p>The configuration file consists of statements in the format
-    <code>key=value</code>. The syntax of different configuration
-    elements are discussed below.
-
-    <h3>Repository-wide threshold</h3>
-
-    <p>The repository-wide threshold filters logging requests by level
-    regardless of logger. The syntax is:
-
-    <pre>
-    log4j.threshold=[level]
-    </pre>
-
-    <p>The level value can consist of the string values OFF, FATAL,
-    ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
-    custom level value can be specified in the form
-    level#classname. By default the repository-wide threshold is set
-    to the lowest possible value, namely the level <code>ALL</code>.
-    </p>
-
-
-    <h3>Appender configuration</h3>
-
-    <p>Appender configuration syntax is:
-    <pre>
-    # For appender named <i>appenderName</i>, set its class.
-    # Note: The appender name can contain dots.
-    log4j.appender.appenderName=fully.qualified.name.of.appender.class
-
-    # Set appender specific options.
-    log4j.appender.appenderName.option1=value1
-    ...
-    log4j.appender.appenderName.optionN=valueN
-    </pre>
-
-    For each named appender you can configure its {@link Layout}. The
-    syntax for configuring an appender's layout is:
-    <pre>
-    log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
-    log4j.appender.appenderName.layout.option1=value1
-    ....
-    log4j.appender.appenderName.layout.optionN=valueN
-    </pre>
-
-    The syntax for adding {@link Filter}s to an appender is:
-    <pre>
-    log4j.appender.appenderName.filter.ID=fully.qualified.name.of.filter.class
-    log4j.appender.appenderName.filter.ID.option1=value1
-    ...
-    log4j.appender.appenderName.filter.ID.optionN=valueN
-    </pre>
-    The first line defines the class name of the filter identified by ID;
-    subsequent lines with the same ID specify filter option - value
-    pairs. Multiple filters are added to the appender in the lexicographic
-    order of IDs.
-
-    The syntax for adding an {@link ErrorHandler} to an appender is:
-    <pre>
-    log4j.appender.appenderName.errorhandler=fully.qualified.name.of.filter.class
-    log4j.appender.appenderName.errorhandler.root-ref={true|false}
-    log4j.appender.appenderName.errorhandler.logger-ref=loggerName
-    log4j.appender.appenderName.errorhandler.appender-ref=appenderName
-    log4j.appender.appenderName.errorhandler.option1=value1
-    ...
-    log4j.appender.appenderName.errorhandler.optionN=valueN
-    </pre>
-
-    <h3>Configuring loggers</h3>
-
-    <p>The syntax for configuring the root logger is:
-    <pre>
-      log4j.rootLogger=[level], appenderName, appenderName, ...
-    </pre>
-
-    <p>This syntax means that an optional <em>level</em> can be
-    supplied followed by appender names separated by commas.
-
-    <p>The level value can consist of the string values OFF, FATAL,
-    ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
-    custom level value can be specified in the form
-    <code>level#classname</code>.
-
-    <p>If a level value is specified, then the root level is set
-    to the corresponding level.  If no level value is specified,
-    then the root level remains untouched.
-
-    <p>The root logger can be assigned multiple appenders.
-
-    <p>Each <i>appenderName</i> (separated by commas) will be added to
-    the root logger. The named appender is defined using the
-    appender syntax defined above.
-
-    <p>For non-root categories the syntax is almost the same:
-    <pre>
-    log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
-    </pre>
-
-    <p>The meaning of the optional level value is discussed above
-    in relation to the root logger. In addition however, the value
-    INHERITED can be specified meaning that the named logger should
-    inherit its level from the logger hierarchy.
-
-    <p>If no level value is supplied, then the level of the
-    named logger remains untouched.
-
-    <p>By default categories inherit their level from the
-    hierarchy. However, if you set the level of a logger and later
-    decide that that logger should inherit its level, then you should
-    specify INHERITED as the value for the level value. NULL is a
-    synonym for INHERITED.
-
-    <p>Similar to the root logger syntax, each <i>appenderName</i>
-    (separated by commas) will be attached to the named logger.
-
-    <p>See the <a href="../../../../manual.html#additivity">appender
-    additivity rule</a> in the user manual for the meaning of the
-    <code>additivity</code> flag.
-
-    <h3>ObjectRenderers</h3>
-
-    You can customize the way message objects of a given type are
-    converted to String before being logged. This is done by
-    specifying an {@link org.apache.log4j.or.ObjectRenderer ObjectRenderer}
-    for the object type would like to customize.
-
-    <p>The syntax is:
-
-    <pre>
-    log4j.renderer.fully.qualified.name.of.rendered.class=fully.qualified.name.of.rendering.class
-    </pre>
-
-    As in,
-    <pre>
-    log4j.renderer.my.Fruit=my.FruitRenderer
-    </pre>
-
-   <h3>ThrowableRenderer</h3>
-
-   You can customize the way an instance of Throwable is
-   converted to String before being logged. This is done by
-   specifying an {@link org.apache.log4j.spi.ThrowableRenderer ThrowableRenderer}.
-
-   <p>The syntax is:
-
-   <pre>
-   log4j.throwableRenderer=fully.qualified.name.of.rendering.class
-   log4j.throwableRenderer.paramName=paramValue
-   </pre>
-
-   As in,
-   <pre>
-   log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
-   </pre>
-
-    <h3>Logger Factories</h3>
-
-    The usage of custom logger factories is discouraged and no longer
-    documented.
-
-    <h3>Resetting Hierarchy</h3>
-
-    The hierarchy will be reset before configuration when
-    log4j.reset=true is present in the properties file.
-
-    <h3>Example</h3>
-
-    <p>An example configuration is given below. Other configuration
-    file examples are given in the <code>examples</code> folder.
-
-    <pre>
-
-    # Set options for appender named "A1".
-    # Appender "A1" will be a SyslogAppender
-    log4j.appender.A1=org.apache.log4j.net.SyslogAppender
-
-    # The syslog daemon resides on www.abc.net
-    log4j.appender.A1.SyslogHost=www.abc.net
-
-    # A1's layout is a PatternLayout, using the conversion pattern
-    # <b>%r %-5p %c{2} %M.%L %x - %m\n</b>. Thus, the log output will
-    # include # the relative time since the start of the application in
-    # milliseconds, followed by the level of the log request,
-    # followed by the two rightmost components of the logger name,
-    # followed by the callers method name, followed by the line number,
-    # the nested diagnostic context and finally the message itself.
-    # Refer to the documentation of {@link PatternLayout} for further information
-    # on the syntax of the ConversionPattern key.
-    log4j.appender.A1.layout=org.apache.log4j.PatternLayout
-    log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %m\n
-
-    # Set options for appender named "A2"
-    # A2 should be a RollingFileAppender, with maximum file size of 10 MB
-    # using at most one backup file. A2's layout is TTCC, using the
-    # ISO8061 date format with context printing enabled.
-    log4j.appender.A2=org.apache.log4j.RollingFileAppender
-    log4j.appender.A2.MaxFileSize=10MB
-    log4j.appender.A2.MaxBackupIndex=1
-    log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
-    log4j.appender.A2.layout.ContextPrinting=enabled
-    log4j.appender.A2.layout.DateFormat=ISO8601
-
-    # Root logger set to DEBUG using the A2 appender defined above.
-    log4j.rootLogger=DEBUG, A2
-
-    # Logger definitions:
-    # The SECURITY logger inherits is level from root. However, it's output
-    # will go to A1 appender defined above. It's additivity is non-cumulative.
-    log4j.logger.SECURITY=INHERIT, A1
-    log4j.additivity.SECURITY=false
-
-    # Only warnings or above will be logged for the logger "SECURITY.access".
-    # Output will go to A1.
-    log4j.logger.SECURITY.access=WARN
-
-
-    # The logger "class.of.the.day" inherits its level from the
-    # logger hierarchy.  Output will go to the appender's of the root
-    # logger, A2 in this case.
-    log4j.logger.class.of.the.day=INHERIT
-    </pre>
-
-    <p>Refer to the <b>setOption</b> method in each Appender and
-    Layout for class specific options.
-
-    <p>Use the <code>#</code> or <code>!</code> characters at the
-    beginning of a line for comments.
-
-   <p>
-   @param configFileName The name of the configuration file where the
-   configuration information is stored.
-
-  */
-  public
-  void doConfigure(String configFileName, LoggerRepository hierarchy) {
-    Properties props = new Properties();
-    FileInputStream istream = null;
-    try {
-      istream = new FileInputStream(configFileName);
-      props.load(istream);
-      istream.close();
-    }
-    catch (Exception e) {
-      if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
-          Thread.currentThread().interrupt();
-      }
-      LogLog.error("Could not read configuration file ["+configFileName+"].", e);
-      LogLog.error("Ignoring configuration file [" + configFileName+"].");
-      return;
-    } finally {
-        if(istream != null) {
-            try {
-                istream.close();
-            } catch(InterruptedIOException ignore) {
-                Thread.currentThread().interrupt();
-            } catch(Throwable ignore) {
-            }
-
-        }
-    }
-    // If we reach here, then the config file is alright.
-    doConfigure(props, hierarchy);
-  }
-
-  /**
-   */
-  static
-  public
-  void configure(String configFilename) {
-    new PropertyConfigurator().doConfigure(configFilename,
-                                          LogManager.getLoggerRepository());
-  }
-
-  /**
-  Read configuration options from url <code>configURL</code>.
-
-  @since 0.8.2
-*/
-public
-static
-void configure(java.net.URL configURL) {
- new PropertyConfigurator().doConfigure(configURL,
-                    LogManager.getLoggerRepository());
-}
-
-/**
-Reads configuration options from an InputStream.
-
-@since 1.2.17
-*/
-public
-static
-void configure(InputStream inputStream) {
-new PropertyConfigurator().doConfigure(inputStream,
-                  LogManager.getLoggerRepository());
-}
-
-
-  /**
-     Read configuration options from <code>properties</code>.
-
-     See {@link #doConfigure(String, LoggerRepository)} for the expected format.
-  */
-  static
-  public
-  void configure(Properties properties) {
-    new PropertyConfigurator().doConfigure(properties,
-                                          LogManager.getLoggerRepository());
-  }
-
-  /**
-     Like {@link #configureAndWatch(String, long)} except that the
-     default delay as defined by {@link FileWatchdog#DEFAULT_DELAY} is
-     used.
-
-     @param configFilename A file in key=value format.
-
-  */
-  static
-  public
-  void configureAndWatch(String configFilename) {
-    configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY);
-  }
-
-
-  /**
-     Read the configuration file <code>configFilename</code> if it
-     exists. Moreover, a thread will be created that will periodically
-     check if <code>configFilename</code> has been created or
-     modified. The period is determined by the <code>delay</code>
-     argument. If a change or file creation is detected, then
-     <code>configFilename</code> is read to configure log4j.
-
-      @param configFilename A file in key=value format.
-      @param delay The delay in milliseconds to wait between each check.
-  */
-  static
-  public
-  void configureAndWatch(String configFilename, long delay) {
-    PropertyWatchdog pdog = new PropertyWatchdog(configFilename);
-    pdog.setDelay(delay);
-    pdog.start();
-  }
-
-
-  /**
-     Read configuration options from <code>properties</code>.
-
-     See {@link #doConfigure(String, LoggerRepository)} for the expected format.
-  */
-  public
-  void doConfigure(Properties properties, LoggerRepository hierarchy) {
-       repository = hierarchy;
-    String value = properties.getProperty(LogLog.DEBUG_KEY);
-    if(value == null) {
-      value = properties.getProperty("log4j.configDebug");
-      if(value != null) {
-        LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
-    }
-    }
-
-    if(value != null) {
-      LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
-    }
-
-      //
-      //   if log4j.reset=true then
-      //        reset hierarchy
-    String reset = properties.getProperty(RESET_KEY);
-    if (reset != null && OptionConverter.toBoolean(reset, false)) {
-          hierarchy.resetConfiguration();
-    }
-
-    String thresholdStr = OptionConverter.findAndSubst(THRESHOLD_PREFIX,
-                                                      properties);
-    if(thresholdStr != null) {
-      hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr,
-                                                    Level.ALL));
-      LogLog.debug("Hierarchy threshold set to ["+hierarchy.getThreshold()+"].");
-    }
-    
-    configureRootCategory(properties, hierarchy);
-    configureLoggerFactory(properties);
-    parseCatsAndRenderers(properties, hierarchy);
-
-    LogLog.debug("Finished configuring.");
-    // We don't want to hold references to appenders preventing their
-    // garbage collection.
-    registry.clear();
-  }
-
-    /**
-     * Read configuration options from an InputStream.
-     * 
-     * @since 1.2.17
-     */
-    public void doConfigure(InputStream inputStream, LoggerRepository hierarchy) {
-        Properties props = new Properties();
-        try {
-            props.load(inputStream);
-        } catch (IOException e) {
-            if (e instanceof InterruptedIOException) {
-                Thread.currentThread().interrupt();
-            }
-            LogLog.error("Could not read configuration file from InputStream [" + inputStream
-                 + "].", e);
-            LogLog.error("Ignoring configuration InputStream [" + inputStream +"].");
-            return;
-          }
-        this.doConfigure(props, hierarchy);
-    }
-
-  /**
-     Read configuration options from url <code>configURL</code>.
-   */
-  public
-  void doConfigure(java.net.URL configURL, LoggerRepository hierarchy) {
-    Properties props = new Properties();
-    LogLog.debug("Reading configuration from URL " + configURL);
-    InputStream istream = null;
-    URLConnection uConn = null;
-    try {
-      uConn = configURL.openConnection();
-      uConn.setUseCaches(false);
-      istream = uConn.getInputStream();
-      props.load(istream);
-    }
-    catch (Exception e) {
-      if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
-          Thread.currentThread().interrupt();
-      }
-      LogLog.error("Could not read configuration file from URL [" + configURL
-                  + "].", e);
-      LogLog.error("Ignoring configuration file [" + configURL +"].");
-      return;
-    }
-    finally {
-        if (istream != null) {
-            try {
-                istream.close();
-            } catch(InterruptedIOException ignore) {
-                Thread.currentThread().interrupt();
-            } catch(IOException ignore) {
-            } catch(RuntimeException ignore) {
-            }
-        }
-    }
-    doConfigure(props, hierarchy);
-  }
-
-
-  // --------------------------------------------------------------------------
-  // Internal stuff
-  // --------------------------------------------------------------------------
-
-  /**
-     Check the provided <code>Properties</code> object for a
-     {@link org.apache.log4j.spi.LoggerFactory LoggerFactory}
-     entry specified by {@link #LOGGER_FACTORY_KEY}.  If such an entry
-     exists, an attempt is made to create an instance using the default
-     constructor.  This instance is used for subsequent Category creations
-     within this configurator.
-
-     @see #parseCatsAndRenderers
-   */
-  protected void configureLoggerFactory(Properties props) {
-    String factoryClassName = OptionConverter.findAndSubst(LOGGER_FACTORY_KEY,
-                                                          props);
-    if(factoryClassName != null) {
-      LogLog.debug("Setting category factory to ["+factoryClassName+"].");
-      loggerFactory = (LoggerFactory)
-                 OptionConverter.instantiateByClassName(factoryClassName,
-                                                        LoggerFactory.class,
-                                                        loggerFactory);
-      PropertySetter.setProperties(loggerFactory, props, FACTORY_PREFIX + ".");
-    }
-  }
-
-  /*
-  void configureOptionHandler(OptionHandler oh, String prefix,
-                             Properties props) {
-    String[] options = oh.getOptionStrings();
-    if(options == null)
-      return;
-
-    String value;
-    for(int i = 0; i < options.length; i++) {
-      value =  OptionConverter.findAndSubst(prefix + options[i], props);
-      LogLog.debug(
-         "Option " + options[i] + "=[" + (value == null? "N/A" : value)+"].");
-      // Some option handlers assume that null value are not passed to them.
-      // So don't remove this check
-      if(value != null) {
-       oh.setOption(options[i], value);
-      }
-    }
-    oh.activateOptions();
-  }
-  */
-
-
-  void configureRootCategory(Properties props, LoggerRepository hierarchy) {
-    String effectiveFrefix = ROOT_LOGGER_PREFIX;
-    String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);
-
-    if(value == null) {
-      value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
-      effectiveFrefix = ROOT_CATEGORY_PREFIX;
-    }
-
-    if(value == null) {
-        LogLog.debug("Could not find root logger information. Is this OK?");
-    } else {
-      Logger root = hierarchy.getRootLogger();
-      synchronized(root) {
-       parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
-      }
-    }
-  }
-
-
-  /**
-     Parse non-root elements, such non-root categories and renderers.
-  */
-  protected
-  void parseCatsAndRenderers(Properties props, LoggerRepository hierarchy) {
-    Enumeration enumeration = props.propertyNames();
-    while(enumeration.hasMoreElements()) {
-      String key = (String) enumeration.nextElement();
-      if(key.startsWith(CATEGORY_PREFIX) || key.startsWith(LOGGER_PREFIX)) {
-       String loggerName = null;
-       if(key.startsWith(CATEGORY_PREFIX)) {
-         loggerName = key.substring(CATEGORY_PREFIX.length());
-       } else if(key.startsWith(LOGGER_PREFIX)) {
-         loggerName = key.substring(LOGGER_PREFIX.length());
-       }
-       String value =  OptionConverter.findAndSubst(key, props);
-       Logger logger = hierarchy.getLogger(loggerName, loggerFactory);
-       synchronized(logger) {
-         parseCategory(props, logger, key, loggerName, value);
-         parseAdditivityForLogger(props, logger, loggerName);
-       }
-      } else if(key.startsWith(RENDERER_PREFIX)) {
-       String renderedClass = key.substring(RENDERER_PREFIX.length());
-       String renderingClass = OptionConverter.findAndSubst(key, props);
-       if(hierarchy instanceof RendererSupport) {
-         RendererMap.addRenderer((RendererSupport) hierarchy, renderedClass,
-                                 renderingClass);
-       }
-      } else if (key.equals(THROWABLE_RENDERER_PREFIX)) {
-          if (hierarchy instanceof ThrowableRendererSupport) {
-            ThrowableRenderer tr = (ThrowableRenderer)
-                  OptionConverter.instantiateByKey(props,
-                          THROWABLE_RENDERER_PREFIX,
-                          org.apache.log4j.spi.ThrowableRenderer.class,
-                          null);
-            if(tr == null) {
-                LogLog.error(
-                    "Could not instantiate throwableRenderer.");
-            } else {
-                PropertySetter setter = new PropertySetter(tr);
-                setter.setProperties(props, THROWABLE_RENDERER_PREFIX + ".");
-                ((ThrowableRendererSupport) hierarchy).setThrowableRenderer(tr);
-
-            }
-          }
-      }
-    }
-  }
-
-  /**
-     Parse the additivity option for a non-root category.
-   */
-  void parseAdditivityForLogger(Properties props, Logger cat,
-                                 String loggerName) {
-    String value = OptionConverter.findAndSubst(ADDITIVITY_PREFIX + loggerName,
-                                            props);
-    LogLog.debug("Handling "+ADDITIVITY_PREFIX + loggerName+"=["+value+"]");
-    // touch additivity only if necessary
-    if((value != null) && (!value.equals(""))) {
-      boolean additivity = OptionConverter.toBoolean(value, true);
-      LogLog.debug("Setting additivity for \""+loggerName+"\" to "+
-                  additivity);
-      cat.setAdditivity(additivity);
-    }
-  }
-
-  /**
-     This method must work for the root category as well.
-   */
-  void parseCategory(Properties props, Logger logger, String optionKey,
-                    String loggerName, String value) {
-
-    LogLog.debug("Parsing for [" +loggerName +"] with value=[" + value+"].");
-    // We must skip over ',' but not white space
-    StringTokenizer st = new StringTokenizer(value, ",");
-
-    // If value is not in the form ", appender.." or "", then we should set
-    // the level of the loggeregory.
-
-    if(!(value.startsWith(",") || value.equals(""))) {
-
-      // just to be on the safe side...
-      if(!st.hasMoreTokens()) {
-        return;
-    }
-
-      String levelStr = st.nextToken();
-      LogLog.debug("Level token is [" + levelStr + "].");
-
-      // If the level value is inherited, set category level value to
-      // null. We also check that the user has not specified inherited for the
-      // root category.
-      if(INHERITED.equalsIgnoreCase(levelStr) || 
-                                         NULL.equalsIgnoreCase(levelStr)) {
-       if(loggerName.equals(INTERNAL_ROOT_NAME)) {
-         LogLog.warn("The root logger cannot be set to null.");
-       } else {
-         logger.setLevel(null);
-       }
-      } else {
-       logger.setLevel(OptionConverter.toLevel(levelStr, Level.DEBUG));
-      }
-      LogLog.debug("Category " + loggerName + " set to " + logger.getLevel());
-    }
-
-    // Begin by removing all existing appenders.
-    logger.removeAllAppenders();
-
-    Appender appender;
-    String appenderName;
-    while(st.hasMoreTokens()) {
-      appenderName = st.nextToken().trim();
-      if(appenderName == null || appenderName.equals(",")) {
-        continue;
-    }
-      LogLog.debug("Parsing appender named \"" + appenderName +"\".");
-      appender = parseAppender(props, appenderName);
-      if(appender != null) {
-       logger.addAppender(appender);
-      }
-    }
-  }
-
-  Appender parseAppender(Properties props, String appenderName) {
-    Appender appender = registryGet(appenderName);
-    if((appender != null)) {
-      LogLog.debug("Appender \"" + appenderName + "\" was already parsed.");
-      return appender;
-    }
-    // Appender was not previously initialized.
-    String prefix = APPENDER_PREFIX + appenderName;
-    String layoutPrefix = prefix + ".layout";
-
-    appender = (Appender) OptionConverter.instantiateByKey(props, prefix,
-                                             org.apache.log4j.Appender.class,
-                                             null);
-    if(appender == null) {
-      LogLog.error(
-              "Could not instantiate appender named \"" + appenderName+"\".");
-      return null;
-    }
-    appender.setName(appenderName);
-
-    if(appender instanceof OptionHandler) {
-      if(appender.requiresLayout()) {
-       Layout layout = (Layout) OptionConverter.instantiateByKey(props,
-                                                                 layoutPrefix,
-                                                                 Layout.class,
-                                                                 null);
-       if(layout != null) {
-         appender.setLayout(layout);
-         LogLog.debug("Parsing layout options for \"" + appenderName +"\".");
-         //configureOptionHandler(layout, layoutPrefix + ".", props);
-          PropertySetter.setProperties(layout, props, layoutPrefix + ".");
-         LogLog.debug("End of parsing for \"" + appenderName +"\".");
-       }
-      }
-      final String errorHandlerPrefix = prefix + ".errorhandler";
-      String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props);
-      if (errorHandlerClass != null) {
-               ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByKey(props,
-                                         errorHandlerPrefix,
-                                         ErrorHandler.class,
-                                         null);
-               if (eh != null) {
-                         appender.setErrorHandler(eh);
-                         LogLog.debug("Parsing errorhandler options for \"" + appenderName +"\".");
-                         parseErrorHandler(eh, errorHandlerPrefix, props, repository);
-                         final Properties edited = new Properties();
-                         final String[] keys = new String[] { 
-                                         errorHandlerPrefix + "." + ROOT_REF,
-                                         errorHandlerPrefix + "." + LOGGER_REF,
-                                         errorHandlerPrefix + "." + APPENDER_REF_TAG
-                         };
-                         for(Iterator iter = props.entrySet().iterator();iter.hasNext();) {
-                                 Map.Entry entry = (Map.Entry) iter.next();
-                                 int i = 0;
-                                 for(; i < keys.length; i++) {
-                                         if(keys[i].equals(entry.getKey())) {
-                            break;
-                        }
-                                 }
-                                 if (i == keys.length) {
-                                         edited.put(entry.getKey(), entry.getValue());
-                                 }
-                         }
-                     PropertySetter.setProperties(eh, edited, errorHandlerPrefix + ".");
-                         LogLog.debug("End of errorhandler parsing for \"" + appenderName +"\".");
-               }
-         
-      }
-      //configureOptionHandler((OptionHandler) appender, prefix + ".", props);
-      PropertySetter.setProperties(appender, props, prefix + ".");
-      LogLog.debug("Parsed \"" + appenderName +"\" options.");
-    }
-    parseAppenderFilters(props, appenderName, appender);
-    registryPut(appender);
-    return appender;
-  }
-  
-  private void parseErrorHandler(
-                 final ErrorHandler eh,
-                 final String errorHandlerPrefix,
-                 final Properties props, 
-                 final LoggerRepository hierarchy) {
-               boolean rootRef = OptionConverter.toBoolean(
-                                         OptionConverter.findAndSubst(errorHandlerPrefix + ROOT_REF, props), false);
-               if (rootRef) {
-                                 eh.setLogger(hierarchy.getRootLogger());
-           }
-               String loggerName = OptionConverter.findAndSubst(errorHandlerPrefix + LOGGER_REF , props);
-               if (loggerName != null) {
-                       Logger logger = (loggerFactory == null) ? hierarchy.getLogger(loggerName)
-                                       : hierarchy.getLogger(loggerName, loggerFactory);
-                       eh.setLogger(logger);
-               }
-               String appenderName = OptionConverter.findAndSubst(errorHandlerPrefix + APPENDER_REF_TAG, props);
-               if (appenderName != null) {
-                       Appender backup = parseAppender(props, appenderName);
-                       if (backup != null) {
-                               eh.setBackupAppender(backup);
-                       }
-               }
-  }
-                               
-  
-  void parseAppenderFilters(Properties props, String appenderName, Appender appender) {
-    // extract filters and filter options from props into a hashtable mapping
-    // the property name defining the filter class to a list of pre-parsed
-    // name-value pairs associated to that filter
-    final String filterPrefix = APPENDER_PREFIX + appenderName + ".filter.";
-    int fIdx = filterPrefix.length();
-    Hashtable filters = new Hashtable();
-    Enumeration e = props.keys();
-    String name = "";
-    while (e.hasMoreElements()) {
-      String key = (String) e.nextElement();
-      if (key.startsWith(filterPrefix)) {
-        int dotIdx = key.indexOf('.', fIdx);
-        String filterKey = key;
-        if (dotIdx != -1) {
-          filterKey = key.substring(0, dotIdx);
-          name = key.substring(dotIdx+1);
-        }
-        Vector filterOpts = (Vector) filters.get(filterKey);
-        if (filterOpts == null) {
-          filterOpts = new Vector();
-          filters.put(filterKey, filterOpts);
-        }
-        if (dotIdx != -1) {
-          String value = OptionConverter.findAndSubst(key, props);
-          filterOpts.add(new NameValue(name, value));
-        }
-      }
-    }
-
-    // sort filters by IDs, insantiate filters, set filter options,
-    // add filters to the appender
-    Enumeration g = new SortedKeyEnumeration(filters);
-    while (g.hasMoreElements()) {
-      String key = (String) g.nextElement();
-      String clazz = props.getProperty(key);
-      if (clazz != null) {
-        LogLog.debug("Filter key: ["+key+"] class: ["+props.getProperty(key) +"] props: "+filters.get(key));
-        Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz, Filter.class, null);
-        if (filter != null) {
-          PropertySetter propSetter = new PropertySetter(filter);
-          Vector v = (Vector)filters.get(key);
-          Enumeration filterProps = v.elements();
-          while (filterProps.hasMoreElements()) {
-            NameValue kv = (NameValue)filterProps.nextElement();
-            propSetter.setProperty(kv.key, kv.value);
-          }
-          propSetter.activate();
-          LogLog.debug("Adding filter of type ["+filter.getClass()
-           +"] to appender named ["+appender.getName()+"].");
-          appender.addFilter(filter);
-        }
-      } else {
-        LogLog.warn("Missing class definition for filter: ["+key+"]");
-      }
-    }
-  }
-
-
-  void  registryPut(Appender appender) {
-    registry.put(appender.getName(), appender);
-  }
-
-  Appender registryGet(String name) {
-    return (Appender) registry.get(name);
-  }
-}
-
-class PropertyWatchdog extends FileWatchdog {
-
-  PropertyWatchdog(String filename) {
-    super(filename);
-  }
-
-  /**
-     Call {@link PropertyConfigurator#configure(String)} with the
-     <code>filename</code> to reconfigure log4j. */
-  public
-  void doOnChange() {
-    new PropertyConfigurator().doConfigure(filename,
-                                          LogManager.getLoggerRepository());
-  }
-}
-
-class NameValue {
-  String key, value;
-  public NameValue(String key, String value) {
-    this.key = key;
-    this.value = value;
-  }
-  public String toString() {
-    return key + "=" + value;
-  }
-}
-
-class SortedKeyEnumeration implements Enumeration {
-
-  private Enumeration e;
-
-  public SortedKeyEnumeration(Hashtable ht) {
-    Enumeration f = ht.keys();
-    Vector keys = new Vector(ht.size());
-    for (int i, last = 0; f.hasMoreElements(); ++last) {
-      String key = (String) f.nextElement();
-      for (i = 0; i < last; ++i) {
-        String s = (String) keys.get(i);
-        if (key.compareTo(s) <= 0) {
-            break;
-        }
-      }
-      keys.add(i, key);
-    }
-    e = keys.elements();
-  }
-
-  public boolean hasMoreElements() {
-    return e.hasMoreElements();
-  }
-
-  public Object nextElement() {
-    return e.nextElement();
-  }
-}