[logback-dev] svn commit: r2079 - in logback/trunk: logback-classic/src/main/java/ch/qos/logback/classic/hoard logback-classic/src/main/java/ch/qos/logback/classic/joran logback-classic/src/main/java/ch/qos/logback/classic/spi logback-classic/src/test/input/joran/hoard logback-classic/src/test/java/ch/qos/logback/classic/hoard logback-core/src/main/java/ch/qos/logback/core logback-core/src/main/java/ch/qos/logback/core/db logback-core/src/main/java/ch/qos/logback/core/joran logback-core/src/main/java/ch/qos/logback/core/joran/action logback-core/src/main/java/ch/qos/logback/core/joran/spi logback-core/src/main/java/ch/qos/logback/core/spi logback-core/src/main/java/ch/qos/logback/core/util logback-core/src/test/java/ch/qos/logback/core/joran/action

noreply.ceki at qos.ch noreply.ceki at qos.ch
Fri Dec 12 22:05:20 CET 2008


Author: ceki
Date: Fri Dec 12 22:05:20 2008
New Revision: 2079

Added:
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/AppenderFactory.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/HoardAction.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/HoardingAppender.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/HoardingJoranConfigurator.java
   logback/trunk/logback-classic/src/test/input/joran/hoard/
   logback/trunk/logback-classic/src/test/input/joran/hoard/hoard0.xml
   logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/hoard/
   logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/hoard/HoardingAppenderTest.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/PropertyContainer.java
Modified:
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/joran/JoranConfigurator.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggerContextAwareBase.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/Context.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/db/BindDataSourceToJNDIAction.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/GenericConfigurator.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/IncludeAction.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/EventPlayer.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/InterpretationContext.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/OptionHelper.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/action/PropertyActionTest.java

Log:

- Initial commit of HoardingAppender

HoardingAppender contains other appenders which it can build
dynamically depending on MDC values. The built appender is specified
as part of a configuration file. Here is an example.

<configuration debug="true">
  <appender name="HOARD"  class="ch.qos.logback.classic.hoard.HoardingAppender">
    <mdcKey>userid</mdcKey>
    <hoard>
      <!-- you can put any appender here -->
      <appender name="file-${userid}" class="ch.qos.logback.core.FileAppender">
        <File>${userid}.log</File>
        <Append>true</Append>
        <layout class="ch.qos.logback.classic.PatternLayout">
          <Pattern>%d [%thread] %level %logger{35} - %msg%n</Pattern>
        </layout>
      </appender>
    </hoard>
  </appender>
  <root level="DEBUG">
    <appender-ref ref="HOARD" />
  </root>
</configuration>

A new file appender will be built each according to the MDC value
associated with the key "userid" when a logging event occurs. The
above configuration file will ventilate logging into log files named
after the userid. 

- Added PropertyContainer interface
- Context interface now extends PropertyContainer
- InterpretationContext implements PropertyContainer
  It now has a field called propertiesMap which has precedence
  over values placed in the context
- InterpretationContext.getSubstitutionProperty was renamed as
  getProperty
- It is now possible to initialize a joran Interpreter with an initial
  (not empty) pattern

