[logback-dev] [GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. v_0.9.29-5-g690ac09

added by portage for gitosis-gentoo git-noreply at pixie.qos.ch
Thu Jun 23 23:48:20 CEST 2011


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".

The branch, master has been updated
       via  690ac09e30d017edea2681395b1fa33095f5f269 (commit)
      from  33a24d81695f2a90ed239c0054225992c6be4aab (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=690ac09e30d017edea2681395b1fa33095f5f269
http://github.com/ceki/logback/commit/690ac09e30d017edea2681395b1fa33095f5f269

commit 690ac09e30d017edea2681395b1fa33095f5f269
Author: Ceki Gulcu <ceki at qos.ch>
Date:   Thu Jun 23 23:40:38 2011 +0200

    fixed LBCLASSIC-265

diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeFilter.java b/logback-classic/src/main/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeFilter.java
index c514c68..6615f51 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeFilter.java
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeFilter.java
@@ -19,8 +19,11 @@ import java.util.List;
 
 import ch.qos.logback.classic.gaffer.GafferUtil;
 import ch.qos.logback.classic.util.EnvUtil;
+import ch.qos.logback.core.joran.event.SaxEvent;
 import ch.qos.logback.core.joran.spi.ConfigurationWatchList;
 import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil;
+import ch.qos.logback.core.status.StatusChecker;
+import ch.qos.logback.core.status.WarnStatus;
 import org.slf4j.Marker;
 
 import ch.qos.logback.classic.Level;
@@ -51,26 +54,33 @@ public class ReconfigureOnChangeFilter extends TurboFilter {
   URL mainConfigurationURL;
   protected volatile long nextCheck;
 
-  ConfigurationWatchList cwl;
+  ConfigurationWatchList configurationWatchList;
 
   @Override
   public void start() {
-    cwl = ConfigurationWatchListUtil.getConfigurationWatchList(context);
-    if (cwl != null) {
-      mainConfigurationURL = cwl.getMainURL();
-      List<File> watchList = cwl.getCopyOfFileWatchList();
+    configurationWatchList = ConfigurationWatchListUtil.getConfigurationWatchList(context);
+    if (configurationWatchList != null) {
+      mainConfigurationURL = configurationWatchList.getMainURL();
+      List<File> watchList = configurationWatchList.getCopyOfFileWatchList();
       long inSeconds = refreshPeriod / 1000;
       addInfo("Will scan for changes in [" + watchList + "] every "
               + inSeconds + " seconds. ");
-      synchronized (cwl) {
+      synchronized (configurationWatchList) {
         updateNextCheck(System.currentTimeMillis());
       }
       super.start();
-    }  else {
+    } else {
       addWarn("Empty ConfigurationWatchList in context");
     }
   }
 
+  @Override
+  public String toString() {
+    return "ReconfigureOnChangeFilter{" +
+            "invocationCounter=" + invocationCounter +
+            '}';
+  }
+
   // The next fields counts the number of time the decide method is called
   //
   // IMPORTANT: This field can be updated by multiple threads. It follows that
@@ -91,7 +101,7 @@ public class ReconfigureOnChangeFilter extends TurboFilter {
       return FilterReply.NEUTRAL;
     }
 
-    synchronized (cwl) {
+    synchronized (configurationWatchList) {
       if (changeDetected()) {
         // Even though reconfiguration involves resetting the loggerContext,
         // which clears the list of turbo filters including this instance, it is
@@ -109,7 +119,7 @@ public class ReconfigureOnChangeFilter extends TurboFilter {
   // locks held by the current thread, in particular, the AppenderAttachable
   // reader lock.
   private void detachReconfigurationToNewThread() {
-    addInfo("Detected change in [" + cwl.getCopyOfFileWatchList() + "]");
+    addInfo("Detected change in [" + configurationWatchList.getCopyOfFileWatchList() + "]");
     new ReconfiguringThread().start();
   }
 
@@ -121,7 +131,7 @@ public class ReconfigureOnChangeFilter extends TurboFilter {
     long now = System.currentTimeMillis();
     if (now >= nextCheck) {
       updateNextCheck(now);
-      return cwl.changeDetected();
+      return configurationWatchList.changeDetected();
     }
     return false;
   }
@@ -140,23 +150,14 @@ public class ReconfigureOnChangeFilter extends TurboFilter {
 
   class ReconfiguringThread extends Thread {
     public void run() {
-      if(mainConfigurationURL == null) {
+      if (mainConfigurationURL == null) {
         addInfo("Due to missing top level configuration file, skipping reconfiguration");
         return;
       }
       LoggerContext lc = (LoggerContext) context;
       addInfo("Will reset and reconfigure context named [" + context.getName() + "]");
       if (mainConfigurationURL.toString().endsWith("xml")) {
-        JoranConfigurator jc = new JoranConfigurator();
-        jc.setContext(context);
-        lc.reset();
-        try {
-          jc.doConfigure(mainConfigurationURL);
-          lc.getStatusManager().add(
-                  new InfoStatus("done resetting the logging context", this));
-        } catch (JoranException e) {
-          addError("Failure during reconfiguration", e);
-        }
+        performXMLConfiguration(lc);
       } else if (mainConfigurationURL.toString().endsWith("groovy")) {
         if (EnvUtil.isGroovyAvailable()) {
           lc.reset();
@@ -168,5 +169,41 @@ public class ReconfigureOnChangeFilter extends TurboFilter {
         }
       }
     }
+
+    private void performXMLConfiguration(LoggerContext lc) {
+      JoranConfigurator jc = new JoranConfigurator();
+      jc.setContext(context);
+      StatusChecker statusChecker = new StatusChecker(context);
+      List<SaxEvent> eventList = jc.recallSafeConfiguration();
+      lc.getStatusManager().add(
+              new InfoStatus("Resetting the logging ", this));
+      lc.reset();
+
+      try {
+        jc.doConfigure(mainConfigurationURL);
+      } catch (JoranException e) {
+        fallbackConfiguration(lc, eventList);
+      }
+    }
+
+    private void fallbackConfiguration(LoggerContext lc, List<SaxEvent> eventList) {
+      JoranConfigurator jc = new JoranConfigurator();
+      jc.setContext(context);
+      if (eventList != null) {
+        lc.getStatusManager().add(
+                new WarnStatus("Falling back to previously registered safe configuration.", this));
+        try {
+          jc.doConfigure(eventList);
+          addInfo("Re-registering previous fallback configuration as a fallback point");
+          jc.registerSafeConfiguration();
+        } catch (JoranException e) {
+          addError("Unexpected exception thrown by configuration considered as safes", e);
+        }
+      } else {
+        lc.getStatusManager().add(
+                new WarnStatus("No previous configuration to fall back to.", this));
+
+      }
+    }
   }
 }
diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeTest.java
index 885e10f..6def1ae 100644
--- a/logback-classic/src/test/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeTest.java
+++ b/logback-classic/src/test/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeTest.java
@@ -14,6 +14,7 @@
 package ch.qos.logback.classic.turbo;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import java.io.*;
@@ -22,7 +23,8 @@ import java.util.Random;
 
 import ch.qos.logback.classic.gaffer.GafferConfigurator;
 import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil;
-import org.hsqldb.lib.StringInputStream;
+import ch.qos.logback.core.testUtil.RandomUtil;
+import ch.qos.logback.core.util.CoreTestConstants;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -47,6 +49,12 @@ public class ReconfigureOnChangeTest {
   final static int THREAD_COUNT = 5;
   final static int LOOP_LEN = 1000 * 1000;
 
+  static final boolean  MUST_BE_ERROR_FREE = true;
+  static final boolean  ERRORS_EXPECTED = false;
+
+
+  int diff = RandomUtil.getPositiveInt();
+
   // the space in the file name mandated by
   // http://jira.qos.ch/browse/LBCORE-119
   final static String SCAN1_FILE_AS_STR = ClassicTestConstants.INPUT_PREFIX
@@ -118,9 +126,9 @@ public class ReconfigureOnChangeTest {
     gc.run(file);
   }
 
-  RunnableWithCounterAndDone[] buildRunnableArray(File configFile) {
+  RunnableWithCounterAndDone[] buildRunnableArray(File configFile, UpdateType updateType) {
     RunnableWithCounterAndDone[] rArray = new RunnableWithCounterAndDone[THREAD_COUNT];
-    rArray[0] = new Updater(configFile);
+    rArray[0] = new Updater(configFile, updateType);
     for (int i = 1; i < THREAD_COUNT; i++) {
       rArray[i] = new LoggingRunnable(logger);
     }
@@ -129,11 +137,11 @@ public class ReconfigureOnChangeTest {
 
 
   void doScanTest(File fileToTouch) throws JoranException, IOException, InterruptedException {
-    doScanTest(fileToTouch, false);
+    doScanTest(fileToTouch, UpdateType.TOUCH, false, MUST_BE_ERROR_FREE);
   }
 
-  void doScanTest(File fileToTouch, boolean forcedReconfigurationSkip) throws JoranException, IOException, InterruptedException {
-    RunnableWithCounterAndDone[] runnableArray = buildRunnableArray(fileToTouch);
+  void doScanTest(File fileToTouch, UpdateType updateType, boolean forcedReconfigurationSkip, boolean mustBeErrorFree) throws JoranException, IOException, InterruptedException {
+    RunnableWithCounterAndDone[] runnableArray = buildRunnableArray(fileToTouch, updateType);
     harness.execute(runnableArray);
 
     loggerContext.getStatusManager().add(
@@ -143,7 +151,7 @@ public class ReconfigureOnChangeTest {
     if(forcedReconfigurationSkip)
       expectedReconfigurations = 0;
 
-    verify(expectedReconfigurations);
+    verify(expectedReconfigurations, mustBeErrorFree);
   }
 
   // chose a test at random. These tests are rather long...
@@ -195,21 +203,31 @@ public class ReconfigureOnChangeTest {
     String configurationStr = "<configuration scan=\"true\" scanPeriod=\"50 millisecond\"><include resource=\"asResource/inner1.xml\"/></configuration>";
     configure(new ByteArrayInputStream(configurationStr.getBytes("UTF-8")));
     File innerFile = new File(INCLUSION_SCAN_INNER1_AS_STR);
-    doScanTest(innerFile, true);
+    doScanTest(innerFile, UpdateType.TOUCH, true, MUST_BE_ERROR_FREE);
+  }
+
+  @Test
+  public void fallbackToSafe() throws IOException, JoranException, InterruptedException {
+    String path = CoreTestConstants.OUTPUT_DIR_PREFIX + "reconfigureOnChangeConfig-"+diff + ".xml";
+    File file = new File(path);
+    writeToFile(file, "<configuration scan=\"true\" scanPeriod=\"50 millisecond\"><root level=\"ERROR\"/></configuration> ");
+    configure(file);
+    doScanTest(file, UpdateType.MALFORMED, false, ERRORS_EXPECTED);
   }
 
+
   @Test
   public void gscan1() throws JoranException, IOException, InterruptedException {
     File file = new File(G_SCAN1_FILE_AS_STR);
     gConfigure(file);
-    RunnableWithCounterAndDone[] runnableArray = buildRunnableArray(file);
+    RunnableWithCounterAndDone[] runnableArray = buildRunnableArray(file, UpdateType.TOUCH);
     harness.execute(runnableArray);
 
     loggerContext.getStatusManager().add(
             new InfoStatus("end of execution ", this));
 
     long expectedRreconfigurations = runnableArray[0].getCounter();
-    verify(expectedRreconfigurations);
+    verify(expectedRreconfigurations, MUST_BE_ERROR_FREE);
   }
 
   // check for deadlocks
@@ -219,23 +237,27 @@ public class ReconfigureOnChangeTest {
           InterruptedException {
     File file = new File(SCAN_LBCLASSIC_154_FILE_AS_STR);
     configure(file);
-    RunnableWithCounterAndDone[] runnableArray = buildRunnableArray(file);
+    RunnableWithCounterAndDone[] runnableArray = buildRunnableArray(file, UpdateType.TOUCH);
     harness.execute(runnableArray);
 
     loggerContext.getStatusManager().add(
             new InfoStatus("end of execution ", this));
 
     long expectedReconfigurations = runnableArray[0].getCounter();
-    verify(expectedReconfigurations);
+    verify(expectedReconfigurations, MUST_BE_ERROR_FREE);
   }
 
 
 
 
-  void verify(long expectedReconfigurations) {
+  void verify(long expectedReconfigurations, boolean errorFreeness) {
     StatusChecker checker = new StatusChecker(loggerContext);
     StatusPrinter.print(loggerContext);
-    assertTrue(checker.isErrorFree(0));
+    if(errorFreeness == MUST_BE_ERROR_FREE) {
+      assertTrue(checker.isErrorFree(0));
+    } else {
+      assertFalse(checker.isErrorFree(0));
+    }
     int effectiveResets = checker
             .matchCount("Will reset and reconfigure context");
     // the number of effective resets must be equal or less than
@@ -329,11 +351,29 @@ public class ReconfigureOnChangeTest {
     return (end - start) / (1.0d * LOOP_LEN);
   }
 
+  enum UpdateType {TOUCH, MALFORMED}
+
+  void writeToFile(File file, String contents) {
+    try {
+      FileWriter fw = new FileWriter(file);
+      fw.write(contents);
+      fw.close();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
   class Updater extends RunnableWithCounterAndDone {
     File configFile;
+    UpdateType updateType;
 
-    Updater(File configFile) {
+    Updater(File configFile, UpdateType updateType) {
       this.configFile = configFile;
+      this.updateType = updateType;
+    }
+
+    Updater(File configFile) {
+      this(configFile, UpdateType.TOUCH);
     }
 
     public void run() {
@@ -347,9 +387,25 @@ public class ReconfigureOnChangeTest {
         }
         counter++;
         ReconfigureOnChangeTest.this.addInfo("***settting last modified", this);
-        configFile.setLastModified(System.currentTimeMillis());
+        switch(updateType) {
+          case TOUCH: updateFile();
+            break;
+          case MALFORMED:
+            malformedUpdate(counter);
+        }
       }
     }
+
+    private void malformedUpdate(long counter) {
+      writeToFile(configFile, "<configuration scan=\"true\" scanPeriod=\"50 millisecond\">\n" +
+              "  <root level=\"ERROR\">\n" +
+              "</configuration>");
+    }
+    void updateFile() {
+      configFile.setLastModified(System.currentTimeMillis());
+    }
   }
 
+
+
 }
diff --git a/logback-core/src/main/java/ch/qos/logback/core/CoreConstants.java b/logback-core/src/main/java/ch/qos/logback/core/CoreConstants.java
index 3c624fa..ef1afb8 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/CoreConstants.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/CoreConstants.java
@@ -62,12 +62,12 @@ public class CoreConstants {
   /**
    * An empty string array.
    */
-  public final static String[] EMPTY_STRING_ARRAY = new String[] {};
+  public final static String[] EMPTY_STRING_ARRAY = new String[]{};
 
   /**
    * An empty Class array.
    */
-  public final static Class<?>[] EMPTY_CLASS_ARRAY = new Class[] {};
+  public final static Class<?>[] EMPTY_CLASS_ARRAY = new Class[]{};
   public final static String CAUSED_BY = "Caused by: ";
 
 
@@ -111,9 +111,10 @@ public class CoreConstants {
 
   static public final String SEE_FNP_NOT_SET = "See also http://logback.qos.ch/codes.html#tbr_fnp_not_set";
 
-  public static String CONFIGURATION_WATCH_LIST = "CONFIGURATION_WATCH_LIST";
-  public static String CONFIGURATION_WATCH_LIST_RESET = "CONFIGURATION_WATCH_LIST_RESET";
+  static public final String CONFIGURATION_WATCH_LIST = "CONFIGURATION_WATCH_LIST";
+  static public final String CONFIGURATION_WATCH_LIST_RESET = "CONFIGURATION_WATCH_LIST_RESET";
 
+  static public final String SAFE_JORAN_CONFIGURATION = "SAFE_JORAN_CONFIGURATION";
 
   /**
    * The key under which the local host name is registered in the logger
@@ -123,12 +124,11 @@ public class CoreConstants {
 
   /**
    * The key under which the current context name is registered in the logger
-   * context. 
+   * context.
    */
   public static final String CONTEXT_NAME_KEY = "CONTEXT_NAME";
 
 
   public static int BYTES_PER_INT = 4;
   public static final int MILLIS_IN_ONE_SECOND = 1000;
-  public final static String XML_PARSING_ERROR = "XML PARSING ERROR";
 }
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/GenericConfigurator.java b/logback-core/src/main/java/ch/qos/logback/core/joran/GenericConfigurator.java
index 9b6ac3a..d52c529 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/GenericConfigurator.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/GenericConfigurator.java
@@ -21,6 +21,8 @@ import java.net.URL;
 import java.net.URLConnection;
 import java.util.List;
 
+import static ch.qos.logback.core.CoreConstants.SAFE_JORAN_CONFIGURATION;
+
 import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil;
 import org.xml.sax.InputSource;
 
@@ -47,7 +49,7 @@ public abstract class GenericConfigurator extends ContextAwareBase {
       // per http://jira.qos.ch/browse/LBCORE-105
       // per http://jira.qos.ch/browse/LBCORE-127
       urlConnection.setUseCaches(false);
-      
+
       InputStream in = urlConnection.getInputStream();
       doConfigure(in);
       in.close();
@@ -69,7 +71,7 @@ public abstract class GenericConfigurator extends ContextAwareBase {
       fis = new FileInputStream(file);
       doConfigure(fis);
     } catch (IOException ioe) {
-      String errMsg = "Could not open [" + file.getName() + "].";
+      String errMsg = "Could not open [" + file.getPath() + "].";
       addError(errMsg, ioe);
       throw new JoranException(errMsg, ioe);
     } finally {
@@ -98,13 +100,13 @@ public abstract class GenericConfigurator extends ContextAwareBase {
   abstract protected void addImplicitRules(Interpreter interpreter);
 
   protected void addDefaultNestedComponentRegistryRules(DefaultNestedComponentRegistry registry) {
-    
+
   }
-  
+
   protected Pattern initialPattern() {
     return new Pattern();
   }
-  
+
   protected void buildInterpreter() {
     RuleStore rs = new SimpleRuleStore(context);
     addInstanceRules(rs);
@@ -118,27 +120,43 @@ public abstract class GenericConfigurator extends ContextAwareBase {
   // this is the most inner form of doConfigure whereto other doConfigure
   // methods ultimately delegate
   final public void doConfigure(final InputSource inputSource)
-      throws JoranException {
+          throws JoranException {
 
-    if(!ConfigurationWatchListUtil.wasConfigurationWatchListReset(context)) {
+    if (!ConfigurationWatchListUtil.wasConfigurationWatchListReset(context)) {
       informContextOfURLUsedForConfiguration(null);
     }
     SaxEventRecorder recorder = new SaxEventRecorder();
     recorder.setContext(context);
     recorder.recordEvents(inputSource);
+    doConfigure(recorder.saxEventList);
+    // no exceptions a this level
+    addInfo("Registering current configuration as safe fallback point");
+    registerSafeConfiguration();
+  }
+
+  public void doConfigure(final List<SaxEvent> eventList)
+          throws JoranException {
     buildInterpreter();
     // disallow simultaneous configurations of the same context
     synchronized (context.getConfigurationLock()) {
-      interpreter.play(recorder.saxEventList);
+      interpreter.getEventPlayer().play(eventList);
     }
+  }
 
+  /**
+   * Register the current event list in currently in the interpreter as a safe
+   * configuration point.
+   *
+   * @since 0.9.30
+   */
+  public void registerSafeConfiguration() {
+    context.putObject(SAFE_JORAN_CONFIGURATION, interpreter.getEventPlayer().getCopyOfPlayerEventList());
   }
 
-  // protected since v0.9.30
-  protected void doConfigure(final List<SaxEvent> eventList)
-      throws JoranException {
-    buildInterpreter();
-    EventPlayer player = new EventPlayer(interpreter);
-    player.play(eventList);
+  /**
+   * Recall the event list previously registered as a safe point.
+   */
+  public List<SaxEvent> recallSafeConfiguration() {
+    return (List<SaxEvent>) context.getObject(SAFE_JORAN_CONFIGURATION);
   }
 }
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/action/IncludeAction.java b/logback-core/src/main/java/ch/qos/logback/core/joran/action/IncludeAction.java
index e29178d..286e2d2 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/action/IncludeAction.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/action/IncludeAction.java
@@ -69,7 +69,7 @@ public class IncludeAction extends Action {
     trimHeadAndTail(recorder);
 
     // offset = 2, because we need to get past this element as well as the end element
-    ec.getJoranInterpreter().addEventsDynamically(recorder.saxEventList, 2);
+    ec.getJoranInterpreter().getEventPlayer().addEventsDynamically(recorder.saxEventList, 2);
   }
 
   void close(InputStream in) {
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java
index e0e5f8b..97f9c80 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/conditional/IfAction.java
@@ -112,7 +112,7 @@ public class IfAction extends Action {
     // if boolResult==false & missing else,  listToPlay may be null
     if(listToPlay != null) {
       // insert past this event
-      interpreter.addEventsDynamically(listToPlay, 1);
+      interpreter.getEventPlayer().addEventsDynamically(listToPlay, 1);
     }
 
   }
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/event/SaxEventRecorder.java b/logback-core/src/main/java/ch/qos/logback/core/joran/event/SaxEventRecorder.java
index 5efbcd0..2e815e2 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/event/SaxEventRecorder.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/event/SaxEventRecorder.java
@@ -59,11 +59,12 @@ public class SaxEventRecorder extends DefaultHandler implements ContextAware {
       saxParser.parse(inputSource, this);
       return saxEventList;
     } catch (IOException ie) {
-      handleError(CoreConstants.XML_PARSING_ERROR+ ". I/O error occurred while parsing xml file", ie);
+      handleError("I/O error occurred while parsing xml file", ie);
     } catch(SAXException se) {
-      handleError(CoreConstants.XML_PARSING_ERROR+ ". Problem parsing XML document. See previously reported errors.", se);
+      // Exception added into StatusManager via Sax error handling. No need to add it again
+      throw new JoranException("Problem parsing XML document. See previously reported errors.", se);
     } catch (Exception ex) {
-      handleError(CoreConstants.XML_PARSING_ERROR+ ". Unexpected exception while parsing XML document.", ex);
+      handleError("Unexpected exception while parsing XML document.", ex);
     }
     throw new IllegalStateException("This point can never be reached");
   }
@@ -80,7 +81,7 @@ public class SaxEventRecorder extends DefaultHandler implements ContextAware {
       spf.setNamespaceAware(true);
       return spf.newSAXParser();
     } catch (Exception pce) {
-      String errMsg = "Parser configuration error occured";
+      String errMsg = "Parser configuration error occurred";
       addError(errMsg, pce);
       throw new JoranException(errMsg, pce);
     }
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/EventPlayer.java b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/EventPlayer.java
index 61d058f..3197407 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/EventPlayer.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/EventPlayer.java
@@ -13,6 +13,7 @@
  */
 package ch.qos.logback.core.joran.spi;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import ch.qos.logback.core.joran.event.BodyEvent;
@@ -29,7 +30,16 @@ public class EventPlayer {
   public EventPlayer(Interpreter interpreter) {
     this.interpreter = interpreter; 
   }
-  
+
+  /**
+   * Return a copy of the current event list in the player.
+   * @return
+   * @since 0.9.20
+   */
+  public List<SaxEvent> getCopyOfPlayerEventList() {
+    return new ArrayList<SaxEvent>(eventList);
+  }
+
   public void play(List<SaxEvent> seList) {
     eventList = seList;
     SaxEvent se;
diff --git a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java
index 48f074b..3f2698a 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java
@@ -74,7 +74,7 @@ public class Interpreter {
   final private CAI_WithLocatorSupport cai;
   private Pattern pattern;
   Locator locator;
-  EventPlayer player;
+  EventPlayer eventPlayer;
 
   /**
    * The <id>actionListStack</id> contains a list of actions that are executing
@@ -100,7 +100,11 @@ public class Interpreter {
     implicitActions = new ArrayList<ImplicitAction>(3);
     this.pattern = initialPattern;
     actionListStack = new Stack<List>();
-    player = new EventPlayer(this);
+    eventPlayer = new EventPlayer(this);
+  }
+
+  public EventPlayer getEventPlayer() {
+    return eventPlayer;
   }
 
   public void setInterpretationContextPropertiesMap(
@@ -327,16 +331,6 @@ public class Interpreter {
   public RuleStore getRuleStore() {
     return ruleStore;
   }
-
-  public void play(List<SaxEvent> eventList) {
-    player.play(eventList);
-  }
-
-  public void addEventsDynamically(List<SaxEvent> eventList, int offset) {
-    if (player != null) {
-      player.addEventsDynamically(eventList, offset);
-    }
-  }
 }
 
 /**
diff --git a/logback-core/src/main/java/ch/qos/logback/core/status/StatusChecker.java b/logback-core/src/main/java/ch/qos/logback/core/status/StatusChecker.java
index 207db5d..ff82f46 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/status/StatusChecker.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/status/StatusChecker.java
@@ -20,6 +20,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import ch.qos.logback.core.Context;
+import ch.qos.logback.core.CoreConstants;
 
 public class StatusChecker {
 
@@ -46,7 +47,7 @@ public class StatusChecker {
     List<Status> filteredList = filterStatusListByTimeThreshold(sm.getCopyOfStatusList(), threshold);
     int maxLevel = Status.INFO;
     for (Status s : filteredList) {
-      if(s.getLevel() > maxLevel)
+      if (s.getLevel() > maxLevel)
         maxLevel = s.getLevel();
     }
     return maxLevel;
diff --git a/logback-core/src/test/java/ch/qos/logback/core/joran/TrivialConfiguratorTest.java b/logback-core/src/test/java/ch/qos/logback/core/joran/TrivialConfiguratorTest.java
index f8ce354..236e01a 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/joran/TrivialConfiguratorTest.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/joran/TrivialConfiguratorTest.java
@@ -28,6 +28,8 @@ import java.util.jar.JarOutputStream;
 import java.util.zip.ZipEntry;
 
 import ch.qos.logback.core.CoreConstants;
+import ch.qos.logback.core.db.dialect.SQLDialect;
+import ch.qos.logback.core.util.StatusPrinter;
 import org.junit.Test;
 
 import ch.qos.logback.core.Context;
@@ -54,8 +56,7 @@ public class TrivialConfiguratorTest {
     TrivialConfigurator trivialConfigurator = new TrivialConfigurator(rulesMap);
 
     trivialConfigurator.setContext(context);
-    trivialConfigurator.doConfigure(CoreTestConstants.TEST_DIR_PREFIX
-        + "input/joran/" + filename);
+    trivialConfigurator.doConfigure(filename);
   }
 
   @Test
@@ -63,7 +64,7 @@ public class TrivialConfiguratorTest {
     int oldBeginCount = IncAction.beginCount;
     int oldEndCount = IncAction.endCount;
     int oldErrorCount = IncAction.errorCount;
-    doTest("inc.xml");
+    doTest(CoreTestConstants.TEST_DIR_PREFIX + "input/joran/"+"inc.xml");
     assertEquals(oldErrorCount, IncAction.errorCount);
     assertEquals(oldBeginCount + 1, IncAction.beginCount);
     assertEquals(oldEndCount + 1, IncAction.endCount);
@@ -72,35 +73,33 @@ public class TrivialConfiguratorTest {
   @Test
   public void inexistentFile() {
     TrivialStatusListener tsl = new TrivialStatusListener();
-    String filename = "nothereBLAH.xml";
+    String filename = CoreTestConstants.TEST_DIR_PREFIX + "input/joran/"
+            + "nothereBLAH.xml";
     context.getStatusManager().add(tsl);
     try {
       doTest(filename);
     } catch (Exception e) {
+      assertTrue(e.getMessage().startsWith("Could not open ["));
     }
     assertTrue(tsl.list.size() + " should be greater than or equal to 1",
-        tsl.list.size() >= 1);
+            tsl.list.size() >= 1);
     Status s0 = tsl.list.get(0);
-    assertTrue(s0.getMessage().startsWith("Could not open [" + filename + "]"));
-  }
+    assertTrue(s0.getMessage().startsWith("Could not open ["));
+ }
 
   @Test
   public void illFormedXML() {
     TrivialStatusListener tsl = new TrivialStatusListener();
-    String filename = "illformed.xml";
+    String filename = CoreTestConstants.TEST_DIR_PREFIX + "input/joran/" + "illformed.xml";
     context.getStatusManager().add(tsl);
     try {
       doTest(filename);
     } catch (Exception e) {
     }
-    assertEquals(2, tsl.list.size());
+    assertEquals(1, tsl.list.size());
     Status s0 = tsl.list.get(0);
     assertTrue(s0.getMessage().startsWith(
-        "Parsing fatal error on line 5 and column 3"));
-    Status s1 = tsl.list.get(1);
-    assertTrue(s1
-        .getMessage()
-        .startsWith(CoreConstants.XML_PARSING_ERROR));
+            "Parsing fatal error on line 5 and column 3"));
   }
 
   @Test
@@ -131,7 +130,7 @@ public class TrivialConfiguratorTest {
     URLConnection urlConnection2 = url2.openConnection();
     urlConnection2.setUseCaches(false);
     InputStream is = urlConnection2.getInputStream();
-    
+
     TrivialConfigurator tc = new TrivialConfigurator(rulesMap);
     tc.setContext(context);
     tc.doConfigure(url1);
@@ -149,16 +148,16 @@ public class TrivialConfiguratorTest {
     outputDir.mkdirs();
     int randomPart = RandomUtil.getPositiveInt();
     return new File(CoreTestConstants.OUTPUT_DIR_PREFIX + "foo-" + randomPart
-        + ".jar");
+            + ".jar");
   }
 
   private void fillInJarFile(File jarFile, String jarEntryName)
-      throws IOException {
+          throws IOException {
     fillInJarFile(jarFile, jarEntryName, null);
   }
 
   private void fillInJarFile(File jarFile, String jarEntryName1,
-      String jarEntryName2) throws IOException {
+                             String jarEntryName2) throws IOException {
     JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile));
     jos.putNextEntry(new ZipEntry(jarEntryName1));
     jos.write("<x/>".getBytes());

-----------------------------------------------------------------------

Summary of changes:
 .../classic/turbo/ReconfigureOnChangeFilter.java   |   79 +++++++++++++-----
 .../classic/turbo/ReconfigureOnChangeTest.java     |   88 ++++++++++++++++----
 .../java/ch/qos/logback/core/CoreConstants.java    |   12 ++--
 .../logback/core/joran/GenericConfigurator.java    |   46 +++++++---
 .../logback/core/joran/action/IncludeAction.java   |    2 +-
 .../logback/core/joran/conditional/IfAction.java   |    2 +-
 .../logback/core/joran/event/SaxEventRecorder.java |    9 +-
 .../ch/qos/logback/core/joran/spi/EventPlayer.java |   12 +++-
 .../ch/qos/logback/core/joran/spi/Interpreter.java |   18 ++---
 .../ch/qos/logback/core/status/StatusChecker.java  |    3 +-
 .../core/joran/TrivialConfiguratorTest.java        |   35 ++++----
 11 files changed, 211 insertions(+), 95 deletions(-)


hooks/post-receive
-- 
Logback: the generic, reliable, fast and flexible logging framework.


More information about the logback-dev mailing list