You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by ca...@apache.org on 2006/04/29 06:12:32 UTC

svn commit: r398080 - in /logging/log4j/trunk: src/java/org/apache/log4j/ src/java/org/apache/log4j/varia/ tests/ tests/input/ tests/input/rolling/ tests/src/java/org/apache/log4j/ tests/src/java/org/apache/log4j/rolling/ tests/src/java/org/apache/log4...

Author: carnold
Date: Fri Apr 28 21:12:29 2006
New Revision: 398080

URL: http://svn.apache.org/viewcvs?rev=398080&view=rev
Log:
Bug 39023: o.a.l.DRFA, RFA and .varia.ERFA not compatibile

Added:
    logging/log4j/trunk/tests/input/RFA1.properties
    logging/log4j/trunk/tests/src/java/org/apache/log4j/DRFATestCase.java
    logging/log4j/trunk/tests/src/java/org/apache/log4j/RFATestCase.java
    logging/log4j/trunk/tests/src/java/org/apache/log4j/varia/ERFATestCase.java
Removed:
    logging/log4j/trunk/tests/input/rolling/obsoleteDRFA1.properties
    logging/log4j/trunk/tests/input/rolling/obsoleteERFA1.properties
    logging/log4j/trunk/tests/input/rolling/obsoleteRFA1.properties
    logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/ObsoleteDailyRollingFileAppenderTest.java
    logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/ObsoleteRollingFileAppenderTest.java
    logging/log4j/trunk/tests/src/java/org/apache/log4j/varia/ExternallyRolledFileAppenderTest.java
Modified:
    logging/log4j/trunk/src/java/org/apache/log4j/DailyRollingFileAppender.java
    logging/log4j/trunk/src/java/org/apache/log4j/RollingFileAppender.java
    logging/log4j/trunk/src/java/org/apache/log4j/varia/ExternallyRolledFileAppender.java
    logging/log4j/trunk/tests/build.xml
    logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/SizeBasedRollingTest.java
    logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/TimeBasedRollingTest.java

Modified: logging/log4j/trunk/src/java/org/apache/log4j/DailyRollingFileAppender.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/DailyRollingFileAppender.java?rev=398080&r1=398079&r2=398080&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/DailyRollingFileAppender.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/DailyRollingFileAppender.java Fri Apr 28 21:12:29 2006
@@ -1,12 +1,12 @@
 /*
- * Copyright 1999,2005 The Apache Software Foundation.
- *
+ * Copyright 1999-2005 The Apache Software Foundation.
+ * 
  * Licensed 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.
@@ -14,343 +14,430 @@
  * limitations under the License.
  */
 
-package org.apache.log4j;
 
