logging-log4j-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mwom...@apache.org
Subject svn commit: r391905 - in /logging/log4j/trunk: docs/ src/java/org/apache/log4j/ src/java/org/apache/log4j/joran/ src/java/org/apache/log4j/spi/ src/java/org/apache/log4j/watchdog/ src/java/org/apache/log4j/xml/ tests/input/watchdog/ tests/src/java/org/...
Date Thu, 06 Apr 2006 05:32:41 GMT
Author: mwomack
Date: Wed Apr  5 22:32:38 2006
New Revision: 391905

URL: http://svn.apache.org/viewcvs?rev=391905&view=rev
Log:
Cleaned up FileWatchdog implementation, added back configureAndWatch methods for DOMConfigurator and PropertyConfigurator, added more FileWatchdog related tests.

Added:
    logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java   (with props)
    logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml   (with props)
    logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml   (with props)
    logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml   (with props)
    logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties   (with props)
    logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties   (with props)
    logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt   (with props)
    logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt   (with props)
Removed:
    logging/log4j/trunk/src/java/org/apache/log4j/watchdog/TimedLocationWatchdog.java
Modified:
    logging/log4j/trunk/docs/HISTORY.txt
    logging/log4j/trunk/src/java/org/apache/log4j/PropertyConfigurator.java
    logging/log4j/trunk/src/java/org/apache/log4j/joran/JoranConfigurator.java
    logging/log4j/trunk/src/java/org/apache/log4j/watchdog/FileWatchdog.java
    logging/log4j/trunk/src/java/org/apache/log4j/watchdog/Watchdog.java
    logging/log4j/trunk/src/java/org/apache/log4j/watchdog/WatchdogSkeleton.java
    logging/log4j/trunk/src/java/org/apache/log4j/xml/DOMConfigurator.java
    logging/log4j/trunk/tests/src/java/org/apache/log4j/watchdog/FileWatchdogTestCase.java

Modified: logging/log4j/trunk/docs/HISTORY.txt
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/docs/HISTORY.txt?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/docs/HISTORY.txt (original)
+++ logging/log4j/trunk/docs/HISTORY.txt Wed Apr  5 22:32:38 2006
@@ -11,6 +11,8 @@
  - Release of version 1.3-alpha-9
    Release date: TBD
 
+ - Cleaned up FileWatchdog implementation.
+
    January 30th, 2006
  - Release of version 1.3alpha-8
    

Modified: logging/log4j/trunk/src/java/org/apache/log4j/PropertyConfigurator.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/PropertyConfigurator.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/PropertyConfigurator.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/PropertyConfigurator.java Wed Apr  5 22:32:38 2006
@@ -22,16 +22,13 @@
 import org.apache.log4j.config.ConfiguratorBase;
 import org.apache.log4j.config.PropertySetter;
 import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.helpers.Constants;
 import org.apache.log4j.or.RendererMap;
-import org.apache.log4j.spi.Configurator;
-import org.apache.log4j.spi.ErrorItem;
-import org.apache.log4j.spi.LoggerFactory;
-import org.apache.log4j.spi.LoggerRepository;
-import org.apache.log4j.spi.LoggerRepositoryEx;
 
 //import org.apache.log4j.config.PropertySetterException;
-import org.apache.log4j.spi.OptionHandler;
-import org.apache.log4j.spi.RendererSupport;
+import org.apache.log4j.spi.*;
+import org.apache.log4j.watchdog.FileWatchdog;
+import org.apache.log4j.plugins.PluginRegistry;
 
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -43,6 +40,8 @@
 import java.util.Properties;
 import java.util.StringTokenizer;
 import java.util.Vector;
+import java.net.URL;
+import java.net.MalformedURLException;
 
 
 /**
@@ -85,7 +84,8 @@
    @author Ceki Gülcü
    @author Anders Kristensen
    @since 0.8.1 */