This is still very much ongoing work.
  

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/AppenderFactory.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/AppenderFactory.java	Fri Dec 12 22:05:20 2008
@@ -0,0 +1,49 @@
+package ch.qos.logback.classic.hoard;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.joran.event.SaxEvent;
+import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.util.StatusPrinter;
+
+public class AppenderFactory {
+
+  final List<SaxEvent> eventList;
+  Context context;
+  
+  AppenderFactory(Context context, List<SaxEvent> eventList) {
+    this.context = context;
+    this.eventList = new ArrayList<SaxEvent>(eventList);
+    removeHoardElement();
+
+  }
+
+  void removeHoardElement() {
+    eventList.remove(0);
+    eventList.remove(eventList.size() - 1);
+    System.out.println(eventList);
+  }
+
+  Appender<LoggingEvent> buildAppender(Context context, String mdcKey,
+      String mdcValue) throws JoranException {
+    //HoardingContext hoardingContext = new HoardingContext(context, mdcKey,
+    //    mdcValue);
+    HoardingJoranConfigurator hjc = new HoardingJoranConfigurator(mdcKey, mdcValue);
+    hjc.setContext(context);
+
+    hjc.doConfigure(eventList);
+
+    StatusPrinter.print(context);
+
+    return hjc.getAppender();
+  }
+
+  public List<SaxEvent> getEventList() {
+    return eventList;
+  }
+
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/HoardAction.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/HoardAction.java	Fri Dec 12 22:05:20 2008
@@ -0,0 +1,47 @@
+package ch.qos.logback.classic.hoard;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xml.sax.Attributes;
+
+import ch.qos.logback.core.joran.action.Action;
+import ch.qos.logback.core.joran.event.InPlayListener;
+import ch.qos.logback.core.joran.event.SaxEvent;
+import ch.qos.logback.core.joran.spi.ActionException;
+import ch.qos.logback.core.joran.spi.InterpretationContext;
+
+public class HoardAction  extends Action implements InPlayListener {
+  List<SaxEvent> seList;
+  
+  @Override
+  public void begin(InterpretationContext ec, String name, Attributes attributes)
+      throws ActionException {
+    seList = new ArrayList<SaxEvent>();
+    ec.addInPlayListener(this);
+  }
+
+  @Override
+  public void end(InterpretationContext ec, String name) throws ActionException {
+    ec.removeInPlayListener(this);
+    Object o = ec.peekObject();
+    if (o instanceof HoardingAppender) {
+      HoardingAppender ha = (HoardingAppender) o; 
+      AppenderFactory appenderFactory = new AppenderFactory(context, seList);
+      ha.setAppenderFactory(appenderFactory);
+    }
+  }
+
+  public void inPlay(SaxEvent event) {
+    seList.add(event);
+    System.out.println(event);
+  }
+
+  public List<SaxEvent> getSeList() {
+    return seList;
+  }
+
+    
+
+
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/HoardingAppender.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/HoardingAppender.java	Fri Dec 12 22:05:20 2008
@@ -0,0 +1,59 @@
+package ch.qos.logback.classic.hoard;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.slf4j.MDC;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.UnsynchronizedAppenderBase;
+import ch.qos.logback.core.joran.spi.JoranException;
+
+public class HoardingAppender extends UnsynchronizedAppenderBase<LoggingEvent> {
+
+  static String DEFAULT = "default";
+
+  Map<String, Appender<LoggingEvent>> appenderMap = new Hashtable<String, Appender<LoggingEvent>>();
+
+  String mdcKey;
+
+  AppenderFactory appenderFactory;
+
+  void setAppenderFactory(AppenderFactory appenderFactory) {
+    this.appenderFactory = appenderFactory;
+  }
+
+  
+  
+  @Override
+  protected void append(LoggingEvent loggingEvent) {
+    String mdcValue = MDC.get(mdcKey);
+
+    if (mdcValue == null) {
+      mdcValue = DEFAULT;
+    }
+
+    Appender<LoggingEvent> appender = appenderMap.get(mdcValue);
+
+    if (appender == null) {
+      try {
+        appender = appenderFactory.buildAppender(context, mdcKey, mdcValue);
+      } catch (JoranException e) {
+        addError("Failed to build appender for " + mdcKey + "=" + mdcValue, e);
+        return;
+      }
+    }
+    appender.doAppend(loggingEvent);
+  }
+
+  public String getMdcKey() {
+    return mdcKey;
+  }
+
+  public void setMdcKey(String mdcKey) {
+    this.mdcKey = mdcKey;
+  }
+  
+  
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/HoardingJoranConfigurator.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/hoard/HoardingJoranConfigurator.java	Fri Dec 12 22:05:20 2008
@@ -0,0 +1,64 @@
+package ch.qos.logback.classic.hoard;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.joran.GenericConfigurator;
+import ch.qos.logback.core.joran.action.ActionConst;
+import ch.qos.logback.core.joran.action.AppenderAction;
+import ch.qos.logback.core.joran.action.NestedBasicPropertyIA;
+import ch.qos.logback.core.joran.action.NestedComplexPropertyIA;
+import ch.qos.logback.core.joran.spi.Interpreter;
+import ch.qos.logback.core.joran.spi.Pattern;
+import ch.qos.logback.core.joran.spi.RuleStore;
+
+public class HoardingJoranConfigurator  extends GenericConfigurator {
+
+  String key;
+  String value;
+  
+  HoardingJoranConfigurator(String key, String value) {
+    this.key = key;
+    this.value = value;
+  }
+  @Override
+  protected Pattern initialPattern() {
+    return new Pattern("configuration");
+  }
+  
+  @Override
+  protected void addImplicitRules(Interpreter interpreter) {
+    NestedComplexPropertyIA nestedComplexIA = new NestedComplexPropertyIA();
+    nestedComplexIA.setContext(context);
+    interpreter.addImplicitAction(nestedComplexIA);
+    
+    NestedBasicPropertyIA nestedSimpleIA = new NestedBasicPropertyIA();
+    nestedSimpleIA.setContext(context);
+    interpreter.addImplicitAction(nestedSimpleIA);
+  }
+
+  @Override
+  protected void addInstanceRules(RuleStore rs) {
+    rs.addRule(new Pattern("configuration/appender"), new AppenderAction());
+  }
+
+  @Override
+  protected void buildInterpreter() {
+    super.buildInterpreter();
+    Map<String, Object> omap = interpreter.getInterpretationContext().getObjectMap();
+    omap.put(ActionConst.APPENDER_BAG, new HashMap());
+    omap.put(ActionConst.FILTER_CHAIN_BAG, new HashMap());
+    Map<String, String> propertiesMap = new HashMap<String, String>();
+    propertiesMap.put(key, value);
+    interpreter.setInterpretationContextPropertiesMap(propertiesMap);
+  }
+
+  public Appender getAppender() {
+    Map<String, Object> omap = interpreter.getInterpretationContext().getObjectMap();
+    HashMap map = (HashMap) omap.get(ActionConst.APPENDER_BAG);
+    Collection values = map.values();
+    return (Appender) values.iterator().next();
+  }
+}

Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/joran/JoranConfigurator.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/joran/JoranConfigurator.java	(original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/joran/JoranConfigurator.java	Fri Dec 12 22:05:20 2008
@@ -10,6 +10,7 @@
 
 package ch.qos.logback.classic.joran;
 
+import ch.qos.logback.classic.hoard.HoardAction;
 import ch.qos.logback.classic.joran.action.ConfigurationAction;
 import ch.qos.logback.classic.joran.action.ConsolePluginAction;
 import ch.qos.logback.classic.joran.action.ContextNameAction;
@@ -25,6 +26,7 @@
 import ch.qos.logback.core.joran.action.AppenderRefAction;
 import ch.qos.logback.core.joran.action.IncludeAction;
 import ch.qos.logback.core.joran.action.MatcherAction;
+import ch.qos.logback.core.joran.action.NOPAction;
 import ch.qos.logback.core.joran.spi.Pattern;
 import ch.qos.logback.core.joran.spi.RuleStore;
 
@@ -51,6 +53,10 @@
     rs.addRule(new Pattern("*/evaluator/matcher"),
         new MatcherAction());
 
+    rs.addRule(new Pattern("configuration/appender/hoard"), new HoardAction());
+    rs.addRule(new Pattern("configuration/appender/hoard/*"), new NOPAction());
+    
+    
     rs.addRule(new Pattern("configuration/logger"), new LoggerAction());
     rs.addRule(new Pattern("configuration/logger/level"), new LevelAction());
 

Modified: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggerContextAwareBase.java
==============================================================================
--- logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggerContextAwareBase.java	(original)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/spi/LoggerContextAwareBase.java	Fri Dec 12 22:05:20 2008
@@ -1,11 +1,11 @@
 /**
- * LOGBack: the reliable, fast and flexible logging library for Java.
- *
- * Copyright (C) 1999-2006, QOS.ch
- *
- * This library is free software, you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation.
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ * 
+ * Copyright (C) 2000-2008, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
  */
 package ch.qos.logback.classic.spi;
 

Added: logback/trunk/logback-classic/src/test/input/joran/hoard/hoard0.xml
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/input/joran/hoard/hoard0.xml	Fri Dec 12 22:05:20 2008
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE configuration>
+
+<configuration debug="true">
+
+  <appender name="HOARD"
+    class="ch.qos.logback.classic.hoard.HoardingAppender">
+
+    <mdcKey>userid</mdcKey>
+    
+
+    <hoard>
+      <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+        <File>${userid}.log</File>
+        <Append>true</Append>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+          <Pattern>%d [%thread] %level %logger{35} - %msg%n</Pattern>
+        </layout>
+      </appender>
+    </hoard>
+
+  </appender>
+
+  <root level="DEBUG">
+    <appender-ref ref="HOARD" />
+  </root>
+
+</configuration>

Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/hoard/HoardingAppenderTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/hoard/HoardingAppenderTest.java	Fri Dec 12 22:05:20 2008
@@ -0,0 +1,44 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ * 
+ * Copyright (C) 2000-2008, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.classic.hoard;
+
+import org.junit.Test;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.classic.util.TeztConstants;
+import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.util.StatusPrinter;
+
+public class HoardingAppenderTest {
+
+  static String PREFIX = TeztConstants.TEST_DIR_PREFIX + "input/joran/hoard/";
+  		
+  LoggerContext loggerContext = new LoggerContext();
+  Logger logger = loggerContext.getLogger(this.getClass().getName());
+  Logger root = loggerContext.getLogger(LoggerContext.ROOT_NAME);
+
+  void configure(String file) throws JoranException {
+    JoranConfigurator jc = new JoranConfigurator();
+    jc.setContext(loggerContext);
+    jc.doConfigure(file);
+  }
+
+
+  @Test
+  public void testLevel() throws JoranException {
+    configure(PREFIX + "hoard0.xml");
+    logger.debug("ss");
+    //StatusPrinter.print(loggerContext);
+    
+  }
+
+}

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/Context.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/Context.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/Context.java	Fri Dec 12 22:05:20 2008
@@ -9,10 +9,11 @@
  */
 package ch.qos.logback.core;
 
+import ch.qos.logback.core.spi.PropertyContainer;
 import ch.qos.logback.core.status.StatusManager;
 
 
-public interface Context {
+public interface Context extends PropertyContainer {
 
 	
   StatusManager getStatusManager();

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/db/BindDataSourceToJNDIAction.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/db/BindDataSourceToJNDIAction.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/db/BindDataSourceToJNDIAction.java	Fri Dec 12 22:05:20 2008
@@ -40,7 +40,7 @@
    */
   public void begin(
       InterpretationContext ec, String localName, Attributes attributes) {
-    String dsClassName = ec.getSubstitutionProperty(DATA_SOURCE_CLASS);
+    String dsClassName = ec.getProperty(DATA_SOURCE_CLASS);
 
     if (OptionHelper.isEmpty(dsClassName)) {
       addWarn("dsClassName is a required parameter");
@@ -49,9 +49,9 @@
       return;
     }
 
-    String urlStr = ec.getSubstitutionProperty(URL);
-    String userStr = ec.getSubstitutionProperty(USER);
-    String passwordStr = ec.getSubstitutionProperty(PASSWORD);
+    String urlStr = ec.getProperty(URL);
+    String userStr = ec.getProperty(USER);
+    String passwordStr = ec.getProperty(PASSWORD);
 
     try {
       DataSource ds =

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/GenericConfigurator.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/GenericConfigurator.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/GenericConfigurator.java	Fri Dec 12 22:05:20 2008
@@ -24,6 +24,7 @@
 import ch.qos.logback.core.joran.spi.InterpretationContext;
 import ch.qos.logback.core.joran.spi.Interpreter;
 import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.joran.spi.Pattern;
 import ch.qos.logback.core.joran.spi.RuleStore;
 import ch.qos.logback.core.joran.spi.SimpleRuleStore;
 import ch.qos.logback.core.spi.ContextAwareBase;
@@ -78,10 +79,14 @@
 
   abstract protected void addImplicitRules(Interpreter interpreter);
 
+  protected Pattern initialPattern() {
+    return new Pattern();
+  }
+  
   protected void buildInterpreter() {
     RuleStore rs = new SimpleRuleStore(context);
     addInstanceRules(rs);
-    this.interpreter = new Interpreter(context, rs);
+    this.interpreter = new Interpreter(context, rs, initialPattern());
     InterpretationContext ec = interpreter.getInterpretationContext();
     ec.setContext(context);
     addImplicitRules(interpreter);

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/IncludeAction.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/IncludeAction.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/IncludeAction.java	Fri Dec 12 22:05:20 2008
@@ -64,7 +64,7 @@
     // remove the <included> tag from the beginning and </included> from the end
     trimHeadAndTail(recorder);
     
-    ec.getJoranInterpreter().addEvents(recorder.saxEventList);
+    ec.getJoranInterpreter().addEventsDynamically(recorder.saxEventList);
   }
 
   private boolean checkAttributes(Attributes attributes) {

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/EventPlayer.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/EventPlayer.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/EventPlayer.java	Fri Dec 12 22:05:20 2008
@@ -51,7 +51,7 @@
     }
   }
   
-  public void addEvents(List<SaxEvent> eventList) {
+  public void addEventsDynamically(List<SaxEvent> eventList) {
     this.eventList.addAll(currentIndex+2, eventList);
   }
 }

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/InterpretationContext.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/InterpretationContext.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/InterpretationContext.java	Fri Dec 12 22:05:20 2008
@@ -24,30 +24,38 @@
 import ch.qos.logback.core.joran.event.InPlayListener;
 import ch.qos.logback.core.joran.event.SaxEvent;
 import ch.qos.logback.core.spi.ContextAwareBase;
+import ch.qos.logback.core.spi.PropertyContainer;
 import ch.qos.logback.core.util.OptionHelper;
 
-
 /**
  * 
  * An InterpretationContext contains the contextual state of a Joran parsing
- * session. {@link Action} objects depend on this context to exchange 
- * and store information.
+ * session. {@link Action} objects depend on this context to exchange and store
+ * information.
  * 
  * @author Ceki G&uuml;lc&uuml;
  */
-public class InterpretationContext extends ContextAwareBase {
+public class InterpretationContext extends ContextAwareBase implements
+    PropertyContainer {
   Stack<Object> objectStack;
   Map<String, Object> objectMap;
+  Map<String, String> propertiesMap;
+
   Interpreter joranInterpreter;
   final List<InPlayListener> listenerList = new ArrayList<InPlayListener>();
-  
+
   public InterpretationContext(Context context, Interpreter joranInterpreter) {
     this.context = context;
     this.joranInterpreter = joranInterpreter;
-    objectStack = new Stack<Object> ();
+    objectStack = new Stack<Object>();
     objectMap = new HashMap<String, Object>(5);
+    propertiesMap = new HashMap<String, String>(5);
   }
-  
+
+  void setPropertiesMap(Map<String, String> propertiesMap) {
+    this.propertiesMap = propertiesMap;
+  }
+
   String updateLocationInfo(String msg) {
     Locator locator = joranInterpreter.getLocator();
 
@@ -57,7 +65,7 @@
       return msg;
     }
   }
-  
+
   public Locator getLocator() {
     return joranInterpreter.getLocator();
   }
@@ -135,31 +143,40 @@
     }
   }
 
-  public String getSubstitutionProperty(String key) {
-    return context.getProperty(key);
+  /**
+   * If a key is found in propertiesMap then return it. Otherwise, delegate to
+   * the context.
+   */
+  public String getProperty(String key) {
+    String v = propertiesMap.get(key);
+    if (v != null) {
+      return v;
+    } else {
+      return context.getProperty(key);
+    }
   }
 
   public String subst(String value) {
     if (value == null) {
       return null;
     }
-    return OptionHelper.substVars(value, context);
+    return OptionHelper.substVars(value, this);
   }
-  
+
   public void addInPlayListener(InPlayListener ipl) {
-    if(listenerList.contains(ipl)) {
-      addWarn("InPlayListener "+ipl+" has been already registered");
+    if (listenerList.contains(ipl)) {
+      addWarn("InPlayListener " + ipl + " has been already registered");
     } else {
       listenerList.add(ipl);
     }
   }
-  
+
   public boolean removeInPlayListener(InPlayListener ipl) {
     return listenerList.remove(ipl);
   }
-  
+
   void fireInPlay(SaxEvent event) {
-    for(InPlayListener ipl: listenerList) {
+    for (InPlayListener ipl : listenerList) {
       ipl.inPlay(event);
     }
   }

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Interpreter.java	Fri Dec 12 22:05:20 2008
@@ -12,6 +12,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Stack;
 import java.util.Vector;
 
@@ -64,7 +65,7 @@
   private static List EMPTY_LIST = new Vector(0);
 
   final private RuleStore ruleStore;
-  final private InterpretationContext ec;
+  final private InterpretationContext interpretationContext;
   final private ArrayList<ImplicitAction> implicitActions;
   final private CAI_WithLocatorSupport cai;
   Pattern pattern;
@@ -87,18 +88,20 @@
    */
   Pattern skip = null;
 
-  public Interpreter(Context context, RuleStore rs) {
+  public Interpreter(Context context, RuleStore rs, Pattern initialPattern) {
     this.cai = new CAI_WithLocatorSupport(this);
     this.cai.setContext(context);
     ruleStore = rs;
-    ec = new InterpretationContext(context, this);
+    interpretationContext = new InterpretationContext(context, this);
     implicitActions = new ArrayList<ImplicitAction>(3);
-    pattern = new Pattern();
+    this.pattern = initialPattern;
     actionListStack = new Stack<List>();
     player = new EventPlayer(this);
   }
-
   
+  public void setInterpretationContextPropertiesMap(Map<String, String> propertiesMap) {
+    interpretationContext.setPropertiesMap(propertiesMap);
+  }
   /**
    * @deprecated replaced by {@link #getInterpretationContext()}
    */
@@ -107,7 +110,7 @@
   }
   
   public InterpretationContext getInterpretationContext() {
-    return ec;
+    return interpretationContext;
   }
 
   public void startDocument() {
@@ -241,7 +244,7 @@
 
     // logger.debug("set of applicable patterns: " + applicableActionList);
     if (applicableActionList == null) {
-      applicableActionList = lookupImplicitAction(pattern, attributes, ec);
+      applicableActionList = lookupImplicitAction(pattern, attributes, interpretationContext);
     }
 
     return applicableActionList;
@@ -259,7 +262,7 @@
       // now let us invoke the action. We catch and report any eventual
       // exceptions
       try {
-        action.begin(ec, tagName, atts);
+        action.begin(interpretationContext, tagName, atts);
       } catch (ActionException e) {
         skip = (Pattern) pattern.clone();
         cai.addError("ActionException in Action for tag [" + tagName + "]", e);
@@ -279,7 +282,7 @@
     while (i.hasNext()) {
       Action action = (Action) i.next();
       try {
-        action.body(ec, body);
+        action.body(interpretationContext, body);
       } catch (ActionException ae) {
         cai
             .addError("Exception in end() methd for action [" + action + "]",
@@ -301,7 +304,7 @@
       // now let us invoke the end method of the action. We catch and report
       // any eventual exceptions
       try {
-        action.end(ec, tagName);
+        action.end(interpretationContext, tagName);
       } catch (ActionException ae) {
         // at this point endAction, there is no point in skipping children as
         // they have been already processed
@@ -321,9 +324,9 @@
     player.play(eventList);
   }
 
-  public void addEvents(List<SaxEvent> eventList) {
+  public void addEventsDynamically(List<SaxEvent> eventList) {
     if (player != null) {
-      player.addEvents(eventList);
+      player.addEventsDynamically(eventList);
     }
   }
 }

Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/PropertyContainer.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/spi/PropertyContainer.java	Fri Dec 12 22:05:20 2008
@@ -0,0 +1,6 @@
+package ch.qos.logback.core.spi;
+
+public interface PropertyContainer {
+
+  public String getProperty(String key);
+}

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/OptionHelper.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/OptionHelper.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/OptionHelper.java	Fri Dec 12 22:05:20 2008
@@ -14,6 +14,7 @@
 
 import ch.qos.logback.core.Context;
 import ch.qos.logback.core.CoreConstants;
+import ch.qos.logback.core.spi.PropertyContainer;
 
 /**
  * @author Ceki Gulcu
@@ -125,7 +126,7 @@
    * @throws IllegalArgumentException
    *           if <code>val</code> is malformed.
    */
-  public static String substVars(String val, Context context) {
+  public static String substVars(String val, PropertyContainer pc) {
 
     StringBuffer sbuf = new StringBuffer();
 
@@ -167,7 +168,7 @@
           String replacement = null;
 
           // first try the props passed as parameter
-          replacement = context.getProperty(key);
+          replacement = pc.getProperty(key);
 
           // then try in System properties
           if (replacement == null) {
@@ -186,7 +187,7 @@
             // where the properties are
             // x1=p1
             // x2=${x1}
-            String recursiveReplacement = substVars(replacement, context);
+            String recursiveReplacement = substVars(replacement, pc);
             sbuf.append(recursiveReplacement);
           } else {
             // if we could not find a replacement, then signal the error

Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/action/PropertyActionTest.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/action/PropertyActionTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/action/PropertyActionTest.java	Fri Dec 12 22:05:20 2008
@@ -43,7 +43,7 @@
     atts.setValue("name", "v1");
     atts.setValue("value", "work");
     spAction.begin(ec, null, atts);
-    assertEquals("work", ec.getSubstitutionProperty("v1"));
+    assertEquals("work", ec.getProperty("v1"));
   }
   
   @Test
@@ -52,7 +52,7 @@
     atts.setValue("name", "v1");
     atts.setValue("value", "${w}k");
     spAction.begin(ec, null, atts);
-    assertEquals("work", ec.getSubstitutionProperty("v1"));
+    assertEquals("work", ec.getProperty("v1"));
   }
   
   @Test
@@ -93,24 +93,24 @@
     context.putProperty("STEM", Constants.TEST_DIR_PREFIX + "input/joran");
     atts.setValue("file", "${STEM}/propertyActionTest.properties");
     spAction.begin(ec, null, atts);
-    assertEquals("tata", ec.getSubstitutionProperty("v1"));
-    assertEquals("toto", ec.getSubstitutionProperty("v2"));
+    assertEquals("tata", ec.getProperty("v1"));
+    assertEquals("toto", ec.getProperty("v2"));
   }
 
   @Test
   public void testLoadFile() {
     atts.setValue("file", Constants.TEST_DIR_PREFIX + "input/joran/propertyActionTest.properties");
     spAction.begin(ec, null, atts);
-    assertEquals("tata", ec.getSubstitutionProperty("v1"));
-    assertEquals("toto", ec.getSubstitutionProperty("v2"));
+    assertEquals("tata", ec.getProperty("v1"));
+    assertEquals("toto", ec.getProperty("v2"));
   }
 
   @Test
   public void testLoadResource() {
     atts.setValue("resource", "asResource/joran/propertyActionTest.properties");
     spAction.begin(ec, null, atts);
-    assertEquals("tata", ec.getSubstitutionProperty("r1"));
-    assertEquals("toto", ec.getSubstitutionProperty("r2"));
+    assertEquals("tata", ec.getProperty("r1"));
+    assertEquals("toto", ec.getProperty("r2"));
   }
   
   @Test
@@ -118,8 +118,8 @@
     context.putProperty("STEM", "asResource/joran");
     atts.setValue("resource", "${STEM}/propertyActionTest.properties");
     spAction.begin(ec, null, atts);
-    assertEquals("tata", ec.getSubstitutionProperty("r1"));
-    assertEquals("toto", ec.getSubstitutionProperty("r2"));
+    assertEquals("tata", ec.getProperty("r1"));
+    assertEquals("toto", ec.getProperty("r2"));
   }
   
   @Test


More information about the logback-dev mailing list