-import org.apache.log4j.rolling.TimeBasedRollingPolicy;
-import org.apache.log4j.spi.Filter;
-import org.apache.log4j.spi.LoggerRepository;
-import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.spi.OptionHandler;
+
+package org.apache.log4j;
 
 import java.io.IOException;
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Calendar;
+import java.util.TimeZone;
+import java.util.Locale;
 
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.spi.LoggingEvent;
 
 /**
-  * org.apache.log4j.DailyRollingFileAppender emulates earlier implementations
-  * by delegating to general purpose org.apache.log4j.rollling.RollingFileAppender
-  * introduced in log4j 1.3.  This class is provided for compatibility with
-  * existing configuration files but is not intended to be compatible with
-  * existing extensions of the prior RollingFileAppender and is marked final
-  * to prevent such use.
-  *
-  *  @author Curt Arnold
-  * @deprecated Replaced by {@link org.apache.log4j.rolling.RollingFileAppender}
-*/
-public final class DailyRollingFileAppender implements Appender, OptionHandler {
+   DailyRollingFileAppender extends {@link FileAppender} so that the
+   underlying file is rolled over at a user chosen frequency.
 
-  /**
-   * It is assumed and enforced that errorHandler is never null.
-   * 
-   * @deprecated as of 1.3
-   */
-  private final org.apache.log4j.spi.ErrorHandler errorHandler = new org.apache.log4j.helpers.OnlyOnceErrorHandler();
+   <p>The rolling schedule is specified by the <b>DatePattern</b>
+   option. This pattern should follow the {@link SimpleDateFormat}
+   conventions. In particular, you <em>must</em> escape literal text
+   within a pair of single quotes. A formatted version of the date
+   pattern is used as the suffix for the rolled file name.
 
-  /**
-     The date pattern used to initiate rollover.
-  */
-  private String datePattern = "'.'yyyy-MM-dd";
+   <p>For example, if the <b>File</b> option is set to
+   <code>/foo/bar.log</code> and the <b>DatePattern</b> set to
+   <code>'.'yyyy-MM-dd</code>, on 2001-02-16 at midnight, the logging
+   file <code>/foo/bar.log</code> will be copied to
+   <code>/foo/bar.log.2001-02-16</code> and logging for 2001-02-17
+   will continue in <code>/foo/bar.log</code> until it rolls over
+   the next day.
 
-  /**
-   *  Nested new rolling file appender.
-   */
-  private final org.apache.log4j.rolling.RollingFileAppender rfa =
-    new org.apache.log4j.rolling.RollingFileAppender();
+   <p>Is is possible to specify monthly, weekly, half-daily, daily,
+   hourly, or minutely rollover schedules.
 
-  /**
-     The default constructor simply calls its {@link
-     FileAppender#FileAppender parents constructor}.  */
-  public DailyRollingFileAppender() {
-  }
+   <p><table border="1" cellpadding="2">
+   <tr>
+   <th>DatePattern</th>
+   <th>Rollover schedule</th>
+   <th>Example</th>
 
-  /**
-    Instantiate a DailyRollingFileAppender and open the file designated by
-    <code>filename</code>. The opened filename will become the ouput
-    destination for this appender.
+   <tr>
+   <td><code>'.'yyyy-MM</code>
+   <td>Rollover at the beginning of each month</td>
 
-  */
-  public DailyRollingFileAppender(
-    final Layout layout, final String filename, final String datePattern)
-    throws IOException {
-    rfa.setLayout(layout);
-    rfa.setFile(filename);
-    this.datePattern = datePattern;
-    activateOptions();
-  }
+   <td>At midnight of May 31st, 2002 <code>/foo/bar.log</code> will be
+   copied to <code>/foo/bar.log.2002-05</code>. Logging for the month
+   of June will be output to <code>/foo/bar.log</code> until it is
+   also rolled over the next month.
 
-  /**
-     The <b>DatePattern</b> takes a string in the same format as
-     expected by {@link java.text.SimpleDateFormat}. This options determines the
-     rollover schedule.
-   */
-  public void setDatePattern(String pattern) {
-    datePattern = pattern;
-  }
+   <tr>
+   <td><code>'.'yyyy-ww</code>
 
-  /** 
-   * Returns the value of the <b>DatePattern</b> option. 
-   * By default, the pattern is set to ".yyyy-MM-dd" meaning daily rollover.
-   */
-  public String getDatePattern() {
-    return datePattern;
-  }
+   <td>Rollover at the first day of each week. The first day of the
+   week depends on the locale.</td>
 
-  /**
-   * Prepares DailyRollingFileAppender for use.
-   */
-  public void activateOptions() {
-    TimeBasedRollingPolicy policy = new TimeBasedRollingPolicy();
-    StringBuffer pattern = new StringBuffer(rfa.getFile());
-    boolean inLiteral = false;
-    boolean inPattern = false;
-
-    for (int i = 0; i < datePattern.length(); i++) {
-      if (datePattern.charAt(i) == '\'') {
-        inLiteral = !inLiteral;
-
-        if (inLiteral && inPattern) {
-          pattern.append("}");
-          inPattern = false;
-        }
-      } else {
-        if (!inLiteral && !inPattern) {
-          pattern.append("%d{");
-          inPattern = true;
-        }
+   <td>Assuming the first day of the week is Sunday, on Saturday
+   midnight, June 9th 2002, the file <i>/foo/bar.log</i> will be
+   copied to <i>/foo/bar.log.2002-23</i>.  Logging for the 24th week
+   of 2002 will be output to <code>/foo/bar.log</code> until it is
+   rolled over the next week.
 
-        pattern.append(datePattern.charAt(i));
-      }
-    }
+   <tr>
+   <td><code>'.'yyyy-MM-dd</code>
 
-    if (inPattern) {
-      pattern.append("}");
-    }
+   <td>Rollover at midnight each day.</td>
 
-    policy.setFileNamePattern(pattern.toString());
-    policy.activateOptions();
-    rfa.setTriggeringPolicy(policy);
-    rfa.setRollingPolicy(policy);
+   <td>At midnight, on March 8th, 2002, <code>/foo/bar.log</code> will
+   be copied to <code>/foo/bar.log.2002-03-08</code>. Logging for the
+   9th day of March will be output to <code>/foo/bar.log</code> until
+   it is rolled over the next day.
 
-    rfa.activateOptions();
-  }
+   <tr>
+   <td><code>'.'yyyy-MM-dd-a</code>
 
+   <td>Rollover at midnight and midday of each day.</td>
 
-  /**
-   * Add a filter to the end of the filter list.
-   *
-   * @since 0.9.0
-   */
-  public void addFilter(final Filter newFilter) {
-    rfa.addFilter(newFilter);
-  }
+   <td>At noon, on March 9th, 2002, <code>/foo/bar.log</code> will be
+   copied to <code>/foo/bar.log.2002-03-09-AM</code>. Logging for the
+   afternoon of the 9th will be output to <code>/foo/bar.log</code>
+   until it is rolled over at midnight.
 
-  /**
-   * Returns the head Filter. The Filters are organized in a linked list and
-   * so all Filters on this Appender are available through the result.
-   *
-   * @return the head Filter or null, if no Filters are present
-   *
-   * @since 1.1
-   */
-  public Filter getFilter() {
-    return rfa.getFilter();
-  }
+   <tr>
+   <td><code>'.'yyyy-MM-dd-HH</code>
 
-  /**
-   * Clear the list of filters by removing all the filters in it.
-   *
-   * @since 0.9.0
-   */
-  public void clearFilters() {
-    rfa.clearFilters();
-  }
+   <td>Rollover at the top of every hour.</td>
 
-  /**
-   * Release any resources allocated within the appender such as file handles,
-   * network connections, etc.
-   *
-   * <p>
-   * It is a programming error to append to a closed appender.
-   * </p>
-   *
-   * @since 0.8.4
-   */
-  public void close() {
-    rfa.close();
-  }
+   <td>At approximately 11:00.000 o'clock on March 9th, 2002,
+   <code>/foo/bar.log</code> will be copied to
+   <code>/foo/bar.log.2002-03-09-10</code>. Logging for the 11th hour
+   of the 9th of March will be output to <code>/foo/bar.log</code>
+   until it is rolled over at the beginning of the next hour.
 
-  /**
-   * Is this appender closed?
-   *
-   * @since 1.3
-   */
-  public boolean isClosed() {
-    return rfa.isClosed();
-  }
 
-  /**
-   * Is this appender in working order?
-   *
-   * @since 1.3
-   */
-  public boolean isActive() {
-    return rfa.isActive();
-  }
+   <tr>
+   <td><code>'.'yyyy-MM-dd-HH-mm</code>
 
-  /**
-   * Log in <code>Appender</code> specific way. When appropriate, Loggers will
-   * call the <code>doAppend</code> method of appender implementations in
-   * order to log.
-   */
-  public void doAppend(final LoggingEvent event) {
-    rfa.doAppend(event);
-  }
+   <td>Rollover at the beginning of every minute.</td>
 
-  /**
-   * Get the name of this appender. The name uniquely identifies the appender.
-   */
-  public String getName() {
-    return rfa.getName();
-  }
+   <td>At approximately 11:23,000, on March 9th, 2001,
+   <code>/foo/bar.log</code> will be copied to
+   <code>/foo/bar.log.2001-03-09-10-22</code>. Logging for the minute
+   of 11:23 (9th of March) will be output to
+   <code>/foo/bar.log</code> until it is rolled over the next minute.
+
+   </table>
+
+   <p>Do not use the colon ":" character in anywhere in the
+   <b>DatePattern</b> option. The text before the colon is interpeted
+   as the protocol specificaion of a URL which is probably not what
+   you want.
+
+
+   @author Eirik Lygre
+   @author Ceki G&uuml;lc&uuml;
+   @deprecated Since log4j 1.3, use org.apache.log4j.rolling.RollingFileAppender instead.
+ */
+public class DailyRollingFileAppender extends FileAppender {
+
+
+  // The code assumes that the following constants are in a increasing
+  // sequence.
+  static final int TOP_OF_TROUBLE=-1;
+  static final int TOP_OF_MINUTE = 0;
+  static final int TOP_OF_HOUR   = 1;
+  static final int HALF_DAY      = 2;
+  static final int TOP_OF_DAY    = 3;
+  static final int TOP_OF_WEEK   = 4;
+  static final int TOP_OF_MONTH  = 5;
 
-  /**
-   * Set the {@link Layout} for this appender.
-   *
-   * @since 0.8.1
-   */
-  public void setLayout(final Layout layout) {
-    rfa.setLayout(layout);
-  }
 
   /**
-   * Returns this appenders layout.
-   *
-   * @since 1.1
+     The date pattern. By default, the pattern is set to
+     "'.'yyyy-MM-dd" meaning daily rollover.
    */
-  public Layout getLayout() {
-    return rfa.getLayout();
-  }
+  private String datePattern = "'.'yyyy-MM-dd";
 
   /**
-   * Set the name of this appender. The name is used by other components to
-   * identify this appender.
-   *
-   * @since 0.8.1
-   */
-  public void setName(final String name) {
-    rfa.setName(name);
-  }
+     The log file will be renamed to the value of the
+     scheduledFilename variable when the next interval is entered. For
+     example, if the rollover period is one hour, the log file will be
+     renamed to the value of "scheduledFilename" at the beginning of
+     the next hour. 
 
-  public void setLoggerRepository(final LoggerRepository repository)
-    throws IllegalStateException {
-    rfa.setLoggerRepository(repository);
-  }
+     The precise time when a rollover occurs depends on logging
+     activity. 
+  */
+  private String scheduledFilename;
 
   /**
-     The <b>File</b> property takes a string value which should be the
-     name of the file to append to.
+     The next time we estimate a rollover should occur. */
+  private long nextCheck = System.currentTimeMillis () - 1;
 
-     <p><font color="#DD0044"><b>Note that the special values
-     "System.out" or "System.err" are no longer honored.</b></font>
+  Date now = new Date();
 
-     <p>Note: Actual opening of the file is made when {@link
-     #activateOptions} is called, not when the options are set.  */
-  public void setFile(final String file) {
-    rfa.setFile(file);
-  }
+  SimpleDateFormat sdf;
 
-  /**
-      Returns the value of the <b>Append</b> option.
-   */
-  public boolean getAppend() {
-    return rfa.getAppend();
-  }
+  private final RollingCalendar rc = new RollingCalendar();
 
-  /** Returns the value of the <b>File</b> option. */
-  public String getFile() {
-    return rfa.getFile();
-  }
+  int checkPeriod = TOP_OF_TROUBLE;
 
-  /**
-     Get the value of the <b>BufferedIO</b> option.
+  // The gmtTimeZone is used only in computeCheckPeriod() method.
+  static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
 
-     <p>BufferedIO will significatnly increase performance on heavily
-     loaded systems.
 
-  */
-  public boolean getBufferedIO() {
-    return rfa.getBufferedIO();
+  /**
+     The default constructor does nothing. */
+  public DailyRollingFileAppender() {
   }
 
   /**
-     Get the size of the IO buffer.
-  */
-  public int getBufferSize() {
-    return rfa.getBufferSize();
+    Instantiate a <code>DailyRollingFileAppender</code> and open the
+    file designated by <code>filename</code>. The opened filename will
+    become the ouput destination for this appender.
+
+    */
+  public DailyRollingFileAppender (Layout layout, String filename,
+				   String datePattern) throws IOException {
+    super(layout, filename, true);
+    this.datePattern = datePattern;
+    activateOptions();
   }
 
   /**
-     The <b>Append</b> option takes a boolean value. It is set to
-     <code>true</code> by default. If true, then <code>File</code>
-     will be opened in append mode by {@link #setFile setFile} (see
-     above). Otherwise, {@link #setFile setFile} will open
-     <code>File</code> in truncate mode.
-
-     <p>Note: Actual opening of the file is made when {@link
-     #activateOptions} is called, not when the options are set.
+     The <b>DatePattern</b> takes a string in the same format as
+     expected by {@link SimpleDateFormat}. This options determines the
+     rollover schedule.
    */
-  public void setAppend(final boolean flag) {
-    rfa.setAppend(flag);
+  public void setDatePattern(String pattern) {
+    datePattern = pattern;
   }
 
-  /**
-     The <b>BufferedIO</b> option takes a boolean value. It is set to
-     <code>false</code> by default. If true, then <code>File</code>
-     will be opened and the resulting {@link java.io.Writer} wrapped
-     around a {@link java.io.BufferedWriter}.
+  /** Returns the value of the <b>DatePattern</b> option. */
+  public String getDatePattern() {
+    return datePattern;
+  }
 
-     BufferedIO will significatnly increase performance on heavily
-     loaded systems.
+  public void activateOptions() {
+    super.activateOptions();
+    if(datePattern != null && fileName != null) {
+      now.setTime(System.currentTimeMillis());
+      sdf = new SimpleDateFormat(datePattern);
+      int type = computeCheckPeriod();
+      printPeriodicity(type);
+      rc.setType(type);
+      File file = new File(fileName);
+      scheduledFilename = fileName+sdf.format(new Date(file.lastModified()));
+
+    } else {
+      LogLog.error("Either File or DatePattern options are not set for appender ["
+		   +name+"].");
+    }
+  }
 
-  */
-  public void setBufferedIO(final boolean bufferedIO) {
-    rfa.setBufferedIO(bufferedIO);
+  void printPeriodicity(int type) {
+    switch(type) {
+    case TOP_OF_MINUTE:
+      LogLog.debug("Appender ["+name+"] to be rolled every minute.");
+      break;
+    case TOP_OF_HOUR:
+      LogLog.debug("Appender ["+name
+		   +"] to be rolled on top of every hour.");
+      break;
+    case HALF_DAY:
+      LogLog.debug("Appender ["+name
+		   +"] to be rolled at midday and midnight.");
+      break;
+    case TOP_OF_DAY:
+      LogLog.debug("Appender ["+name
+		   +"] to be rolled at midnight.");
+      break;
+    case TOP_OF_WEEK:
+      LogLog.debug("Appender ["+name
+		   +"] to be rolled at start of week.");
+      break;
+    case TOP_OF_MONTH:
+      LogLog.debug("Appender ["+name
+		   +"] to be rolled at start of every month.");
+      break;
+    default:
+      LogLog.warn("Unknown periodicity for appender ["+name+"].");
+    }
   }
 
-  /**
-     Set the size of the IO buffer.
-  */
-  public void setBufferSize(final int bufferSize) {
-    rfa.setBufferSize(bufferSize);
+
+  // This method computes the roll over period by looping over the
+  // periods, starting with the shortest, and stopping when the r0 is
+  // different from from r1, where r0 is the epoch formatted according
+  // the datePattern (supplied by the user) and r1 is the
+  // epoch+nextMillis(i) formatted according to datePattern. All date
+  // formatting is done in GMT and not local format because the test
+  // logic is based on comparisons relative to 1970-01-01 00:00:00
+  // GMT (the epoch).
+
+  int computeCheckPeriod() {
+    RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.ENGLISH);
+    // set sate to 1970-01-01 00:00:00 GMT
+    Date epoch = new Date(0);
+    if(datePattern != null) {
+      for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
+	SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
+	simpleDateFormat.setTimeZone(gmtTimeZone); // do all date formatting in GMT
+	String r0 = simpleDateFormat.format(epoch);
+	rollingCalendar.setType(i);
+	Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));
+	String r1 =  simpleDateFormat.format(next);
+	//System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);
+	if(r0 != null && r1 != null && !r0.equals(r1)) {
+	  return i;
+	}
+      }
+    }
+    return TOP_OF_TROUBLE; // Deliberately head for trouble...
   }
 
   /**
-   * Return the hardcoded <code>OnlyOnceErrorHandler</code> for this Appender.
-   * <code>ErrorHandler</code>'s are no longer utilized as of version 1.3.
-   *
-   * @since 0.9.0
-   * @deprecated As of 1.3
-   */
-  public final org.apache.log4j.spi.ErrorHandler getErrorHandler() {
-    return this.errorHandler;
+     Rollover the current file to a new file.
+  */
+  void rollOver() throws IOException {
+
+    /* Compute filename, but only if datePattern is specified */
+    if (datePattern == null) {
+      errorHandler.error("Missing DatePattern option in rollOver().");
+      return;
+    }
+
+    String datedFilename = fileName+sdf.format(now);
+    // It is too early to roll over because we are still within the
+    // bounds of the current interval. Rollover will occur once the
+    // next interval is reached.
+    if (scheduledFilename.equals(datedFilename)) {
+      return;
+    }
+
+    // close current file, and rename it to datedFilename
+    this.closeFile();
+
+    File target  = new File(scheduledFilename);
+    if (target.exists()) {
+      target.delete();
+    }
+
+    File file = new File(fileName);
+    boolean result = file.renameTo(target);
+    if(result) {
+      LogLog.debug(fileName +" -> "+ scheduledFilename);
+    } else {
+      LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
+    }
+
+    try {
+      // This will also close the file. This is OK since multiple
+      // close operations are safe.
+      this.setFile(fileName, false, this.bufferedIO, this.bufferSize);
+    }
+    catch(IOException e) {
+      errorHandler.error("setFile("+fileName+", false) call failed.");
+    }
+    scheduledFilename = datedFilename;
   }
 
   /**
-   * Ignored as of 1.3
+   * This method differentiates DailyRollingFileAppender from its
+   * super class.
    *
-   * @since 0.9.0
-   * @deprecated As of 1.3
-   */
-  public final void setErrorHandler(org.apache.log4j.spi.ErrorHandler eh) {
-    ; //ignore
-  }
+   * <p>Before actually logging, this method will check whether it is
+   * time to do a rollover. If it is, it will schedule the next
+   * rollover time and then rollover.
+   * */
+  protected void subAppend(LoggingEvent event) {
+    long n = System.currentTimeMillis();
+    if (n >= nextCheck) {
+      now.setTime(n);
+      nextCheck = rc.getNextCheckMillis(now);
+      try {
+	rollOver();
+      }
+      catch(IOException ioe) {
+	LogLog.error("rollOver() failed.", ioe);
+      }
+    }
+    super.subAppend(event);
+   }
+}
 
-    /**
-     * Gets whether appender requires a layout.
-     * @return false
-     */
-  public boolean requiresLayout() {
-      return true;
+/**
+ *  RollingCalendar is a helper class to DailyRollingFileAppender.
+ *  Given a periodicity type and the current time, it computes the
+ *  start of the next interval.
+ *  @deprecated Since log4j 1.3.
+ * */
+class RollingCalendar extends GregorianCalendar {
+
+  private int type = DailyRollingFileAppender.TOP_OF_TROUBLE;
+
+  RollingCalendar() {
+    super();
+  }  
+
+  RollingCalendar(TimeZone tz, Locale locale) {
+    super(tz, locale);
+  }  
+
+  void setType(int type) {
+    this.type = type;
+  }
+
+  public long getNextCheckMillis(Date now) {
+    return getNextCheckDate(now).getTime();
+  }
+
+  public Date getNextCheckDate(Date now) {
+    this.setTime(now);
+
+    switch(type) {
+    case DailyRollingFileAppender.TOP_OF_MINUTE:
+	this.set(Calendar.SECOND, 0);
+	this.set(Calendar.MILLISECOND, 0);
+	this.add(Calendar.MINUTE, 1);
+	break;
+    case DailyRollingFileAppender.TOP_OF_HOUR:
+	this.set(Calendar.MINUTE, 0);
+	this.set(Calendar.SECOND, 0);
+	this.set(Calendar.MILLISECOND, 0);
+	this.add(Calendar.HOUR_OF_DAY, 1);
+	break;
+    case DailyRollingFileAppender.HALF_DAY:
+	this.set(Calendar.MINUTE, 0);
+	this.set(Calendar.SECOND, 0);
+	this.set(Calendar.MILLISECOND, 0);
+	int hour = get(Calendar.HOUR_OF_DAY);
+	if(hour < 12) {
+	  this.set(Calendar.HOUR_OF_DAY, 12);
+	} else {
+	  this.set(Calendar.HOUR_OF_DAY, 0);
+	  this.add(Calendar.DAY_OF_MONTH, 1);
+	}
+	break;
+    case DailyRollingFileAppender.TOP_OF_DAY:
+	this.set(Calendar.HOUR_OF_DAY, 0);
+	this.set(Calendar.MINUTE, 0);
+	this.set(Calendar.SECOND, 0);
+	this.set(Calendar.MILLISECOND, 0);
+	this.add(Calendar.DATE, 1);
+	break;
+    case DailyRollingFileAppender.TOP_OF_WEEK:
+	this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
+	this.set(Calendar.HOUR_OF_DAY, 0);
+	this.set(Calendar.SECOND, 0);
+	this.set(Calendar.MILLISECOND, 0);
+	this.add(Calendar.WEEK_OF_YEAR, 1);
+	break;
+    case DailyRollingFileAppender.TOP_OF_MONTH:
+	this.set(Calendar.DATE, 1);
+	this.set(Calendar.HOUR_OF_DAY, 0);
+	this.set(Calendar.SECOND, 0);
+	this.set(Calendar.MILLISECOND, 0);
+	this.add(Calendar.MONTH, 1);
+	break;
+    default:
+	throw new IllegalStateException("Unknown periodicity type.");
+    }
+    return getTime();
   }
-
-
 }

Modified: logging/log4j/trunk/src/java/org/apache/log4j/RollingFileAppender.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/RollingFileAppender.java?rev=398080&r1=398079&r2=398080&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/RollingFileAppender.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/RollingFileAppender.java Fri Apr 28 21:12:29 2006
@@ -1,12 +1,12 @@
 /*
- * Copyright 1999,2005 The Apache Software Foundation.
- *
+ * Copyright 1999-2005 The Apache Software Foundation.
+ * 
  * Licensed 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.
@@ -14,59 +14,46 @@
  * limitations under the License.
  */
 
+
+
 package org.apache.log4j;
 
+import java.io.IOException;
+import java.io.Writer;
+import java.io.File;
 import org.apache.log4j.helpers.OptionConverter;
-import org.apache.log4j.rolling.FixedWindowRollingPolicy;
-import org.apache.log4j.rolling.SizeBasedTriggeringPolicy;
-import org.apache.log4j.spi.Filter;
-import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.helpers.CountingQuietWriter;
 import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.spi.OptionHandler;
 
-import java.io.IOException;
+/**
+   RollingFileAppender extends FileAppender to backup the log files when
+   they reach a certain size.
 
+   @author Heinz Richter
+   @author Ceki G&uuml;lc&uuml;
 
-/**
- * org.apache.log4j.RollingFileAppender emulates earlier implementations
- * by delegating to general purpose org.apache.log4j.rollling.RollingFileAppender
- * introduced in log4j 1.3.    This class is provided for compatibility with
- * existing configuration files but is not intended to be compatible with
- * existing extensions of the prior RollingFileAppender and is marked final
- * to prevent such use.
- *
- * @author Curt Arnold
- * @deprecated Replaced by {@link org.apache.log4j.rolling.RollingFileAppender}
-*/
-public class RollingFileAppender implements Appender, OptionHandler {
+   @deprecated Since log4j 1.3, use org.apache.log4j.rolling.RollingFileAppender instead.
 
-  /**
-   * It is assumed and enforced that errorHandler is never null.
-   * 
-   * @deprecated as of 1.3
-   */
-  private final org.apache.log4j.spi.ErrorHandler errorHandler = new org.apache.log4j.helpers.OnlyOnceErrorHandler();
+*/
+public class RollingFileAppender extends FileAppender {
 
   /**
      The default maximum file size is 10MB.
   */
-  private long maxFileSize = 10 * 1024 * 1024;
+  protected long maxFileSize = 10*1024*1024;
 
   /**
      There is one backup file by default.
    */
-  private int maxBackupIndex = 1;
-
-  /**
-   *  Nested new rolling file appender.
-   */
-  private final org.apache.log4j.rolling.RollingFileAppender rfa =
-    new org.apache.log4j.rolling.RollingFileAppender();
+  protected int  maxBackupIndex  = 1;
 
   /**
      The default constructor simply calls its {@link
      FileAppender#FileAppender parents constructor}.  */
-  public RollingFileAppender() {
+  public
+  RollingFileAppender() {
+    super();
   }
 
   /**
@@ -78,13 +65,10 @@
     appended to. Otherwise, the file desginated by
     <code>filename</code> will be truncated before being opened.
   */
-  public RollingFileAppender(
-    final Layout layout, final String filename, final boolean append)
-    throws IOException {
-    rfa.setLayout(layout);
-    rfa.setFile(filename);
-    rfa.setAppend(append);
-    activateOptions();
+  public
+  RollingFileAppender(Layout layout, String filename, boolean append)
+                                      throws IOException {
+    super(layout, filename, append);
   }
 
   /**
@@ -93,31 +77,102 @@
     destination for this appender.
 
     <p>The file will be appended to.  */
-  public RollingFileAppender(final Layout layout, final String filename)
-    throws IOException {
-    rfa.setLayout(layout);
-    rfa.setFile(filename);
-    activateOptions();
+  public
+  RollingFileAppender(Layout layout, String filename) throws IOException {
+    super(layout, filename);
   }
 
   /**
      Returns the value of the <b>MaxBackupIndex</b> option.
    */
-  public int getMaxBackupIndex() {
+  public
+  int getMaxBackupIndex() {
     return maxBackupIndex;
   }
 
-  /**
-     Get the maximum size that the output file is allowed to reach
-     before being rolled over to backup files.
+ /**
+    Get the maximum size that the output file is allowed to reach
+    before being rolled over to backup files.
 
-     @since 1.1
-  */
-  public long getMaximumFileSize() {
+    @since 1.1
+ */
+  public
+  long getMaximumFileSize() {
     return maxFileSize;
   }
 
   /**
+     Implements the usual roll over behaviour.
+
+     <p>If <code>MaxBackupIndex</code> is positive, then files
+     {<code>File.1</code>, ..., <code>File.MaxBackupIndex -1</code>}
+     are renamed to {<code>File.2</code>, ...,
+     <code>File.MaxBackupIndex</code>}. Moreover, <code>File</code> is
+     renamed <code>File.1</code> and closed. A new <code>File</code> is
+     created to receive further log output.
+
+     <p>If <code>MaxBackupIndex</code> is equal to zero, then the
+     <code>File</code> is truncated with no backup files created.
+
+   */
+  public // synchronization not necessary since doAppend is alreasy synched
+  void rollOver() {
+    File target;
+    File file;
+
+    LogLog.debug("rolling over count=" + ((CountingQuietWriter) qw).getCount());
+    LogLog.debug("maxBackupIndex="+maxBackupIndex);
+
+    // If maxBackups <= 0, then there is no file renaming to be done.
+    if(maxBackupIndex > 0) {
+      // Delete the oldest file, to keep Windows happy.
+      file = new File(fileName + '.' + maxBackupIndex);
+      if (file.exists())
+       file.delete();
+
+      // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
+      for (int i = maxBackupIndex - 1; i >= 1; i--) {
+	file = new File(fileName + "." + i);
+	if (file.exists()) {
+	  target = new File(fileName + '.' + (i + 1));
+	  LogLog.debug("Renaming file " + file + " to " + target);
+	  file.renameTo(target);
+	}
+      }
+
+      // Rename fileName to fileName.1
+      target = new File(fileName + "." + 1);
+
+      this.closeFile(); // keep windows happy.
+
+      file = new File(fileName);
+      LogLog.debug("Renaming file " + file + " to " + target);
+      file.renameTo(target);
+    }
+
+    try {
+      // This will also close the file. This is OK since multiple
+      // close operations are safe.
+      this.setFile(fileName, false, bufferedIO, bufferSize);
+    }
+    catch(IOException e) {
+      LogLog.error("setFile("+fileName+", false) call failed.", e);
+    }
+  }
+
+  public
+  synchronized
+  void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
+                                                                 throws IOException {
+    super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
+    if(append) {
+      File f = new File(fileName);
+      ((CountingQuietWriter) qw).setCount(f.length());
+    }
+  }
+
+
+  /**
      Set the maximum number of backup files to keep around.
 
      <p>The <b>MaxBackupIndex</b> option determines how many backup
@@ -126,7 +181,8 @@
      backup files and the log file will be truncated when it reaches
      <code>MaxFileSize</code>.
    */
-  public void setMaxBackupIndex(int maxBackups) {
+  public
+  void setMaxBackupIndex(int maxBackups) {
     this.maxBackupIndex = maxBackups;
   }
 
@@ -141,11 +197,13 @@
      java.beans.Introspector Introspector}.
 
      @see #setMaxFileSize(String)
-  */
-  public void setMaximumFileSize(long maxFileSize) {
+ */
+  public
+  void setMaximumFileSize(long maxFileSize) {
     this.maxFileSize = maxFileSize;
   }
 
+
   /**
      Set the maximum size that the output file is allowed to reach
      before being rolled over to backup files.
@@ -157,267 +215,27 @@
      or gigabytes. For example, the value "10KB" will be interpreted
      as 10240.
    */
-  public void setMaxFileSize(String value) {
+  public
+  void setMaxFileSize(String value) {
     maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
   }
 
-  /**
-   * Prepares RollingFileAppender for use.
-   */
-  public void activateOptions() {
-    SizeBasedTriggeringPolicy trigger = new SizeBasedTriggeringPolicy();
-    trigger.setMaxFileSize(maxFileSize);
-    trigger.activateOptions();
-    rfa.setTriggeringPolicy(trigger);
-
-    FixedWindowRollingPolicy rolling = new FixedWindowRollingPolicy();
-    rolling.setMinIndex(1);
-    rolling.setMaxIndex(maxBackupIndex);
-    rfa.setFile(rfa.getFile());
-    rolling.setFileNamePattern(rfa.getFile() + ".%i");
-    rolling.activateOptions();
-    rfa.setRollingPolicy(rolling);
-
-    rfa.activateOptions();
-  }
-
-
-  /**
-   * Add a filter to the end of the filter list.
-   *
-   * @since 0.9.0
-   */
-  public void addFilter(final Filter newFilter) {
-    rfa.addFilter(newFilter);
-  }
-
-  /**
-   * Returns the head Filter. The Filters are organized in a linked list and
-   * so all Filters on this Appender are available through the result.
-   *
-   * @return the head Filter or null, if no Filters are present
-   *
-   * @since 1.1
-   */
-  public Filter getFilter() {
-    return rfa.getFilter();
-  }
-
-  /**
-   * Clear the list of filters by removing all the filters in it.
-   *
-   * @since 0.9.0
-   */
-  public void clearFilters() {
-    rfa.clearFilters();
-  }
-
-  /**
-   * Release any resources allocated within the appender such as file handles,
-   * network connections, etc.
-   *
-   * <p>
-   * It is a programming error to append to a closed appender.
-   * </p>
-   *
-   * @since 0.8.4
-   */
-  public void close() {
-    rfa.close();
-  }
-
-  /**
-   * Is this appender closed?
-   *
-   * @since 1.3
-   */
-  public boolean isClosed() {
-    return rfa.isClosed();
-  }
-
-  /**
-   * Is this appender in working order?
-   *
-   * @since 1.3
-   */
-  public boolean isActive() {
-    return rfa.isActive();
-  }
-
-  /**
-   * Log in <code>Appender</code> specific way. When appropriate, Loggers will
-   * call the <code>doAppend</code> method of appender implementations in
-   * order to log.
-   */
-  public void doAppend(final LoggingEvent event) {
-    rfa.doAppend(event);
-  }
-
-  /**
-   * Get the name of this appender. The name uniquely identifies the appender.
-   */
-  public String getName() {
-    return rfa.getName();
-  }
-
-  /**
-   * Set the {@link Layout} for this appender.
-   *
-   * @since 0.8.1
-   */
-  public void setLayout(final Layout layout) {
-    rfa.setLayout(layout);
-  }
-
-  /**
-   * Returns this appenders layout.
-   *
-   * @since 1.1
-   */
-  public Layout getLayout() {
-    return rfa.getLayout();
-  }
-
-  /**
-   * Set the name of this appender. The name is used by other components to
-   * identify this appender.
-   *
-   * @since 0.8.1
-   */
-  public void setName(final String name) {
-    rfa.setName(name);
-  }
-
-  public void setLoggerRepository(final LoggerRepository repository)
-    throws IllegalStateException {
-    rfa.setLoggerRepository(repository);
-  }
-
-  /**
-     The <b>File</b> property takes a string value which should be the
-     name of the file to append to.
-
-     <p><font color="#DD0044"><b>Note that the special values
-     "System.out" or "System.err" are no longer honored.</b></font>
-
-     <p>Note: Actual opening of the file is made when {@link
-     #activateOptions} is called, not when the options are set.  */
-  public void setFile(final String file) {
-    rfa.setFile(file);
-  }
-
-  /**
-      Returns the value of the <b>Append</b> option.
-   */
-  public boolean getAppend() {
-    return rfa.getAppend();
-  }
-
-  /** Returns the value of the <b>File</b> option. */
-  public String getFile() {
-    return rfa.getFile();
+  protected
+  void setQWForFiles(Writer writer) {
+     this.qw = new CountingQuietWriter(writer, errorHandler);
   }
 
   /**
-     Get the value of the <b>BufferedIO</b> option.
-
-     <p>BufferedIO will significatnly increase performance on heavily
-     loaded systems.
+     This method differentiates RollingFileAppender from its super
+     class.
 
+     @since 0.9.0
   */
-  public boolean getBufferedIO() {
-    return rfa.getBufferedIO();
-  }
-
-  /**
-     Get the size of the IO buffer.
-  */
-  public int getBufferSize() {
-    return rfa.getBufferSize();
-  }
-
-  /**
-     The <b>Append</b> option takes a boolean value. It is set to
-     <code>true</code> by default. If true, then <code>File</code>
-     will be opened in append mode by {@link #setFile setFile} (see
-     above). Otherwise, {@link #setFile setFile} will open
-     <code>File</code> in truncate mode.
-
-     <p>Note: Actual opening of the file is made when {@link
-     #activateOptions} is called, not when the options are set.
-   */
-  public void setAppend(final boolean flag) {
-    rfa.setAppend(flag);
-  }
-
-  /**
-     The <b>BufferedIO</b> option takes a boolean value. It is set to
-     <code>false</code> by default. If true, then <code>File</code>
-     will be opened and the resulting {@link java.io.Writer} wrapped
-     around a {@link java.io.BufferedWriter}.
-
-     BufferedIO will significatnly increase performance on heavily
-     loaded systems.
-
-  */
-  public void setBufferedIO(final boolean bufferedIO) {
-    rfa.setBufferedIO(bufferedIO);
-  }
-
-  /**
-     Set the size of the IO buffer.
-  */
-  public void setBufferSize(final int bufferSize) {
-    rfa.setBufferSize(bufferSize);
-  }
-
-    /**
-       Implements the usual roll over behaviour.
-
-       <p>If <code>MaxBackupIndex</code> is positive, then files
-       {<code>File.1</code>, ..., <code>File.MaxBackupIndex -1</code>}
-       are renamed to {<code>File.2</code>, ...,
-       <code>File.MaxBackupIndex</code>}. Moreover, <code>File</code> is
-       renamed <code>File.1</code> and closed. A new <code>File</code> is
-       created to receive further log output.
-
-       <p>If <code>MaxBackupIndex</code> is equal to zero, then the
-       <code>File</code> is truncated with no backup files created.
-
-     */
-    public // synchronization not necessary since doAppend is alreasy synched
-    void rollOver() {
-        rfa.rollover();
-    }
-
-    /**
-     * Return the hardcoded <code>OnlyOnceErrorHandler</code> for this Appender.
-     * <code>ErrorHandler</code>'s are no longer utilized as of version 1.3.
-     *
-     * @since 0.9.0
-     * @deprecated As of 1.3
-     */
-    public final org.apache.log4j.spi.ErrorHandler getErrorHandler() {
-      return this.errorHandler;
-    }
-
-    /**
-     * Ignored as of 1.3
-     *
-     * @since 0.9.0
-     * @deprecated As of 1.3
-     */
-    public final void setErrorHandler(org.apache.log4j.spi.ErrorHandler eh) {
-      ; //ignore
-    }
-
-    /**
-     * Gets whether appender requires a layout.
-     * @return false
-     */
-  public boolean requiresLayout() {
-      return false;
-  }
-
-
+  protected
+  void subAppend(LoggingEvent event) {
+    super.subAppend(event);
+    if((fileName != null) &&
+                     ((CountingQuietWriter) qw).getCount() >= maxFileSize)
+      this.rollOver();
+   }
 }

Modified: logging/log4j/trunk/src/java/org/apache/log4j/varia/ExternallyRolledFileAppender.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/src/java/org/apache/log4j/varia/ExternallyRolledFileAppender.java?rev=398080&r1=398079&r2=398080&view=diff
==============================================================================
--- logging/log4j/trunk/src/java/org/apache/log4j/varia/ExternallyRolledFileAppender.java (original)
+++ logging/log4j/trunk/src/java/org/apache/log4j/varia/ExternallyRolledFileAppender.java Fri Apr 28 21:12:29 2006
@@ -1,12 +1,12 @@
 /*
- * Copyright 1999,2005 The Apache Software Foundation.
- *
+ * Copyright 1999-2005 The Apache Software Foundation.
+ * 
  * Licensed 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.
@@ -16,13 +16,12 @@
 
 package org.apache.log4j.varia;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.ServerSocket;
+import java.io.*;
 import java.net.Socket;
-
+import java.net.ServerSocket;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.RollingFileAppender;
+import org.apache.log4j.helpers.LogLog;
 
 /**
    This appender listens on a socket on the port specified by the
@@ -43,162 +42,139 @@
 
 
    @author Ceki G&uuml;lc&uuml;
-   @author Curt Arnold
    @since version 0.9.0
-   @deprecated version 1.3
+   @deprecated since 1.3, use org.apache.log4j.rolling.RollingFileAppender.
  */
-public final class ExternallyRolledFileAppender extends org.apache.log4j.RollingFileAppender {
+public class ExternallyRolledFileAppender extends RollingFileAppender {
+
   /**
      The string constant sent to initiate a roll over.   Current value of
      this string constant is <b>RollOver</b>.
   */
-  public static final String ROLL_OVER = "RollOver";
-
+  static final public String ROLL_OVER = "RollOver";
 
   /**
      The string constant sent to acknowledge a roll over.   Current value of
       this string constant is <b>OK</b>.
   */
-  public static final String OK = "OK";
-  /**
-   * The port to listen on for rollover requests. 
-   * The default value is <code>0</code> which disables listening for requests.
-   */  
-  private int port = 0;
-  /**
-   *  Request listening thread.
-   */
-  private HUP hup;
-
+  static final public String OK = "OK";
 
+  int port = 0;
+  HUP hup;
 
   /**
      The default constructor does nothing but calls its super-class
      constructor.  */
-  public ExternallyRolledFileAppender() {
+  public
+  ExternallyRolledFileAppender() {
   }
 
   /**
-    * Sets the port monitored for rollover requests.
-   */
-  public void setPort(int port) {
+     The <b>Port</b> [roperty is used for setting the port for
+     listening to external roll over messages.
+  */
+  public
+  void setPort(int port) {
     this.port = port;
   }
 
   /**
-    * Gets the port monitored for rollover requests.  A value of <code>0</code>
-    * indicates no monitoring.
+     Returns value of the <b>Port</b> option.
    */
-  public int getPort() {
+  public
+  int getPort() {
     return port;
   }
 
   /**
      Start listening on the port specified by a preceding call to
      {@link #setPort}.  */
-  public void activateOptions() {
+  public
+  void activateOptions() {
     super.activateOptions();
-    if (port != 0) {
-        hup =  new HUP(this, port);
-        hup.setDaemon(true);
-        hup.start();
+    if(port != 0) {
+      if(hup != null) {
+	hup.interrupt();
+      }
+      hup = new HUP(this, port);
+      hup.setDaemon(true);
+      hup.start();
     }
   }
+}
+
+/**
+ * @deprecated since log4j 1.3.
+ */
+class HUP extends Thread {
 
-     /**
-       *  Close this appender instance. The underlying stream or writer is
-       *  also closed.
-       *
-       *  <p>Closed appenders cannot be reused.
-      */
-      public void close() {
-        HUP dying = null;
-        synchronized(this) {
-            dying = hup;
-            hup = null;
-        }
-        if (dying != null) {
-            dying.interrupt();
-            try {
-               new Socket(InetAddress.getLocalHost(), port);
-               dying.join();
-            } catch (Exception ex) {
-            }
-        }
-        super.close();
+  int port;
+  ExternallyRolledFileAppender er;
+
+  HUP(ExternallyRolledFileAppender er, int port) {
+    this.er = er;
+    this.port = port;
+  }
+
+  public
+  void run() {
+    while(!isInterrupted()) {
+      try {
+	ServerSocket serverSocket = new ServerSocket(port);
+	while(true) {
+	  Socket socket = serverSocket.accept();
+	  LogLog.debug("Connected to client at " + socket.getInetAddress());
+	  new Thread(new HUPNode(socket, er)).start();
+	}
       }
+      catch(Exception e) {
+	e.printStackTrace();
+      }
+    }
+  }
+}
+
+/**
+ * @deprecated since log4j 1.3.
+ */
+class HUPNode implements Runnable {
 
+  Socket socket;
+  DataInputStream dis;
+  DataOutputStream dos;
+  ExternallyRolledFileAppender er;
+
+  public
+  HUPNode(Socket socket, ExternallyRolledFileAppender er) {
+    this.socket = socket;
+    this.er = er;
+    try {
+      dis = new DataInputStream(socket.getInputStream());
+      dos = new DataOutputStream(socket.getOutputStream());
+    }
+    catch(Exception e) {
+      e.printStackTrace();
+    }
+  }
 
+  public void run() {
+    try {
+      String line = dis.readUTF();
+      LogLog.debug("Got external roll over signal.");
+      if(ExternallyRolledFileAppender.ROLL_OVER.equals(line)) {
+	synchronized(er) {
+	  er.rollOver();
+	}
+	dos.writeUTF(ExternallyRolledFileAppender.OK);
+      }
+      else {
+	dos.writeUTF("Expecting [RollOver] string.");
+      }
+      dos.close();
+    }
+    catch(Exception e) {
+      LogLog.error("Unexpected exception. Exiting HUPNode.", e);
+    }
+  }
+}
 
-  private static class HUP extends Thread {
-     private final ExternallyRolledFileAppender er;
-     private final int port;
-      /**
-       * Use of loggers within this code is a deadlock waiting to happen.
-       *
-       */
-//     private static final Logger logger = LogManager.getLogger("org.apache.log4j.varia.HUP");
-  
-     public HUP(final ExternallyRolledFileAppender er, int port) {
-        this.er = er;
-        this.port = port;
-     }
-
-     public void run() {
-        ServerSocket serverSocket = null;
-        IOException ioex = null;
-        //
-        //   try to establish connection for 10 attempts
-        //     since configuration may have just been reset
-        //     and the previous HUP hasn't released the socket.
-        for(int i = 0; i < 10; i++) {
-            try {
-                serverSocket = new ServerSocket(port);
-                break;
-            } catch(IOException ex) {
-                ioex = ex;
-                try {
-                    Thread.sleep(100);
-                } catch(InterruptedException intex) {
-                }
-            }
-        }
-        if (serverSocket != null) {
-           try {
-               while (true) {
-                  Socket socket = serverSocket.accept();
-                   if (isInterrupted()) {
-                       break;
-                   }
-    //              logger.debug("Connected to client at " + socket.getInetAddress());
-                   DataInputStream dis = new DataInputStream(socket.getInputStream());
-                   DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
-                   try {
-                     String line = dis.readUTF();
-    //               logger.debug("Got external roll over signal.");
-                     if (ExternallyRolledFileAppender.ROLL_OVER.equals(line)) {
-                        synchronized(er) {
-                            er.rollOver();
-                        }
-                        dos.writeUTF(ExternallyRolledFileAppender.OK);
-                     } else {
-                        dos.writeUTF("Expecting [RollOver] string.");
-                     }
-                   } catch (IOException ex) {
-                   }
-               }
-            } catch (Exception e) {
-               e.printStackTrace();
-            }
-            try {
-                serverSocket.close();
-            } catch(IOException ex) {
-            }
-        } else {
-            if (ioex != null) {
-                ioex.printStackTrace();
-            }
-        }
-     }
-   }
-}
\ No newline at end of file

Modified: logging/log4j/trunk/tests/build.xml
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/build.xml?rev=398080&r1=398079&r2=398080&view=diff
==============================================================================
--- logging/log4j/trunk/tests/build.xml (original)
+++ logging/log4j/trunk/tests/build.xml Fri Apr 28 21:12:29 2006
@@ -225,7 +225,10 @@
                                      CachedDateFormat,
   	                                 Encoding,
   	                                 Syslog,
-                                     NTEventLogAppender
+                                     NTEventLogAppender,
+                                     RFA,
+                                     ERFA,
+                                     DRFA
                                      "/>
 
 
@@ -772,6 +775,30 @@
             <test name="org.apache.log4j.nt.NTEventLogAppenderTest" />
         </junit>
    </target>
+
+  <target name="DRFA" depends="build">
+    <junit printsummary="yes" fork="yes" haltonfailure="${haltonfailure}">
+      <classpath refid="tests.classpath"/>
+      <formatter type="plain" usefile="false"/>
+      <test name="org.apache.log4j.DRFATestCase" />
+    </junit>
+  </target>
+
+  <target name="RFA" depends="build">
+    <junit printsummary="yes" fork="yes" haltonfailure="${haltonfailure}">
+      <classpath refid="tests.classpath"/>
+      <formatter type="plain" usefile="false"/>
+      <test name="org.apache.log4j.RFATestCase" />
+    </junit>
+  </target>
+
+  <target name="ERFA" depends="build">
+    <junit printsummary="yes" fork="yes" haltonfailure="${haltonfailure}">
+      <classpath refid="tests.classpath"/>
+      <formatter type="plain" usefile="false"/>
+      <test name="org.apache.log4j.varia.ERFATestCase" />
+    </junit>
+  </target>
 
 
 

Added: logging/log4j/trunk/tests/input/RFA1.properties
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/input/RFA1.properties?rev=398080&view=auto
==============================================================================
--- logging/log4j/trunk/tests/input/RFA1.properties (added)
+++ logging/log4j/trunk/tests/input/RFA1.properties Fri Apr 28 21:12:29 2006
@@ -0,0 +1,12 @@
+log4j.rootLogger=DEBUG, testAppender
+log4j.appender.testAppender=org.apache.log4j.RollingFileAppender
+log4j.appender.testAppender.file=output/RFA-test1.log
+log4j.appender.testAppender.Append=false
+log4j.appender.testAppender.layout=org.apache.log4j.PatternLayout
+log4j.appender.testAppender.layout.ConversionPattern=%m\n
+log4j.appender.testAppender.maxFileSize=100
+
+#  Prevent internal log4j DEBUG messages from polluting the output.
+log4j.logger.org.apache.log4j.PropertyConfigurator=INFO
+log4j.logger.org.apache.log4j.config.PropertySetter=INFO
+log4j.logger.org.apache.log4j.FileAppender=INFO

Added: logging/log4j/trunk/tests/src/java/org/apache/log4j/DRFATestCase.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/src/java/org/apache/log4j/DRFATestCase.java?rev=398080&view=auto
==============================================================================
--- logging/log4j/trunk/tests/src/java/org/apache/log4j/DRFATestCase.java (added)
+++ logging/log4j/trunk/tests/src/java/org/apache/log4j/DRFATestCase.java Fri Apr 28 21:12:29 2006
@@ -0,0 +1,438 @@
+/*
+ * Copyright 1999-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ */
+
+package org.apache.log4j;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.TimeZone;
+import java.util.Date;
+import java.text.SimpleDateFormat;
+
+/**
+   Exhaustive test of the DailyRollingFileAppender compute algorithm.
+
+   @author Ceki G&uuml;lc&uuml;
+   @author Curt Arnold
+ */
+public class DRFATestCase extends TestCase {
+
+    /**
+     * Create new test.
+     * @param name test name.
+     */
+  public DRFATestCase(final String name) {
+    super(name);
+  }
+
+    /**
+     * Reset configuration after every test.
+     */
+  public void tearDown() {
+      LogManager.resetConfiguration();
+  }
+
+    /**
+     * Test prediction of check period.
+     * @deprecated since class under test is deprecated.
+     */
+  public
+  void testComputeCheckPeriod() {
+    DailyRollingFileAppender drfa = new DailyRollingFileAppender();
+    drfa.setName("testComputeCheckPeriod");
+    drfa.setDatePattern("yyyy-MM-dd.'log'");
+    drfa.activateOptions();
+
+    int x = drfa.computeCheckPeriod();
+    int y = DailyRollingFileAppender.TOP_OF_DAY;
+    assertEquals(drfa.computeCheckPeriod(),
+         DailyRollingFileAppender.TOP_OF_DAY);
+
+    drfa.setDatePattern("yyyy-MM-dd mm.'log'");
+    assertEquals(drfa.computeCheckPeriod(),
+         DailyRollingFileAppender.TOP_OF_MINUTE);
+
+    drfa.setDatePattern("yyyy-MM-dd a.'log'");
+    assertEquals(drfa.computeCheckPeriod(),
+         DailyRollingFileAppender.HALF_DAY);
+
+    drfa.setDatePattern("yyyy-MM-dd HH.'log'");
+    assertEquals(drfa.computeCheckPeriod(),
+         DailyRollingFileAppender.TOP_OF_HOUR);
+
+    drfa.setDatePattern("yyyy-MM.'log'");
+    assertEquals(drfa.computeCheckPeriod(),
+         DailyRollingFileAppender.TOP_OF_MONTH);
+
+    drfa.setDatePattern("'log'HH'log'");
+    assertEquals(drfa.computeCheckPeriod(),
+         DailyRollingFileAppender.TOP_OF_HOUR);
+  }
+
+
+    /**
+     *   Test of RollingCalendar.
+     * @deprecated since class under test is deprecated.
+     */
+  public
+  void testRC1() {
+    RollingCalendar rc = new RollingCalendar();
+    rc.setType(DailyRollingFileAppender.TOP_OF_DAY);
+
+    Calendar c = Calendar.getInstance();
+
+    // jan, mar, may, july, aug, oct, dec have 31 days
+    int [] M31 = {0,2,4,6,7,9,11};
+
+    for(int i = 0; i < M31.length; i ++) {
+      for(int d = 1; d <=31; d++) {
+    for(int h = 0; h < 23; h++) {
+      c.clear();
+      c.set(Calendar.YEAR, 20);
+      c.set(Calendar.MONTH, Calendar.JANUARY + M31[i]);
+      c.set(Calendar.DAY_OF_MONTH, d);
+      c.set(Calendar.HOUR_OF_DAY, h);
+      c.set(Calendar.MINUTE, 10);
+      c.set(Calendar.SECOND, 10);
+      c.set(Calendar.MILLISECOND, 88);
+
+      c.setTime(rc.getNextCheckDate(c.getTime()));
+      if(d == 31) {
+        assertEquals(c.get(Calendar.MONTH),(Calendar.JANUARY+M31[i]+1)%12);
+        assertEquals(c.get(Calendar.DAY_OF_MONTH), 1);
+      } else {
+        assertEquals(c.get(Calendar.MONTH), Calendar.JANUARY+M31[i]);
+        assertEquals(c.get(Calendar.DAY_OF_MONTH), d+1);
+      }
+      assertEquals(c.get(Calendar.HOUR_OF_DAY), 0);
+      assertEquals(c.get(Calendar.MINUTE), 0);
+      assertEquals(c.get(Calendar.SECOND), 0);
+      assertEquals(c.get(Calendar.MILLISECOND), 0);
+    }
+      }
+    }
+  }
+
+    /**
+     * RollingCalendar test.
+     * @deprecated since class under test is deprecated.
+     */
+  public
+  void testRC2() {
+    RollingCalendar rc = new RollingCalendar();
+
+    rc.setType(DailyRollingFileAppender.TOP_OF_HOUR);
+
+    Calendar c = Calendar.getInstance();
+    TimeZone tz = c.getTimeZone();
+
+    // jan, mar, may, july, aug, oct, dec have 31 days
+    int [] M31 = {0,2,4,6,7,9,11};
+
+    for(int i = 0; i < M31.length; i ++) {
+      System.out.println("Month = "+(M31[i]+1));
+      for(int d = 1; d <= 31; d++) {
+    for(int h = 0; h < 23; h++) {
+      for(int m = 0; m <= 59; m++) {
+        c.clear();
+        c.set(Calendar.YEAR, 20);
+        c.set(Calendar.MONTH, Calendar.JANUARY + M31[i]);
+        c.set(Calendar.DAY_OF_MONTH, d);
+        c.set(Calendar.HOUR_OF_DAY, h);
+        c.set(Calendar.MINUTE, m);
+        c.set(Calendar.SECOND, 12);
+        c.set(Calendar.MILLISECOND, 88);
+
+        boolean dltState0 = c.getTimeZone().inDaylightTime(c.getTime());
+        c.setTime(rc.getNextCheckDate(c.getTime()));
+        boolean dltState1 = c.getTimeZone().inDaylightTime(c.getTime());
+
+        assertEquals(c.get(Calendar.MILLISECOND), 0);
+        assertEquals(c.get(Calendar.SECOND), 0);
+        assertEquals(c.get(Calendar.MINUTE), 0);
+
+        if(dltState0 == dltState1) {
+          assertEquals(c.get(Calendar.HOUR_OF_DAY), (h+1)%24);
+        } else {
+          // returning to standard time
+          if(dltState0) {
+        assertEquals(c.get(Calendar.HOUR_OF_DAY), h);
+          } else { // switching to day light saving time
+        //System.err.println("m="+m+", h="+h+", d="+d+", i="+i);
+        //if(h==2) {
+        // System.err.println(c);
+        //}
+        //assertEquals(c.get(Calendar.HOUR_OF_DAY), (h+2)%24);
+          }
+        }
+
+        if(h == 23) {
+          assertEquals(c.get(Calendar.DAY_OF_MONTH), (d+1)%32);
+          if(d == 31) {
+        assertEquals(c.get(Calendar.MONTH),
+                 (Calendar.JANUARY+M31[i]+1)%12);
+          } else {
+        assertEquals(c.get(Calendar.MONTH),
+                 Calendar.JANUARY+M31[i]);
+          }
+        } else {
+          assertEquals(c.get(Calendar.DAY_OF_MONTH), d);
+          assertEquals(c.get(Calendar.MONTH), Calendar.JANUARY+M31[i]);
+        }
+      }
+    }
+      }
+    }
+  }
+
+    /**
+     * RollingCalendar test.
+     * @deprecated since class under test is deprecated.
+     */
+  public
+  void testRC3() {
+    RollingCalendar rc = new RollingCalendar();
+
+    rc.setType(DailyRollingFileAppender.TOP_OF_MINUTE);
+
+    int[] S = {0, 1, 5, 10, 21, 30, 59};
+    int[] M = {0, 1, 5, 10, 21, 30, 59};
+    Calendar c = Calendar.getInstance();
+
+    // jan, mar, may, july, aug, oct, dec have 31 days
+    int [] M31 = {2,9,0,4,6,7,11};
+
+    for(int i = 0; i < M31.length; i ++) {
+      System.out.println("Month = "+(M31[i]+1));
+      for(int d = 1; d <= 31; d++) {
+    for(int h = 0; h < 23; h++) {
+      for(int m = 0; m < M.length; m++) {
+        for(int s = 0; s < S.length; s++) {
+          c.clear();
+          c.set(Calendar.YEAR, 20);
+          c.set(Calendar.MONTH, Calendar.JANUARY + M31[i]);
+          c.set(Calendar.DAY_OF_MONTH, d);
+          c.set(Calendar.HOUR_OF_DAY, h);
+          c.set(Calendar.MINUTE, M[m]);
+          c.set(Calendar.SECOND, S[s]);
+          c.set(Calendar.MILLISECOND, 88);
+          c.add(Calendar.MILLISECOND, 1);
+
+          boolean dltState0 = c.getTimeZone().inDaylightTime(c.getTime());
+
+          c.setTime(rc.getNextCheckDate(c.getTime()));
+          c.add(Calendar.MILLISECOND, 0);
+          boolean dltState1 = c.getTimeZone().inDaylightTime(c.getTime());
+
+          assertEquals(c.get(Calendar.MILLISECOND), 0);
+          assertEquals(c.get(Calendar.SECOND), 0);
+          assertEquals(c.get(Calendar.MINUTE), (M[m]+1)%60);
+
+          if(M[m] == 59) {
+        if(dltState0 == dltState1) {
+          assertEquals(c.get(Calendar.HOUR_OF_DAY), (h+1)%24);
+        }
+        if(h == 23) {
+          assertEquals(c.get(Calendar.DAY_OF_MONTH), (d+1)%32);
+          if(d == 31) {
+              assertEquals(c.get(Calendar.MONTH),
+                 (Calendar.JANUARY+M31[i]+1)%12);
+          } else {
+            assertEquals(c.get(Calendar.MONTH),
+                 Calendar.JANUARY+M31[i]);
+          }
+        } else {
+          assertEquals(c.get(Calendar.DAY_OF_MONTH), d);
+        }
+          } else {
+        // allow discrepancies only if we are switching from std to dls time
+        if(c.get(Calendar.HOUR_OF_DAY) != h) {
+          c.add(Calendar.HOUR_OF_DAY, +1);
+          boolean dltState2 = c.getTimeZone().inDaylightTime(c.getTime());
+          if(dltState1 == dltState2) {
+            fail("No switch");
+          }
+        }
+        assertEquals(c.get(Calendar.DAY_OF_MONTH), d);
+        assertEquals(c.get(Calendar.MONTH), Calendar.JANUARY+M31[i]);
+          }
+        }
+      }
+    }
+      }
+    }
+  }
+
+
+    /**
+     * Common test code for 3 parameter constructor.
+     *
+     * @throws IOException if IOException during test.
+     * @deprecated since class under test is deprecated.
+     */
+   public void test3Param(final String datePattern,
+                          final String filename) throws IOException {
+       Layout layout = new SimpleLayout();
+       DailyRollingFileAppender appender =
+               new DailyRollingFileAppender(layout, filename, datePattern);
+       assertEquals(datePattern, appender.getDatePattern());
+       Logger root = Logger.getRootLogger();
+       root.addAppender(appender);
+       root.info("Hello, World");
+       assertTrue(new File(filename).exists());
+    }
+
+    /**
+     * Creates an appender with an unrecognized top-of-year pattern.
+     *
+     * @throws IOException if IOException during test.
+     * @deprecated since class under test is deprecated.
+     */
+    public void testTopOfYear() throws IOException {
+        try {
+            test3Param("'.'yyyy", "output/drfa_topOfYear.log");
+            fail("Expected illegal state exception.");
+        } catch(IllegalStateException ex) {
+            assertNotNull(ex);
+        }
+    }
+
+    /**
+     * Creates an appender with a top-of-month pattern.
+     *
+     * @throws IOException if IOException during test.
+     * @deprecated since class under test is deprecated.
+     */
+    public void testTopOfMonth() throws IOException {
+        test3Param("'.'yyyy-MM", "output/drfa_topOfMonth.log");
+    }
+
+
+    /**
+     * Creates an appender with a top-of-week pattern.
+     *
+     * @throws IOException if IOException during test.
+     * @deprecated since class under test is deprecated.
+     */
+    public void testTopOfWeek() throws IOException {
+        test3Param("'.'yyyy-w", "output/drfa_topOfWeek.log");
+    }
+
+    /**
+     * Creates an appender with a top-of-day pattern.
+     *
+     * @throws IOException if IOException during test.
+     * @deprecated since class under test is deprecated.
+     */
+    public void testTopOfDay() throws IOException {
+        test3Param("'.'yyyy-MM-dd", "output/drfa_topOfDay.log");
+    }
+
+
+    /**
+     * Creates an appender with a half day pattern.
+     *
+     * @throws IOException if IOException during test.
+     * @deprecated since class under test is deprecated.
+     */
+    public void testHalfDay() throws IOException {
+        test3Param("'.'yyyy-MM-dd-a", "output/drfa_halfDay.log");
+    }
+
+    /**
+     * Creates an appender with a top-of-hour pattern.
+     *
+     * @throws IOException if IOException during test.
+     * @deprecated since class under test is deprecated.
+     */
+    public void testTopOfHour() throws IOException {
+        test3Param("'.'yyyy-MM-dd-HH", "output/drfa_topOfHour.log");
+    }
+
+    /**
+     * Creates an appender with a top-of-day pattern.
+     *
+     * @throws IOException if IOException during test.
+     * @deprecated since class under test is deprecated.
+     */
+    public void testTopOfMinute() throws IOException {
+        test3Param("'.'yyyy-MM-dd-HH-mm", "output/drfa_topOfMinute.log");
+    }
+
+    /**
+     * Attempts to rollOver with no date pattern set.
+     *
+     * @throws IOException if IOException during test.
+     * @deprecated since class under test is deprecated.
+     */
+    public void testRolloverNoPattern() throws IOException {
+        Layout layout = new SimpleLayout();
+        DailyRollingFileAppender appender =
+                new DailyRollingFileAppender(layout, "output/drfa_nopattern.log", null);
+
+        VectorErrorHandler errorHandler = new VectorErrorHandler();
+        appender.setErrorHandler(errorHandler);
+        appender.rollOver();
+        assertEquals(1, errorHandler.size());
+        assertEquals("Missing DatePattern option in rollOver().",
+                errorHandler.getMessage(0));
+    }
+
+    /**
+     * Tests rollOver with a minute periodicity.
+     *
+     * @throws IOException
+     * @throws InterruptedException
+     * @deprecated since class under test is deprecated.
+     */
+    public void testMinuteRollover() throws IOException, InterruptedException {
+        Layout layout = new SimpleLayout();
+        String filename = "output/drfa_minuteRollover.log";
+        String pattern = "'.'yyyy-MM-dd-HH-mm";
+
+        DailyRollingFileAppender appender =
+                new DailyRollingFileAppender(layout,
+                        filename,
+                        pattern);
+        Logger root = Logger.getRootLogger();
+        root.addAppender(appender);
+        File firstFile =
+                new File(filename + new SimpleDateFormat(pattern).format(new Date()));
+        root.info("Hello, World");
+        //
+        //   create a file by that name so it has to be deleted
+        //       on rollover
+        firstFile.createNewFile();
+        assertTrue(firstFile.exists());
+        assertEquals(0, firstFile.length());
+
+        Calendar cal = Calendar.getInstance();
+        long now = cal.getTimeInMillis();
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 1);
+        cal.add(Calendar.MINUTE, 1);
+        long until = cal.getTimeInMillis();
+        Thread.sleep(until - now);
+        root.info("Hello, World");
+        assertTrue(firstFile.exists());
+        assertTrue(firstFile.length() > 0);
+
+    }
+
+}

Added: logging/log4j/trunk/tests/src/java/org/apache/log4j/RFATestCase.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/src/java/org/apache/log4j/RFATestCase.java?rev=398080&view=auto
==============================================================================
--- logging/log4j/trunk/tests/src/java/org/apache/log4j/RFATestCase.java (added)
+++ logging/log4j/trunk/tests/src/java/org/apache/log4j/RFATestCase.java Fri Apr 28 21:12:29 2006
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+package org.apache.log4j;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ *  Test of RollingFileAppender.
+ *
+ * @author Curt Arnold
+ */
+public class RFATestCase extends TestCase {
+
+  public RFATestCase(String name) {
+    super(name);
+  }
+
+  public void tearDown() {
+      LogManager.resetConfiguration();
+  }
+
+    /**
+     * Test basic rolling functionality using property file configuration.
+     */
+    public void test1() throws Exception {
+     Logger logger = Logger.getLogger(RFATestCase.class);
+      PropertyConfigurator.configure("input/RFA1.properties");
+
+      // Write exactly 10 bytes with each log
+      for (int i = 0; i < 25; i++) {
+        if (i < 10) {
+          logger.debug("Hello---" + i);
+        } else if (i < 100) {
+          logger.debug("Hello--" + i);
+        }
+      }
+
+      assertTrue(new File("output/RFA-test1.log").exists());
+      assertTrue(new File("output/RFA-test1.log.1").exists());
+    }
+
+    /**
+     * Test basic rolling functionality using API configuration.
+     */
+    public void test2() throws Exception {
+      Logger logger = Logger.getLogger(RFATestCase.class);
+      Logger root = Logger.getRootLogger();
+      PatternLayout layout = new PatternLayout("%m\n");
+      org.apache.log4j.RollingFileAppender rfa =
+        new org.apache.log4j.RollingFileAppender();
+      rfa.setName("ROLLING");
+      rfa.setLayout(layout);
+      rfa.setAppend(false);
+      rfa.setMaxBackupIndex(3);
+      rfa.setMaximumFileSize(100);
+      rfa.setFile("output/RFA-test2.log");
+      rfa.activateOptions();
+      root.addAppender(rfa);
+
+      // Write exactly 10 bytes with each log
+      for (int i = 0; i < 55; i++) {
+        if (i < 10) {
+          logger.debug("Hello---" + i);
+        } else if (i < 100) {
+          logger.debug("Hello--" + i);
+        }
+      }
+
+      assertTrue(new File("output/RFA-test2.log").exists());
+      assertTrue(new File("output/RFA-test2.log.1").exists());
+      assertTrue(new File("output/RFA-test2.log.2").exists());
+      assertTrue(new File("output/RFA-test2.log.3").exists());
+      assertFalse(new File("output/RFA-test2.log.4").exists());
+    }
+
+    /**
+     * Tests 2 parameter constructor.
+     * @throws IOException if IOException during test.
+     */
+    public void test2ParamConstructor() throws IOException {
+        SimpleLayout layout = new SimpleLayout();
+        RollingFileAppender appender =
+                new RollingFileAppender(layout,"output/rfa_2param.log");
+        assertEquals(1, appender.getMaxBackupIndex());
+        assertEquals(10*1024*1024, appender.getMaximumFileSize());
+    }
+    /**
+     * Tests 3 parameter constructor.
+     * @throws IOException if IOException during test.
+     */
+    public void test3ParamConstructor() throws IOException {
+        SimpleLayout layout = new SimpleLayout();
+        RollingFileAppender appender =
+                new RollingFileAppender(layout,"output/rfa_3param.log", false);
+        assertEquals(1, appender.getMaxBackupIndex());
+    }
+
+}

Modified: logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/SizeBasedRollingTest.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/SizeBasedRollingTest.java?rev=398080&r1=398079&r2=398080&view=diff
==============================================================================
--- logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/SizeBasedRollingTest.java (original)
+++ logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/SizeBasedRollingTest.java Fri Apr 28 21:12:29 2006
@@ -360,16 +360,4 @@
   }
 
 
-    /**
-     * Build test suite using this class and ObsoleteRollingFileAppenderTest.
-     *
-     * @deprecated Marked deprecated since suite contains tests of deprecated classes
-     * @return test suite.
-     */
-  public static Test suite() {
-    TestSuite suite = new TestSuite();
-    suite.addTestSuite(SizeBasedRollingTest.class);
-    suite.addTestSuite(ObsoleteRollingFileAppenderTest.class);
-    return suite;
-  }
 }

Modified: logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/TimeBasedRollingTest.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/TimeBasedRollingTest.java?rev=398080&r1=398079&r2=398080&view=diff
==============================================================================
--- logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/TimeBasedRollingTest.java (original)
+++ logging/log4j/trunk/tests/src/java/org/apache/log4j/rolling/TimeBasedRollingTest.java Fri Apr 28 21:12:29 2006
@@ -483,17 +483,4 @@
     }
   }
 
-  /**
-   * Build test suite using this class and ObsoleteDailyRollingFileAppenderTest.
-   *
-   * @deprecated Marked deprecated since suite contains tests of deprecated classes
-   * @return test suite.
-   */
-  public static Test suite() {
-    TestSuite suite = new TestSuite();
-    suite.addTestSuite(TimeBasedRollingTest.class);
-    suite.addTestSuite(ObsoleteDailyRollingFileAppenderTest.class);
-
-    return suite;
-  }
 }

Added: logging/log4j/trunk/tests/src/java/org/apache/log4j/varia/ERFATestCase.java
URL: http://svn.apache.org/viewcvs/logging/log4j/trunk/tests/src/java/org/apache/log4j/varia/ERFATestCase.java?rev=398080&view=auto
==============================================================================
--- logging/log4j/trunk/tests/src/java/org/apache/log4j/varia/ERFATestCase.java (added)
+++ logging/log4j/trunk/tests/src/java/org/apache/log4j/varia/ERFATestCase.java Fri Apr 28 21:12:29 2006
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+package org.apache.log4j.varia;
+import junit.framework.TestCase;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PatternLayout;
+import org.apache.log4j.RFATestCase;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.net.Socket;
+
+/**
+ *  Test of ExternallyRolledFileAppender.
+ *
+ * @author Curt Arnold
+ */
+public class ERFATestCase extends TestCase {
+
+    /**
+     * Create new instance of test.
+     * @param name test name.
+     */
+  public ERFATestCase(final String name) {
+    super(name);
+  }
+
+    /**
+     * Reset configuration after test.
+     */
+  public void tearDown() {
+      LogManager.resetConfiguration();
+  }
+
+    /**
+     * Test ExternallyRolledFileAppender constructor.
+     * @deprecated since class under test is deprecated.
+     */
+  public void testConstructor() {
+      ExternallyRolledFileAppender appender =
+              new ExternallyRolledFileAppender();
+      assertEquals(0, appender.getPort());
+  }
+
+    /**
+     * Send a message to the ERFA.
+     * @param port port number.
+     * @param msg message, may not be null.
+     * @param expectedResponse expected response, may not be null.
+     * @throws IOException thrown on IO error.
+     * @deprecated since class under test is deprecated.
+     */
+  void sendMessage(int port, final String msg, final String expectedResponse) throws IOException {
+      Socket socket = new Socket((String) null, port);
+      DataInputStream reader = new DataInputStream(socket.getInputStream());
+      DataOutputStream writer = new DataOutputStream(socket.getOutputStream());
+      writer.writeUTF(msg);
+      String response = reader.readUTF();
+      assertEquals(expectedResponse, response);
+      reader.close();
+      writer.close();
+      socket.close();
+  }
+
+    /**
+     * Test externally triggered rollover.
+     * @throws IOException thrown on IO error.
+     * @deprecated since class under test is deprecated.
+     */
+  public void testRollover() throws IOException {
+      ExternallyRolledFileAppender erfa =
+              new ExternallyRolledFileAppender();
+
+      int port = 5500;
+
+      Logger logger = Logger.getLogger(RFATestCase.class);
+      Logger root = Logger.getRootLogger();
+      PatternLayout layout = new PatternLayout("%m\n");
+      erfa.setLayout(layout);
+      erfa.setAppend(false);
+      erfa.setMaxBackupIndex(2);
+      erfa.setPort(port);
+      erfa.setFile("output/ERFA-test2.log");
+      try {
+        erfa.activateOptions();
+      } catch(SecurityException ex) {
+          return;
+      }
+      root.addAppender(erfa);
+
+
+      // Write exactly 10 bytes with each log
+      for (int i = 0; i < 55; i++) {
+        if (i < 10) {
+          logger.debug("Hello---" + i);
+        } else if (i < 100) {
+          logger.debug("Hello--" + i);
+        }
+        if ((i % 10) == 9) {
+            try {
+                sendMessage(port, "RollOver", "OK");
+            } catch(SecurityException ex) {
+                return;
+            }
+        }
+      }
+
+      try {
+        sendMessage(port,
+              "That's all folks.",
+              "Expecting [RollOver] string.");
+      } catch(SecurityException ex) {
+          return;
+      }
+
+
+      assertTrue(new File("output/ERFA-test2.log").exists());
+      assertTrue(new File("output/ERFA-test2.log.1").exists());
+      assertTrue(new File("output/ERFA-test2.log.2").exists());
+      assertFalse(new File("output/ERFA-test2.log.3").exists());
+  }
+}



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