-public class PropertyConfigurator extends ConfiguratorBase {
+public class PropertyConfigurator extends ConfiguratorBase
+    implements ConfiguratorEx {
   static final String CATEGORY_PREFIX = "log4j.category.";
   static final String LOGGER_PREFIX = "log4j.logger.";
   static final String FACTORY_PREFIX = "log4j.factory";
@@ -101,6 +101,9 @@
   public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
   private static final String INTERNAL_ROOT_NAME = "root";
 
+  private static Object watchdogLock = new Object();
+  private static FileWatchdog fileWatchdog = null;
+
   /**
      Used internally to keep track of configured appenders.
    */
@@ -348,6 +351,57 @@
   }
 
   /**
+    Like {@link #configureAndWatch(String, long)} except that the
+    default delay of 60 seconds is used.
+
+    @deprecated Use org.apache.log4j.watchdog.FileWatchdog directly.
+
+    @param configFilename A log4j configuration file in XML format.
+
+  */
+  static public void configureAndWatch(String configFilename) {
+    configureAndWatch(configFilename, 60000);
+  }
+
+  /**
+    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.
+
+    @deprecated Use org.apache.log4j.watchdog.FileWatchdog directly.
+
+    @param configFilename A log4j configuration file in XML format.
+    @param delay The delay in milliseconds to wait between each check.
+  */
+  static public void configureAndWatch(String configFilename, long delay) {
+    synchronized(watchdogLock) {
+      PluginRegistry pluginRegistry =
+        ((LoggerRepositoryEx)LogManager.getLoggerRepository()).getPluginRegistry();
+
+      // stop existing watchdog
+      if (fileWatchdog != null) {
+        pluginRegistry.stopPlugin(fileWatchdog.getName());
+        fileWatchdog = null;
+      }
+
+      // create the watchdog
+      fileWatchdog = new FileWatchdog();
+      fileWatchdog.setName("PropertyConfigurator.FileWatchdog");
+      fileWatchdog.setConfigurator(PropertyConfigurator.class.getName());
+      fileWatchdog.setFile(configFilename);
+      fileWatchdog.setInterval(delay);
+      fileWatchdog.setInitialConfigure(true);
+
+      // register and start the watchdog
+      pluginRegistry.addPlugin(fileWatchdog);
+      fileWatchdog.activateOptions();
+    }
+  }
+
+  /**
      Read configuration options from <code>properties</code>.
 
      See {@link #doConfigure(String, LoggerRepository)} for the expected format.
@@ -358,20 +412,20 @@
     try {
       // we start by attaching a temporary list appender
       attachListAppender(repository);
-      
+
       boolean attachedConsoleApepnder = false;
       if ((value != null) && OptionConverter.toBoolean(value, true)) {
         attachTemporaryConsoleAppender(repository);
         attachedConsoleApepnder = true;
       }
-
+      
       // As soon as we start configuration process, the pristine flag is set to 
       // false.
       if(repository instanceof LoggerRepositoryEx) {
         ((LoggerRepositoryEx) repository).setPristine(false);
       }
 
-      
+
       String thresholdStr =
         OptionConverter.findAndSubst(THRESHOLD_PREFIX, properties);
 
@@ -430,7 +484,7 @@
 
     doConfigure(props, repository);
   }
-  
+
   /**
    * Read configuration options from input stream <code>configStream</code>.
    * @since 1.3
@@ -438,7 +492,7 @@
    * @param repository
    */
   public void doConfigure(InputStream configStream,
-  LoggerRepository repository) {
+                          LoggerRepository repository) {
     Properties props = new Properties();
     getLogger(repository).debug(
       "Reading configuration from input stream");
@@ -679,7 +733,7 @@
           PropertySetter layoutPS = new PropertySetter(layout);
           layoutPS.setLoggerRepository(repository);
           layoutPS.setProperties(props, layoutPrefix + ".");
-          
+
           activateOptions(layout);
           getLogger(repository).debug(
             "End of parsing for \"" + appenderName + "\".");

Modified: logging/log4j/trunk/src/java/org/apache/log4j/joran/JoranConfigurator.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/joran/JoranConfigurator.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/joran/JoranConfigurator.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/joran/JoranConfigurator.java Wed Apr  5 22:32:38 2006
@@ -42,6 +42,7 @@
 import org.apache.log4j.joran.spi.SimpleRuleStore;
 import org.apache.log4j.spi.ErrorItem;
 import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.ConfiguratorEx;
 
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -68,7 +69,8 @@
  * @author Curt Arnold
  * @author <a href="http://www.qos.ch/log4j/">Ceki G&uuml;lc&uuml;</a>
  */
-public class JoranConfigurator extends ConfiguratorBase {
+public class JoranConfigurator extends ConfiguratorBase
+    implements ConfiguratorEx {
   private Interpreter joranInterpreter;
   private LoggerRepository repository;
 

Added: logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java (added)
+++ logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java Wed Apr  5 22:32:38 2006
@@ -0,0 +1,19 @@
+package org.apache.log4j.spi;
+
+import java.io.InputStream;
+
+/**
+ * Defines extended methods for Configurators to implement.
+ *
+ * @author Mark Womack
+ * @since 1.3
+ */
+public interface ConfiguratorEx {
+  /**
+   * Configures using an InputStream for input.
+   * 
+   * @param stream
+   * @param repository
+   */
+  public void doConfigure(InputStream stream, LoggerRepository repository);
+}

Propchange: logging/log4j/trunk/src/java/org/apache/log4j/spi/ConfiguratorEx.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: logging/log4j/trunk/src/java/org/apache/log4j/watchdog/FileWatchdog.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/watchdog/FileWatchdog.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/watchdog/FileWatchdog.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/watchdog/FileWatchdog.java Wed Apr  5 22:32:38 2006
@@ -16,21 +16,28 @@
 
 package org.apache.log4j.watchdog;
 
-import java.io.File;
-import java.net.URL;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.apache.log4j.scheduler.Job;
+
+import java.io.*;
 
 /**
  * Implements a watchdog to watch a file.  When the file changes, determined by
  * a change in the file's modification date, the contents of the file are use to
  * reconfigure the log4j environment.
  */
-public class FileWatchdog extends TimedLocationWatchdog {
+public class FileWatchdog extends WatchdogSkeleton implements Job {
+
+  public static final long DEFAULT_INTERVAL = 60000;
 
   private String filePath;
+  private long interval = DEFAULT_INTERVAL;
+  private boolean initialConfigure = false;
 
   /** The file being watched. */
   private File watchedFile;
-  private URL watchedURL;
+  private long lastModTime = -1;
 
   /**
    * Sets the path of the file to use and watch for configuration changes.
@@ -49,11 +56,60 @@
   public String getFile() {
     return filePath;
   }
+
+  /**
+   * Sets the interval of time between checks for file modifications.
+   *
+   * @param interval
+   */
+  public void setInterval(long interval) {
+    this.interval = interval;
+  }
+
+  /**
+   * Returns the interval of time between checks for file modifications.
+   *
+   * @return interval of time
+   */
+  public long getInterval() {
+    return interval;
+  }
+
+  /**
+   * Set to true if watchdog should configure with file before starting watch
+   * in activateOptions.
+   *
+   * @param initialConfigure
+   */
+  public void setInitialConfigure(boolean initialConfigure) {
+    this.initialConfigure = initialConfigure;
+  }
+
+  /**
+   * Returns true if watchdog will configure before starting watch in
+   * activateOptions.
+   *
+   * @return
+   */
+  public boolean getInitialConfigure() {
+    return initialConfigure;
+  }
+
+  /**
+   * Returns the last modification time of the watched file.
+   * 
+   * @return
+   */
+  public long getLastModTime() {
+    return lastModTime;
+  }
+
   /**
    * Sets up the reference to the file being watched, then calls the version
    * in the super class.
    */
   public void activateOptions() {
+    getLogger().debug("activateOptions called for watchdog " + this.getName());
 
     if (filePath == null) {
       getLogger().error("watchdog \"{}\" not configured with path to watch",
@@ -62,42 +118,83 @@
     }
 
     watchedFile = new File(filePath);
-    try {
-        //
-        //   attempt to invoke JDK 1.4's File.toURI and URI.toURL methods
-        //       which do a better job of escaping file names than File.toURL.
-        Object uri = File.class.getMethod("toURI", null).invoke(watchedFile, null);
-        watchedURL = (URL) uri.getClass().getMethod("toURL", null).invoke(uri, null);
-    } catch(Exception ex) {
-        try {
-            watchedURL = watchedFile.toURL();
-        } catch(java.net.MalformedURLException ex2) {
-            this.getLogger().error("Watchdog {} unable to express filename {} as a URL",
-              this.getName(), watchedFile.getName());
-        }
+
+    // do an initial configure or record the current mod time
+    if (initialConfigure) {
+      execute();
+    } else if (watchedFile.exists()) {
+      lastModTime = watchedFile.lastModified();
+    }
+
+    LoggerRepository repo = getLoggerRepository();
+    if (repo instanceof LoggerRepositoryEx) {
+        ((LoggerRepositoryEx) repo).getScheduler().schedule(this,
+      System.currentTimeMillis() + interval, interval);
+    } else {
+        this.getLogger().error("{} watchdog requires repository that supports LoggerRepositoryEx",
+          this.getName());
     }
-    super.activateOptions();
   }
 
+    /**
+   * Implements the Job interface for the Scheduler.  When this method is called
+   * by the Scheduler it checks the current modification time of the watched
+   * source with the last recorded modification time.  If the modification times
+   * are different, then the log4j environment is reconfigured using the
+   * watched source for the configuration data.
+   */
+  public void execute() {
+    getLogger().debug("FileWatchdog \"{}\" executing", this.getName());
+    if (watchedFile.exists()) {
+      long curModTime = watchedFile.lastModified();
+      getLogger().debug("Checking times for watchdog " + this.getName() +
+        " :(lastModTime - " + lastModTime + ") ?? (curModTime - " +
+        curModTime + ")");
+      if (curModTime != lastModTime) {
+        if (reconfigure()) {
+          lastModTime = curModTime;
+          getLogger().debug("Reconfiguration successful for watchdog " +
+            this.getName());
+        } else {
+          getLogger().debug("Reconfiguration not successful for watchdog " +
+            this.getName() + ", not updating mod time");
+        }
+      } else {
+        getLogger().debug("Times matched, doing nothing");
+      }
+    } else {
+      getLogger().debug("File does not exist, doing nothing");
+    }
+  }
   /**
-   * Returns the modification of the file being watched.
-   * 
-   * @return The modification time of the file.
+   * Shutdown this watchdog.  Since implemented as a scheduled Job, this method
+   * simply removes the watchdog from the Scheduler.
    */
-  public long getModificationTime() {
-    return watchedFile.lastModified();
+  public void shutdown() {
+    LoggerRepository repo = getLoggerRepository();
+    if (repo instanceof LoggerRepositoryEx) {
+        ((LoggerRepositoryEx) repo).getScheduler().delete(this);
+    }
   }
-
   /**
    * Reconfigures the log4j environment using the file as the source of the
    * configuration data.
    */
-  public void reconfigure() {
-    if (watchedFile.exists() && watchedURL != null) {
-        reconfigureByURL(watchedURL);
-    } else {
-        this.getLogger().warn("{} watchdog cannot find file {}",
-          this.getName(), watchedFile.getName());
+  public boolean reconfigure() {
+    InputStream stream = null;
+    try {
+      stream = new FileInputStream(watchedFile);
+      return reconfigureByStream(stream);
+    } catch (FileNotFoundException e) {
+      return false;
+    } finally {
+      if (stream != null) {
+        try {
+          stream.close();
+        } catch (IOException e2) {
+          // ignore
+        }
+      }
     }
   }
 }

Modified: logging/log4j/trunk/src/java/org/apache/log4j/watchdog/Watchdog.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/watchdog/Watchdog.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/watchdog/Watchdog.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/watchdog/Watchdog.java Wed Apr  5 22:32:38 2006
@@ -62,7 +62,9 @@
   /**
    * Called to reconfigure the log4j environment when the monitored data
    * source has been updated.
+   *
+   * @return True if reconfiguration was without errors
    */
-  public void reconfigure();
+  public boolean reconfigure();
   
 }

Modified: logging/log4j/trunk/src/java/org/apache/log4j/watchdog/WatchdogSkeleton.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/watchdog/WatchdogSkeleton.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/watchdog/WatchdogSkeleton.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/watchdog/WatchdogSkeleton.java Wed Apr  5 22:32:38 2006
@@ -18,12 +18,15 @@
 
 
 import org.apache.log4j.PropertyConfigurator;
+import org.apache.log4j.config.ConfiguratorBase;
 import org.apache.log4j.spi.Configurator;
+import org.apache.log4j.spi.ConfiguratorEx;
 import org.apache.log4j.plugins.PluginSkeleton;
 import org.apache.log4j.helpers.OptionConverter;
 
-import java.io.InputStream;
 import java.net.URL;
+import java.io.InputStream;
+import java.util.List;
 
 /**
   Implements the required interface for Watchdog objects.
@@ -34,7 +37,7 @@
   required.  Developers may choose to implement their own version of the
   Watchdog interface (which extends the base Plugin interface) if they so 
   choose.
-  
+
   <p>This implementation provides two helper methods, reconfigureByURL and
   reconfigureByInputStream.  Either of these methods can be called from the
   implemented reconfigure method, as required by the specific type of data
@@ -42,18 +45,18 @@
   that can be described by a URL (ie file, url).  The rconfigureByInputStream
   method is meant for sources where onl a stream of data is available
   (ie socket).
-  
+
   <p>Subclasses of this implementation are required to implement their own
   version of the abstract reconfigure method.
 
   @author Mark Womack <mwomack@apache.org>
   @since 1.3
 */
-public abstract class WatchdogSkeleton 
+public abstract class WatchdogSkeleton
 extends PluginSkeleton implements Watchdog {
-  
+
   protected String configuratorClassName;
-  
+
   /**
    * Sets the Configurator class used for reconfiguration.
    *
@@ -63,7 +66,7 @@
    public void setConfigurator(String configuratorClassName) {
      this.configuratorClassName = configuratorClassName;
    }
-  
+
   /**
    * Returns the configurator class used for reconfiguration.
    *
@@ -77,8 +80,8 @@
    * Called to reconfigure the log4j environment when the monitored data
    * source has been updated.  Must be implemented by subclasses.
    */
-  public abstract void reconfigure();
-  
+  public abstract boolean reconfigure();
+
   /**
    * Helper method to get an instance of the configurator class.
    *
@@ -87,21 +90,21 @@
    */
   protected Configurator getConfiguratorInstance() {
     // create an instance of the configurator class
-    Configurator configurator = null;
-    
+    Configurator configurator;
+
     // if we were configured with a configurator class name, use it
     if (configuratorClassName != null) {
       configurator = (Configurator) OptionConverter.instantiateByClassName(
-      	configuratorClassName, Configurator.class, null);
+        configuratorClassName, Configurator.class, null);
     }
     // otherwise, default to PropertyConfigurator
     else {
       configurator = new PropertyConfigurator();
     }
-    
+
     return configurator;
   }
-  
+
   /**
    * Helper method to reconfigure using a URL.
    * The input parameter, configurationURL, should be a URL pointing to
@@ -109,24 +112,88 @@
    *
    * @param srcURL The url that contains the data to be used for
    *   reconfiguration.
+   * @return True if the reconfiguration was without error
    */
-  protected void reconfigureByURL(URL srcURL) {
+  protected boolean reconfigureByURL(URL srcURL) {
     if (this.getLogger().isDebugEnabled()) {
       this.getLogger().debug("watchdog \"{}\" reconfiguring from url: {}",
         this.getName(), srcURL);
     }
-    
+
     // create an instance of the configurator class
     Configurator configurator = getConfiguratorInstance();
-    
+
     // if able to create configurator, then reconfigure using input stream
     if (configurator != null) {
       configurator.doConfigure(srcURL, this.getLoggerRepository());
+      if (configurator instanceof ConfiguratorBase) {
+        ConfiguratorBase baseConfigurator = (ConfiguratorBase)configurator;
+        List errorList = baseConfigurator.getErrorList();
+        getLogger().error("errors reported during reconfiguration: ");
+        if (errorList.size() != 0) {
+          for (int x = 0; x < errorList.size(); x++) {
+            getLogger().debug("error " + x + ": " + errorList.get(x));
+          }
+          return false;
+        }
+      }
+    }
+    else {
+      getLogger().error(
+        "watchdog \"{}\" could not create configurator, ignoring new configuration settings",
+        this.getName());
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * Helper method to reconfigure using an InputStream.
+   *
+   * @param stream The stream of data to be used for reconfiguration.
+   * @return True if the reconfiguration was without error
+   */
+  protected boolean reconfigureByStream(InputStream stream) {
+    if (this.getLogger().isDebugEnabled()) {
+      this.getLogger().debug("watchdog \"{}\" reconfiguring by stream",
+        this.getName());
     }
-	  else {
-	    getLogger().error(
+
+    // create an instance of the configurator class
+    Configurator configurator = getConfiguratorInstance();
+    ConfiguratorEx configuratorEx = null;
+
+    if (configurator instanceof ConfiguratorEx) {
+      configuratorEx = (ConfiguratorEx)configurator;
+    } else {
+      getLogger().error(
+        "watchdog \"{}\" could not create configurator, configurator class is not of type ConfiguratorEx",
+        this.getName());
+    }
+
+    // if able to create configurator, then reconfigure using input stream
+    if (configuratorEx != null) {
+      configuratorEx.doConfigure(stream, this.getLoggerRepository());
+      if (configuratorEx instanceof ConfiguratorBase) {
+        ConfiguratorBase baseConfigurator = (ConfiguratorBase)configuratorEx;
+        List errorList = baseConfigurator.getErrorList();
+        getLogger().error("errors reported during reconfiguration: ");
+        if (errorList.size() != 0) {
+          for (int x = 0; x < errorList.size(); x++) {
+            getLogger().debug("error " + x + ": " + errorList.get(x));
+          }
+          return false;
+        }
+      }
+    }
+    else {
+      getLogger().error(
         "watchdog \"{}\" could not create configurator, ignoring new configuration settings",
         this.getName());
-	  }
+      return false;
+    }
+
+    return true;
   }
 }

Modified: logging/log4j/trunk/src/java/org/apache/log4j/xml/DOMConfigurator.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/xml/DOMConfigurator.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/xml/DOMConfigurator.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/xml/DOMConfigurator.java Wed Apr  5 22:32:38 2006
@@ -19,6 +19,9 @@
 import org.apache.log4j.LogManager;
 import org.apache.log4j.joran.JoranConfigurator;
 import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.apache.log4j.plugins.PluginRegistry;
+import org.apache.log4j.watchdog.FileWatchdog;
 
 import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
@@ -29,6 +32,7 @@
 import org.xml.sax.helpers.DefaultHandler;
 
 import java.net.URL;
+import java.net.MalformedURLException;
 
 import javax.xml.parsers.SAXParser;
 
@@ -62,6 +66,10 @@
    @deprecated Replaced by the much more flexible {@link org.apache.log4j.joran.JoranConfigurator}.
    @since 0.8.3 */
 public class DOMConfigurator extends JoranConfigurator {
+
+  private static Object watchdogLock = new Object();
+  private static FileWatchdog fileWatchdog = null;
+  
   public static void configure(String file) {
     JoranConfigurator joran = new JoranConfigurator();
     joran.doConfigure(file, LogManager.getLoggerRepository());
@@ -92,6 +100,57 @@
     doConfigure(action, repository);
   }
 
+  /**
+    Like {@link #configureAndWatch(String, long)} except that the
+    default delay of 60 seconds is used.
+    
+    @deprecated Use org.apache.log4j.watchdog.FileWatchdog directly.
+    
+    @param configFilename A log4j configuration file in XML format.
+    
+  */
+  static public void configureAndWatch(String configFilename) {
+    configureAndWatch(configFilename, 60000);
+  }
+
+  /**
+    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.
+
+    @deprecated Use org.apache.log4j.watchdog.FileWatchdog directly.
+    
+    @param configFilename A log4j configuration file in XML format.
+    @param delay The delay in milliseconds to wait between each check.
+  */
+  static public void configureAndWatch(String configFilename, long delay) {
+    synchronized(watchdogLock) {
+      PluginRegistry pluginRegistry = 
+        ((LoggerRepositoryEx)LogManager.getLoggerRepository()).getPluginRegistry();
+          
+      // stop existing watchdog
+      if (fileWatchdog != null) {
+        pluginRegistry.stopPlugin(fileWatchdog.getName());
+        fileWatchdog = null;
+      }
+      
+      // create the watchdog
+      fileWatchdog = new FileWatchdog();
+      fileWatchdog.setName("DOMConfigurator.FileWatchdog");
+      fileWatchdog.setConfigurator(DOMConfigurator.class.getName());
+      fileWatchdog.setFile(configFilename);
+      fileWatchdog.setInterval(delay);
+      fileWatchdog.setInitialConfigure(true);
+      
+      // register and start the watchdog
+      pluginRegistry.addPlugin(fileWatchdog);
+      fileWatchdog.activateOptions();
+    }
+  }
+  
   /**
    *  Class that "parses" a DOM element by replaying the
    * corresponding SAX events.

Added: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml (added)
+++ logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml Wed Apr  5 22:32:38 2006
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration >
+
+<log4j:configuration xmlns:log4j="http://logging.apache.org/">
+
+<!-- we just want a badly configured file here -->
+  
+<!--/log4j:configuration-->

Propchange: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test3_1.xml
------------------------------------------------------------------------------
    svn:executable = *

Added: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml (added)
+++ logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml Wed Apr  5 22:32:38 2006
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration >
+
+<log4j:configuration xmlns:log4j="http://logging.apache.org/">
+
+  <appender name="A1" class="org.apache.log4j.FileAppender">
+  
+    <param name="Append" value="false" />
+    <param name="File"   value="output/watchdog.FileWatchdog.test5.txt" />
+    
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%p - %m%n"/>
+    </layout>
+  </appender>
+
+  <appender name="A2" class="org.apache.log4j.ConsoleAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{ABSOLUTE} %c [%p] - %m%n"/>
+    </layout>
+  </appender>
+  
+  <logger name="org.apache.log4j">
+    <level value="info"/>
+  </logger>
+  
+  <logger name="test.FileWatchdogTestCase">
+    <appender-ref ref="A1" />	
+    <level value="debug"/>
+  </logger>
+
+  <logger name="org.apache.log4j.watchdog">
+    <level value="debug"/>
+  </logger>
+  
+  <root>
+    <appender-ref ref="A2"/>
+    <level value="debug" />
+  </root>
+  
+</log4j:configuration>

Propchange: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_1.xml
------------------------------------------------------------------------------
    svn:executable = *

Added: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml (added)
+++ logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml Wed Apr  5 22:32:38 2006
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration >
+
+<log4j:configuration xmlns:log4j="http://logging.apache.org/">
+  
+  <logger name="test.FileWatchdogTestCase">
+    <level value="info"/>
+  </logger>
+  
+</log4j:configuration>

Propchange: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test5_2.xml
------------------------------------------------------------------------------
    svn:executable = *

Added: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties (added)
+++ logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties Wed Apr  5 22:32:38 2006
@@ -0,0 +1,20 @@
+log4j.debug=TRUE
+log4j.threshold=ON
+
+log4j.rootLogger=DEBUG,A2
+
+log4j.appender.A1=org.apache.log4j.FileAppender
+log4j.appender.A1.File=output/watchdog.FileWatchdog.test6.txt
+log4j.appender.A1.Append=false
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%p - %m%n
+
+log4j.appender.A2=org.apache.log4j.ConsoleAppender
+log4j.appender.A2.layout=org.apache.log4j.PatternLayout
+log4j.appender.A2.layout.ConversionPattern=%d{ABSOLUTE} %c [%p] - %m%n
+
+#log4j.logger.org.apache.log4j=WARN
+log4j.logger.test.FileWatchdogTestCase=DEBUG,A1
+log4j.logger.org.apache.log4j.watchdog.FileWatchdogTestCase=DEBUG
+log4j.logger.org.apache.log4j=INFO
+log4j.logger.org.apache.log4j.watchdog=DEBUG

Propchange: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_1.properties
------------------------------------------------------------------------------
    svn:executable = *

Added: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties (added)
+++ logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties Wed Apr  5 22:32:38 2006
@@ -0,0 +1,10 @@
+log4j.debug=TRUE
+log4j.threshold=ON
+
+log4j.appender.A1=org.apache.log4j.FileAppender
+log4j.appender.A1.File=output/watchdog.FileWatchdog.test6.txt
+log4j.appender.A1.Append=true
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%p - %m%n
+
+log4j.logger.test.FileWatchdogTestCase=INFO,A1

Propchange: logging/log4j/trunk/tests/input/watchdog/watchdog.FileWatchdog.test6_2.properties
------------------------------------------------------------------------------
    svn:executable = *

Modified: logging/log4j/trunk/tests/src/java/org/apache/log4j/watchdog/FileWatchdogTestCase.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/src/java/org/apache/log4j/watchdog/FileWatchdogTestCase.java?rev=391905&r1=391904&r2=391905&view=diff
==============================================================================
--- logging/log4j/trunk/tests/src/java/org/apache/log4j/watchdog/FileWatchdogTestCase.java (original)
+++ logging/log4j/trunk/tests/src/java/org/apache/log4j/watchdog/FileWatchdogTestCase.java Wed Apr  5 22:32:38 2006
@@ -29,7 +29,7 @@
 import org.apache.log4j.spi.LoggerRepositoryEx;
 import org.apache.log4j.joran.JoranConfigurator;
 import org.apache.log4j.Level;
-
+import org.apache.log4j.xml.DOMConfigurator;
 
 public class FileWatchdogTestCase extends TestCase {
 
@@ -46,8 +46,16 @@
 
     private void copyFile(File src, File dst) throws Exception {
       if (dst.exists()) {
-          assertTrue(dst.delete());
+        for (int x = 0; x < 5; x++) {
+          if (x == 4) {
+            assertTrue("File " + dst.getAbsolutePath() +
+            " not deleted", false);
+          }
+          if (dst.delete()) break;
+          Thread.sleep(750);
+        }
       }
+
       FileOutputStream out = new FileOutputStream(dst);
       FileInputStream in = new FileInputStream(src);
       byte[] buffer = new byte[1024];
@@ -101,9 +109,10 @@
     }
 
     // basic test of plugin in standalone mode
-    public void test1() throws Exception {
+    public void testJoranConfigurator() throws Exception {
       LogManager.getLoggerRepository().resetConfiguration();
-      
+      logger.setLevel(Level.DEBUG);
+
       File outFile = new File(getOutputFile("test1"));
       if (outFile.exists()) {
           assertTrue(outFile.delete());
@@ -120,14 +129,14 @@
       // move the first config file into place
       copyFile(sourceFile1, configFile);
       assertTrue(configFile.exists());
-      
+
       testLogger.debug("first config file in place: " + configFile.getAbsolutePath());
 
       // configure environment to first config file
       JoranConfigurator configurator = new JoranConfigurator();
       configurator.doConfigure(configFile.getAbsolutePath(),
           LogManager.getLoggerRepository());
-      
+
       testLogger.debug("log4j configured with configFile");
 
       // now watch the file for changes
@@ -138,7 +147,7 @@
       watchdog.setConfigurator(JoranConfigurator.class.getName());
       ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(watchdog);
       watchdog.activateOptions();
-      
+
       testLogger.debug("watchdog activated");
 
       // output some test messages
@@ -147,16 +156,16 @@
       logger.warn("warn message");
       logger.error("error message");
       logger.fatal("fatal message");
-      
+
       testLogger.debug("first set of test messages output");
 
       Thread.sleep(2000);
-      
+
       testLogger.debug("about to copy second config file");
-      
+
       // copy over a new version of the config file
       copyFile(sourceFile2, configFile);
-      
+
       testLogger.debug("second config file copied");
 
       // wait a few seconds for the watchdog to react
@@ -171,7 +180,7 @@
               logger.warn("warn message");
               logger.error("error message");
               logger.fatal("fatal message");
-              
+
               testLogger.debug("second set of test messages output");
 
               assertTrue(Compare.compare(getOutputFile("test1"),
@@ -181,88 +190,398 @@
           testLogger.debug("looping for level check");
       }
       fail("Expected change in level did not occur within 20 seconds.");
+  }
+
+  // basic test of plugin in standalone mode with PropertyConfigurator
+  public void testPropertyConfigurator() throws Exception {
+    LogManager.getLoggerRepository().resetConfiguration();
+    logger.setLevel(Level.DEBUG);
+
+    File outFile = new File(getOutputFile("test2"));
+    if (outFile.exists()) {
+          assertTrue(outFile.delete());
     }
 
-    // basic test of plugin in standalone mode with PropertyConfigurator
-    public void test2() throws Exception {
-      LogManager.getLoggerRepository().resetConfiguration();
-      
-      File outFile = new File(getOutputFile("test2"));
-      if (outFile.exists()) {
-            assertTrue(outFile.delete());
+    // set up the needed file references
+    File sourceFile1 = new File(getSourceConfigFile("test2", 1));
+    File sourceFile2 = new File(getSourceConfigFile("test2", 2));
+    assertTrue(sourceFile1.exists());
+    assertTrue(sourceFile2.exists());
+
+    File configFile = new File(getConfigFile("test2"));
+
+    // move the first config file into place
+    copyFile(sourceFile1, configFile);
+    assertTrue(configFile.exists());
+
+    testLogger.debug("first config file in place: " + configFile.getAbsolutePath());
+
+    // configure environment to first config file
+    PropertyConfigurator configurator = new PropertyConfigurator();
+    configurator.doConfigure(configFile.getAbsolutePath(),
+        LogManager.getLoggerRepository());
+
+    testLogger.debug("log4j configured with configFile");
+
+    // now watch the file for changes
+    FileWatchdog watchdog = new FileWatchdog();
+    watchdog.setName("test2");
+    watchdog.setFile(configFile.getAbsolutePath());
+    watchdog.setInterval(1000);
+    watchdog.setConfigurator(PropertyConfigurator.class.getName());
+    ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(watchdog);
+    watchdog.activateOptions();
+
+    testLogger.debug("watchdog activated");
+
+    // output some test messages
+    logger.debug("debug message");
+    logger.info("info message");
+    logger.warn("warn message");
+    logger.error("error message");
+    logger.fatal("fatal message");
+
+    testLogger.debug("first set of test messages output");
+
+    Thread.sleep(2000);
+
+    testLogger.debug("about to copy second config file");
+
+    // copy over a new version of the config file
+    copyFile(sourceFile2, configFile);
+
+    testLogger.debug("second config file copied");
+
+    // wait a few seconds for the watchdog to react
+    for (int i = 0; i < 40; i++) {
+        testLogger.debug("sleeping for 500 ms");
+        Thread.sleep(500);
+        testLogger.debug("level for logger " + logger.getName() + " is " + logger.getLevel());
+        if (logger.getLevel() == Level.INFO) {
+            // output some test messages
+            logger.debug("debug message");
+            logger.info("info message");
+            logger.warn("warn message");
+            logger.error("error message");
+            logger.fatal("fatal message");
+
+            testLogger.debug("second set of test messages output");
+            Thread.sleep(500);
+
+            assertTrue("output does not match", Compare.compare(getOutputFile("test2"),
+              getWitnessFile("test2")));
+            return;
+        }
+        testLogger.debug("looping for level check");
+    }
+    fail("Expected change in level did not occur within 20 seconds.");
+  }
+
+  public void testJoranConfigurationError() throws Exception {
+    LogManager.getLoggerRepository().resetConfiguration();
+    logger.setLevel(Level.DEBUG);
+
+    File outFile = new File(getOutputFile("test3"));
+    if (outFile.exists()) {
+        assertTrue(outFile.delete());
+    }
+
+    // set up the needed file references
+    File sourceFile1 = new File(getSourceXMLConfigFile("test3", 1));
+    File sourceFile2 = new File(getSourceXMLConfigFile("test1", 2));
+    assertTrue(sourceFile1.exists());
+    assertTrue(sourceFile2.exists());
+
+    // config file should not exist yet
+    File configFile = new File(getXMLConfigFile("test3"));
+    assertFalse(configFile.exists());
+
+    // now watch the nonexistent file for changes
+    FileWatchdog watchdog = new FileWatchdog();
+    watchdog.setName("test3");
+    watchdog.setFile(configFile.getAbsolutePath());
+    watchdog.setInterval(1000);
+    watchdog.setConfigurator(JoranConfigurator.class.getName());
+    ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(watchdog);
+    watchdog.activateOptions();
+
+    testLogger.debug("watchdog activated");
+
+    // the file does not exist, so the modification time should never change
+    long modTime = watchdog.getLastModTime();
+    for (int count = 0; count < 5; count++) {
+      if (modTime != watchdog.getLastModTime()) {
+        assertTrue("watchdog mod time changed when no file", false);
       }
+      Thread.sleep(500);
+    }
 
-      // set up the needed file references
-      File sourceFile1 = new File(getSourceConfigFile("test2", 1));
-      File sourceFile2 = new File(getSourceConfigFile("test2", 2));
-      assertTrue(sourceFile1.exists());
-      assertTrue(sourceFile2.exists());
+    testLogger.debug("no file, mod time not changed: " + modTime);
 
-      File configFile = new File(getConfigFile("test2"));
+    // move the bad config file into place
+    copyFile(sourceFile1, configFile);
+    assertTrue(configFile.exists());
+
+    testLogger.debug("bad config file put into place");
+
+    // the file is "bad", so the modification time should never change
+    for (int count = 0; count < 7; count++) {
+      if (modTime != watchdog.getLastModTime()) {
+        assertTrue("watchdog mod time changed for bad file", false);
+      }
+      Thread.sleep(500);
+    }
 
-      // move the first config file into place
-      copyFile(sourceFile1, configFile);
-      assertTrue(configFile.exists());
-      
-      testLogger.debug("first config file in place: " + configFile.getAbsolutePath());
+    testLogger.debug("bad file, mod time not changed: " + modTime);
 
-      // configure environment to first config file
-      PropertyConfigurator configurator = new PropertyConfigurator();
-      configurator.doConfigure(configFile.getAbsolutePath(),
-          LogManager.getLoggerRepository());
-      
-      testLogger.debug("log4j configured with configFile");
+    // move the good config file into place
+    copyFile(sourceFile2, configFile);
+    assertTrue(configFile.exists());
+
+    testLogger.debug("moved good config file into place");
+
+    // the file is good, so the modification time and level should change
+    for (int count = 0; count < 7; count++) {
+      if (modTime != watchdog.getLastModTime()) {
+        assertTrue(logger.getLevel() == Level.INFO);
+        break;
+      }
 
-      // now watch the file for changes
-      FileWatchdog watchdog = new FileWatchdog();
-      watchdog.setName("test2");
-      watchdog.setFile(configFile.getAbsolutePath());
-      watchdog.setInterval(1000);
-      watchdog.setConfigurator(PropertyConfigurator.class.getName());
-      ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(watchdog);
-      watchdog.activateOptions();
-      
-      testLogger.debug("watchdog activated");
+      if (count == 6) {
+        assertTrue("mod time for good file never changed", false);
+      }
 
-      // output some test messages
-      logger.debug("debug message");
-      logger.info("info message");
-      logger.warn("warn message");
-      logger.error("error message");
-      logger.fatal("fatal message");
-      
-      testLogger.debug("first set of test messages output");
+      Thread.sleep(500);
+    }
 
-      Thread.sleep(2000);
-      
-      testLogger.debug("about to copy second config file");
-      
-      // copy over a new version of the config file
-      copyFile(sourceFile2, configFile);
-      
-      testLogger.debug("second config file copied");
+    testLogger.debug("good file, modTime changed: " + modTime);
+  }
 
-      // wait a few seconds for the watchdog to react
-      for (int i = 0; i < 40; i++) {
-          testLogger.debug("sleeping for 500 ms");
-          Thread.sleep(500);
-          testLogger.debug("level for logger " + logger.getName() + " is " + logger.getLevel());
-          if (logger.getLevel() == Level.INFO) {
-              // output some test messages
-              logger.debug("debug message");
-              logger.info("info message");
-              logger.warn("warn message");
-              logger.error("error message");
-              logger.fatal("fatal message");
-              
-              testLogger.debug("second set of test messages output");
+  public void testPropertyConfigurationError() throws Exception {
+    LogManager.getLoggerRepository().resetConfiguration();
+    logger.setLevel(Level.DEBUG);
+
+    File outFile = new File(getOutputFile("test4"));
+    if (outFile.exists()) {
+        assertTrue(outFile.delete());
+    }
 
-              assertTrue(Compare.compare(getOutputFile("test2"),
-                getWitnessFile("test2")));
-              return;
-          }
-          testLogger.debug("looping for level check");
+    // set up the needed file references
+    // need a "bad" property file
+    //File sourceFile1 = new File(getSourceConfigFile("test4", 1));
+    File sourceFile2 = new File(getSourceConfigFile("test2", 2));
+    //assertTrue(sourceFile1.exists());
+    assertTrue(sourceFile2.exists());
+
+    // config file should not exist yet
+    File configFile = new File(getConfigFile("test4"));
+    assertFalse(configFile.exists());
+
+    // now watch the nonexistent file for changes
+    FileWatchdog watchdog = new FileWatchdog();
+    watchdog.setName("test4");
+    watchdog.setFile(configFile.getAbsolutePath());
+    watchdog.setInterval(1000);
+    watchdog.setConfigurator(PropertyConfigurator.class.getName());
+    ((LoggerRepositoryEx) LogManager.getLoggerRepository()).getPluginRegistry().addPlugin(watchdog);
+    watchdog.activateOptions();
+
+    testLogger.debug("watchdog activated");
+
+    // the file does not exist, so the modification time should never change
+    long modTime = watchdog.getLastModTime();
+    for (int count = 0; count < 5; count++) {
+      if (modTime != watchdog.getLastModTime()) {
+        assertTrue("watchdog mod time changed when no file", false);
       }
-      fail("Expected change in level did not occur within 20 seconds.");
+      Thread.sleep(500);
+    }
+
+    testLogger.debug("no file, mod time not changed: " + modTime);
+
+/* need a "bad" property file
+    // move the bad config file into place
+    copyFile(sourceFile1, configFile);
+    assertTrue(configFile.exists());
+
+    testLogger.debug("bad config file put into place");
+
+    // the file is "bad", so the modification time should never change
+    for (int count = 0; count < 7; count++) {
+      if (modTime != watchdog.getLastModTime()) {
+        assertTrue("watchdog mod time changed for bad file", false);
+      }
+      Thread.sleep(500);
+    }
+
+    testLogger.debug("bad file, mod time not changed: " + modTime);
+*/
+
+    // move the good config file into place
+    copyFile(sourceFile2, configFile);
+    assertTrue(configFile.exists());
+
+    testLogger.debug("moved good config file into place");
+
+    // the file is good, so the modification time and level should change
+    for (int count = 0; count < 7; count++) {
+      if (modTime != watchdog.getLastModTime()) {
+        assertTrue(logger.getLevel() == Level.INFO);
+        break;
+      }
+
+      if (count == 6) {
+        assertTrue("mod time for good file never changed", false);
+      }
+
+      Thread.sleep(500);
+    }
+
+    testLogger.debug("good file, modTime changed: " + modTime);
+  }
+
+  public void testDOMConfigureAndWatch() throws Exception {
+    LogManager.getLoggerRepository().resetConfiguration();
+    logger.setLevel(Level.DEBUG);
+
+    File outFile = new File(getOutputFile("test5"));
+    if (outFile.exists()) {
+        assertTrue(outFile.delete());
+    }
+
+    // set up the needed file references
+    File sourceFile1 = new File(getSourceXMLConfigFile("test5", 1));
+    File sourceFile2 = new File(getSourceXMLConfigFile("test5", 2));
+    assertTrue(sourceFile1.exists());
+    assertTrue(sourceFile2.exists());
+
+    File configFile = new File(getXMLConfigFile("test5"));
+
+    // move the first config file into place
+    copyFile(sourceFile1, configFile);
+    assertTrue(configFile.exists());
+
+    testLogger.debug("first config file in place: " + configFile.getAbsolutePath());
+
+    // now watch the file for changes
+    DOMConfigurator.configureAndWatch(configFile.getAbsolutePath(), 1000);
+
+    testLogger.debug("configureAndWatch activated");
+
+    // output some test messages
+    logger.debug("debug message");
+    logger.info("info message");
+    logger.warn("warn message");
+    logger.error("error message");
+    logger.fatal("fatal message");
+
+    testLogger.debug("first set of test messages output");
+
+    Thread.sleep(2000);
+
+    testLogger.debug("about to copy second config file");
+
+    // copy over a new version of the config file
+    copyFile(sourceFile2, configFile);
+
+    testLogger.debug("second config file copied");
+
+    // wait a few seconds for the watchdog to react
+    for (int i = 0; i < 40; i++) {
+        testLogger.debug("sleeping for 500 ms");
+        Thread.sleep(500);
+        testLogger.debug("level for logger " + logger.getName() + " is " + logger.getLevel());
+        if (logger.getLevel() == Level.INFO) {
+            // output some test messages
+            logger.debug("debug message");
+            logger.info("info message");
+            logger.warn("warn message");
+            logger.error("error message");
+            logger.fatal("fatal message");
+
+            testLogger.debug("second set of test messages output");
+            Thread.sleep(500);
+
+            assertTrue("output does not match", Compare.compare(getOutputFile("test5"),
+              getWitnessFile("test5")));
+            return;
+        }
+        testLogger.debug("looping for level check");
+    }
+    fail("Expected change in level did not occur within 20 seconds.");
+  }
+
+  /* there is a bug in property configurator where it will not work a second
+     time, so commenting this out for now
+  public void testPropertyConfigureAndWatch() throws Exception {
+    LogManager.getLoggerRepository().resetConfiguration();
+    logger.setLevel(Level.DEBUG);
+
+    File outFile = new File(getOutputFile("test6"));
+    if (outFile.exists()) {
+          assertTrue(outFile.delete());
+    }
+
+    // set up the needed file references
+    File sourceFile1 = new File(getSourceConfigFile("test6", 1));
+    File sourceFile2 = new File(getSourceConfigFile("test6", 2));
+    assertTrue(sourceFile1.exists());
+    assertTrue(sourceFile2.exists());
+
+    File configFile = new File(getConfigFile("test6"));
+
+    // move the first config file into place
+    copyFile(sourceFile1, configFile);
+    assertTrue(configFile.exists());
+
+    testLogger.debug("first config file in place: " + configFile.getAbsolutePath());
+
+    // now watch the file for changes
+    PropertyConfigurator.configureAndWatch(configFile.getAbsolutePath(), 1000);
+
+    testLogger.debug("configureAndWatch activated");
+
+    // output some test messages
+    logger.debug("debug message");
+    logger.info("info message");
+    logger.warn("warn message");
+    logger.error("error message");
+    logger.fatal("fatal message");
+
+    testLogger.debug("first set of test messages output");
+
+    Thread.sleep(2000);
+
+    testLogger.debug("about to copy second config file");
+
+    // copy over a new version of the config file
+    copyFile(sourceFile2, configFile);
+
+    testLogger.debug("second config file copied");
+
+    // wait a few seconds for the watchdog to react
+    for (int i = 0; i < 40; i++) {
+        testLogger.debug("sleeping for 500 ms");
+        Thread.sleep(500);
+        testLogger.debug("level for logger " + logger.getName() + " is " + logger.getLevel());
+        if (logger.getLevel() == Level.INFO) {
+            // output some test messages
+            logger.debug("debug message");
+            logger.info("info message");
+            logger.warn("warn message");
+            logger.error("error message");
+            logger.fatal("fatal message");
+
+            testLogger.debug("second set of test messages output");
+            Thread.sleep(1000);
+
+            assertTrue("output does not match", Compare.compare(getOutputFile("test6"),
+              getWitnessFile("test6")));
+            return;
+        }
+        testLogger.debug("looping for level check");
     }
+    fail("Expected change in level did not occur within 20 seconds.");
+  }
+  */
 }

Added: logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt (added)
+++ logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt Wed Apr  5 22:32:38 2006
@@ -0,0 +1,9 @@
+DEBUG - debug message
+INFO - info message
+WARN - warn message
+ERROR - error message
+FATAL - fatal message
+INFO - info message
+WARN - warn message
+ERROR - error message
+FATAL - fatal message

Propchange: logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test5.txt
------------------------------------------------------------------------------
    svn:executable = *

Added: logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt?rev=391905&view=auto
==============================================================================
--- logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt (added)
+++ logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt Wed Apr  5 22:32:38 2006
@@ -0,0 +1,9 @@
+DEBUG - debug message
+INFO - info message
+WARN - warn message
+ERROR - error message
+FATAL - fatal message
+INFO - info message
+WARN - warn message
+ERROR - error message
+FATAL - fatal message

Propchange: logging/log4j/trunk/tests/witness/watchdog/watchdog.FileWatchdog.test6.txt
------------------------------------------------------------------------------
    svn:executable = *



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


Mime
View raw message