[logback-dev] svn commit: r715 - in logback/trunk/logback-core/src: main/java/ch/qos/logback/core/joran main/java/ch/qos/logback/core/joran/action main/java/ch/qos/logback/core/joran/spi main/java/ch/qos/logback/core/util test/input/joran test/java/ch/qos/logback/core test/java/ch/qos/logback/core/joran test/java/ch/qos/logback/core/joran/event test/java/ch/qos/logback/core/joran/replay test/java/ch/qos/logback/core/joran/spi test/java/ch/qos/logback/core/pattern

noreply.ceki at qos.ch noreply.ceki at qos.ch
Thu Oct 19 15:45:51 CEST 2006


Author: ceki
Date: Thu Oct 19 15:45:50 2006
New Revision: 715

Added:
   logback/trunk/logback-core/src/test/input/joran/fruit1.xml
   logback/trunk/logback-core/src/test/input/joran/fruit2.xml
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/Fruit.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitAction.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitConfigurationTest.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitConfigurator.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitContext.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitFactory.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitFactoryAction.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitShell.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitShellAction.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/PackageTest.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/SimpleConfigurator.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/WeightytFruit.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/pattern/PackageTest.java
      - copied, changed from r714, /logback/trunk/logback-core/src/test/java/ch/qos/logback/core/pattern/AllTest.java
Removed:
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/event/FruitConfigAction.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/pattern/AllTest.java
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/action/NestedSimplePropertyIA.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Pattern.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SimpleRuleStore.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/PropertySetter.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/AllTest.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/PackageTest.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/event/InPlayFireTest.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/PatternTest.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/SimpleStoreTest.java

Log:

- Added suffix pattern matching to SimpleRuleStore. We can now do pattern matching 
  for a/*.
- Tested Joran's newly introduced reconfigure capability.


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	Thu Oct 19 15:45:50 2006
@@ -30,7 +30,7 @@
 
 public abstract class GenericConfigurator extends ContextAwareBase {
 
-  Interpreter interpreter;
+  protected Interpreter interpreter;
 
   final public void doConfigure(URL url) throws JoranException {
     try {
@@ -98,7 +98,7 @@
     player.play(recorder.saxEventList);
   }
 
-  final public void doConfigure(final List<SaxEvent> eventList)
+  public void doConfigure(final List<SaxEvent> eventList)
       throws JoranException {
     buildInterpreter();
     EventPlayer player = new EventPlayer(interpreter);

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedSimplePropertyIA.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedSimplePropertyIA.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedSimplePropertyIA.java	Thu Oct 19 15:45:50 2006
@@ -60,7 +60,7 @@
       ImplicitActionData ad = new ImplicitActionData(parentBean, containmentType);
       ad.propertyName = nestedElementTagName;
       actionDataStack.push(ad);
-
+      // System.out.println("NestedSimplePropertyIA deemed applicable for " +pattern);
       return true;
     default:
       addError("PropertySetter.canContainComponent returned " + containmentType);

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Pattern.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Pattern.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/Pattern.java	Thu Oct 19 15:45:50 2006
@@ -98,7 +98,7 @@
    * with the pattern p passed as parameter. By "tail" components we mean the
    * components at the end of the pattern.
    */
-  public int tailMatch(Pattern p) {
+  public int getTailMatchLength(Pattern p) {
     if (p == null) {
       return 0;
     }
@@ -129,6 +129,43 @@
     return match;
   }
 
+  /**
+   * Returns the number of "prefix" components that this pattern has in common
+   * with the pattern p passed as parameter. By "prefix" components we mean the
+   * components at the beginning of the pattern.
+   */
+  public int getPrefixMatchLength(Pattern p) {
+    if (p == null) {
+      return 0;
+    }
+
+    int lSize = this.components.size();
+    int rSize = p.components.size();
+
+    // no match possible for empty sets
+    if ((lSize == 0) || (rSize == 0)) {
+      return 0;
+    }
+
+    int minLen = (lSize <= rSize) ? lSize : rSize;
+    int match = 0;
+
+    for (int i = 0; i < minLen; i++) {
+      String l = (String) this.components.get(i);
+      String r = (String) p.components.get(i);
+
+      if (l.equals(r) || "*".equals(l) || "*".equals(r)) {
+        match++;
+      } else {
+        break;
+      }
+    }
+
+    return match;
+  }
+
+  
+  
   @Override
   public boolean equals(Object o) {
     //System.out.println("in equals:" +this+ " vs. " + o);

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SimpleRuleStore.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SimpleRuleStore.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/SimpleRuleStore.java	Thu Oct 19 15:45:50 2006
@@ -12,7 +12,6 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 
 import ch.qos.logback.core.Context;
@@ -67,38 +66,77 @@
       }
   }
 
-  public List matchActions(Pattern pattern) {
+  // exact match has highest priority
+  // if no exact match, check for tail match, i.e matches of type */x/y
+  // tail match for */x/y has higher priority than match for */x
+  // if no tail match, check for prefix match, i.e. matches for x/*
+  // match for x/y/* has higher priority than matches for x/*
+  
+  public List matchActions(Pattern currentPattern) {
     //System.out.println("pattern to search for:" + pattern + ", hashcode: " + pattern.hashCode());
     //System.out.println("rules:" + rules);
-    ArrayList a4p = (ArrayList) rules.get(pattern);
+    List actionList;
 
-    if (a4p != null) {
-      return a4p;
+    if ((actionList = rules.get(currentPattern)) != null) {
+      return actionList;
+    } else if ( (actionList = tailMatch(currentPattern)) != null){
+        return actionList;
+    } else if ((actionList = prefixMatch(currentPattern)) != null) {
+      return actionList;
     } else {
-      Iterator patternsIterator = rules.keySet().iterator();
-      int max = 0;
-      Pattern longestMatch = null;
-
-      while (patternsIterator.hasNext()) {
-        Pattern p = (Pattern) patternsIterator.next();
-
-        if ((p.size() > 1) && p.get(0).equals("*")) {
-          int r = pattern.tailMatch(p);
-
-          //System.out.println("tailMatch " +r);
-          if (r > max) {
-            //System.out.println("New longest match "+p);
-            max = r;
-            longestMatch = p;
-          }
+      return null;
+    }
+  }
+  
+  List tailMatch(Pattern currentPattern) {
+    int max = 0;
+    Pattern longestMatchingPattern = null;
+
+    for (Pattern p: rules.keySet()) {
+
+      if ((p.size() > 1) && p.get(0).equals("*")) {
+        int r = currentPattern.getTailMatchLength(p);
+
+        //System.out.println("tailMatch " +r);
+        if (r > max) {
+          //System.out.println("New longest tailMatch "+p);
+          max = r;
+          longestMatchingPattern = p;
         }
       }
+    }
 
-      if (longestMatch != null) {
-        return (ArrayList) rules.get(longestMatch);
-      } else {
-        return null;
+    if (longestMatchingPattern != null) {
+      return rules.get(longestMatchingPattern);
+    } else {
+      return null;
+    }
+  }
+  
+  List prefixMatch(Pattern currentPattern) {
+    int max = 0;
+    Pattern longestMatchingPattern = null;
+
+    for (Pattern p: rules.keySet()) {
+      String last = p.peekLast();
+      if("*".equals(last)) {
+        int r = currentPattern.getPrefixMatchLength(p);
+
+        //System.out.println("prefixMatch " +r);
+        if (r > max) {
+          //System.out.println("New longest prefixMatch "+p);
+          max = r;
+          longestMatchingPattern = p;
+        }
       }
     }
+
+    if (longestMatchingPattern != null) {
+      //System.out.println("prefixMatch will return" +rules.get(longestMatchingPattern));
+      return rules.get(longestMatchingPattern);
+    } else {
+      return null;
+    }
   }
+    
 }

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/PropertySetter.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/PropertySetter.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/PropertySetter.java	Thu Oct 19 15:45:50 2006
@@ -17,7 +17,6 @@
 // Contributors:  Georg Lundesgaard
 package ch.qos.logback.core.util;
 
-
 import java.beans.BeanInfo;
 import java.beans.IntrospectionException;
 import java.beans.Introspector;
@@ -31,46 +30,46 @@
 import ch.qos.logback.core.Appender;
 import ch.qos.logback.core.spi.ContextAwareBase;
 
-
-
 /**
- * General purpose Object property setter. Clients repeatedly invokes 
- * {@link #setProperty setProperty(name,value)} in order to invoke setters 
- * on the Object specified in the constructor. This class relies on the
- * JavaBeans {@link Introspector} to analyze the given Object Class using
- * reflection.
+ * General purpose Object property setter. Clients repeatedly invokes
+ * {@link #setProperty setProperty(name,value)} in order to invoke setters on
+ * the Object specified in the constructor. This class relies on the JavaBeans
+ * {@link Introspector} to analyze the given Object Class using reflection.
  * 
- * <p>Usage:
-   <pre>
-     PropertySetter ps = new PropertySetter(anObject);
-     ps.set("name", "Joe");
-     ps.set("age", "32");
-     ps.set("isMale", "true");
-   </pre>
-   
-   * will cause the invocations anObject.setName("Joe"), anObject.setAge(32), 
-   * and setMale(true) if such methods exist with those signatures. 
-   * Otherwise an {@link IntrospectionException} are thrown.
-
-   @author Anders Kristensen
-   @author Ceki Gulcu
+ * <p>
+ * Usage:
+ * 
+ * <pre>
+ * PropertySetter ps = new PropertySetter(anObject);
+ * ps.set(&quot;name&quot;, &quot;Joe&quot;);
+ * ps.set(&quot;age&quot;, &quot;32&quot;);
+ * ps.set(&quot;isMale&quot;, &quot;true&quot;);
+ * </pre>
+ * 
+ * will cause the invocations anObject.setName("Joe"), anObject.setAge(32), and
+ * setMale(true) if such methods exist with those signatures. Otherwise an
+ * {@link IntrospectionException} are thrown.
+ * 
+ * @author Anders Kristensen
+ * @author Ceki Gulcu
  */
 public class PropertySetter extends ContextAwareBase {
   public static final int NOT_FOUND = 0;
   public static final int AS_COMPONENT = 1;
   public static final int AS_PROPERTY = 2;
   public static final int AS_COLLECTION = 3;
-  
+
   protected Object obj;
   protected Class objClass;
   protected PropertyDescriptor[] propertyDescriptors;
   protected MethodDescriptor[] methodDescriptors;
 
   /**
-    Create a new PropertySetter for the specified Object. This is done
-    in preparation for invoking {@link #setProperty} one or more times.
-
-    @param obj  the object for which to set properties
+   * Create a new PropertySetter for the specified Object. This is done in
+   * preparation for invoking {@link #setProperty} one or more times.
+   * 
+   * @param obj
+   *          the object for which to set properties
    */
   public PropertySetter(Object obj) {
     this.obj = obj;
@@ -78,8 +77,8 @@
   }
 
   /**
-     Uses JavaBeans {@link Introspector} to computer setters of object to be
-     configured.
+   * Uses JavaBeans {@link Introspector} to computer setters of object to be
+   * configured.
    */
   protected void introspect() {
     try {
@@ -87,15 +86,14 @@
       propertyDescriptors = bi.getPropertyDescriptors();
       methodDescriptors = bi.getMethodDescriptors();
     } catch (IntrospectionException ex) {
-      addError(
-        "Failed to introspect " + obj + ": " + ex.getMessage());
+      addError("Failed to introspect " + obj + ": " + ex.getMessage());
       propertyDescriptors = new PropertyDescriptor[0];
       methodDescriptors = new MethodDescriptor[0];
     }
   }
 
   /**
-   * Set the properties for the object that match the <code>prefix</code> 
+   * Set the properties for the object that match the <code>prefix</code>
    * passed as parameter.
    */
   public void setProperties(Properties properties, String prefix) {
@@ -108,13 +106,13 @@
       if (key.startsWith(prefix)) {
         // ignore key if it contains dots after the prefix
         if (key.indexOf('.', len + 1) > 0) {
-          //System.err.println("----------Ignoring---["+key
-          //	     +"], prefix=["+prefix+"].");
+          // System.err.println("----------Ignoring---["+key
+          // +"], prefix=["+prefix+"].");
           continue;
         }
 
         String value = OptionHelper.findAndSubst(key, properties);
-        
+
         key = key.substring(len);
 
         if ("layout".equals(key) && obj instanceof Appender) {
@@ -127,19 +125,22 @@
   }
 
   /**
-     Set a property on this PropertySetter's Object. If successful, this
-     method will invoke a setter method on the underlying Object. The
-     setter is the one for the specified property name and the value is
-     determined partly from the setter argument type and partly from the
-     value specified in the call to this method.
-
-     <p>If the setter expects a String no conversion is necessary.
-     If it expects an int, then an attempt is made to convert 'value'
-     to an int using new Integer(value). If the setter expects a boolean,
-     the conversion is by new Boolean(value).
-
-     @param name    name of the property
-     @param value   String value of the property
+   * Set a property on this PropertySetter's Object. If successful, this method
+   * will invoke a setter method on the underlying Object. The setter is the one
+   * for the specified property name and the value is determined partly from the
+   * setter argument type and partly from the value specified in the call to
+   * this method.
+   * 
+   * <p>
+   * If the setter expects a String no conversion is necessary. If it expects an
+   * int, then an attempt is made to convert 'value' to an int using new
+   * Integer(value). If the setter expects a boolean, the conversion is by new
+   * Boolean(value).
+   * 
+   * @param name
+   *          name of the property
+   * @param value
+   *          String value of the property
    */
   public void setProperty(String name, String value) {
     if (value == null) {
@@ -150,35 +151,37 @@
 
     PropertyDescriptor prop = getPropertyDescriptor(name);
 
-    //LogLog.debug("---------Key: "+name+", type="+prop.getPropertyType());
+    // LogLog.debug("---------Key: "+name+", type="+prop.getPropertyType());
     if (prop == null) {
-      addWarn(
-        "No such property [" + name + "] in " + objClass.getName() + ".");
+      addWarn("No such property [" + name + "] in " + objClass.getName() + ".");
     } else {
       try {
         setProperty(prop, name, value);
       } catch (PropertySetterException ex) {
-        addWarn(
-          "Failed to set property [" + name + "] to value \"" + value + "\". ", ex);
+        addWarn("Failed to set property [" + name + "] to value \"" + value
+            + "\". ", ex);
       }
     }
   }
 
   /**
-      Set the named property given a {@link PropertyDescriptor}.
-
-      @param prop A PropertyDescriptor describing the characteristics
-      of the property to set.
-      @param name The named of the property to set.
-      @param value The value of the property.
+   * Set the named property given a {@link PropertyDescriptor}.
+   * 
+   * @param prop
+   *          A PropertyDescriptor describing the characteristics of the
+   *          property to set.
+   * @param name
+   *          The named of the property to set.
+   * @param value
+   *          The value of the property.
    */
   public void setProperty(PropertyDescriptor prop, String name, String value)
-    throws PropertySetterException {
+      throws PropertySetterException {
     Method setter = prop.getWriteMethod();
 
     if (setter == null) {
-      throw new PropertySetterException(
-        "No setter for property [" + name + "].");
+      throw new PropertySetterException("No setter for property [" + name
+          + "].");
     }
 
     Class[] paramTypes = setter.getParameterTypes();
@@ -192,16 +195,16 @@
     try {
       arg = convertArg(value, paramTypes[0]);
     } catch (Throwable t) {
-      throw new PropertySetterException(
-        "Conversion to type [" + paramTypes[0] + "] failed. ", t);
+      throw new PropertySetterException("Conversion to type [" + paramTypes[0]
+          + "] failed. ", t);
     }
 
     if (arg == null) {
-      throw new PropertySetterException(
-        "Conversion to type [" + paramTypes[0] + "] failed.");
+      throw new PropertySetterException("Conversion to type [" + paramTypes[0]
+          + "] failed.");
     }
 
-    //getLogger().debug("Setting property [{}] to [{}].", name, arg);
+    // getLogger().debug("Setting property [{}] to [{}].", name, arg);
 
     try {
       setter.invoke(obj, new Object[] { arg });
@@ -216,33 +219,32 @@
     Method method = getMethod("add" + cName);
 
     if (method != null) {
-      //getLogger().debug(
-      //  "Found add {} method in class {}", cName, objClass.getName());
+      // getLogger().debug(
+      // "Found add {} method in class {}", cName, objClass.getName());
 
       return AS_COLLECTION;
     }
 
     String dName = Introspector.decapitalize(name);
-    
+
     PropertyDescriptor propertyDescriptor = getPropertyDescriptor(dName);
 
     if (propertyDescriptor != null) {
       Method setterMethod = propertyDescriptor.getWriteMethod();
 
-      
       if (setterMethod != null) {
-        //getLogger().debug(
-        //  "Found setter method for property [{}] in class {}", name,
-        //  objClass.getName());
+        // getLogger().debug(
+        // "Found setter method for property [{}] in class {}", name,
+        // objClass.getName());
         Class[] classArray = setterMethod.getParameterTypes();
-        if(classArray.length != 1) {
+        if (classArray.length != 1) {
           return NOT_FOUND;
         } else {
           Class clazz = classArray[0];
           Package p = clazz.getPackage();
-          if(clazz.isPrimitive()) {
+          if (clazz.isPrimitive()) {
             return AS_PROPERTY;
-          } else if("java.lang".equals(p.getName())) {
+          } else if ("java.lang".equals(p.getName())) {
             return AS_PROPERTY;
           } else {
             return AS_COMPONENT;
@@ -255,8 +257,6 @@
     return NOT_FOUND;
   }
 
-  
-  
   public Class getObjClass() {
     return objClass;
   }
@@ -277,28 +277,24 @@
           try {
             method.invoke(this.obj, new Object[] { childComponent });
           } catch (Exception e) {
-            addError(
-              "Could not invoke method " + method.getName() + " in class "
-              + obj.getClass().getName() + " with parameter of type "
-              + ccc.getName(), e);
+            addError("Could not invoke method " + method.getName()
+                + " in class " + obj.getClass().getName()
+                + " with parameter of type " + ccc.getName(), e);
           }
         } else {
-          addError(
-            "A \"" + ccc.getName() + "\" object is not assignable to a \""
-            + params[0].getName() + "\" variable.");
-          addError(
-            "The class \"" + params[0].getName() + "\" was loaded by ");
-          addError(
-            "[" + params[0].getClassLoader() + "] whereas object of type ");
-          addError(
-            "\"" + ccc.getName() + "\" was loaded by [" + ccc.getClassLoader()
-            + "].");
+          addError("A \"" + ccc.getName()
+              + "\" object is not assignable to a \"" + params[0].getName()
+              + "\" variable.");
+          addError("The class \"" + params[0].getName() + "\" was loaded by ");
+          addError("[" + params[0].getClassLoader()
+              + "] whereas object of type ");
+          addError("\"" + ccc.getName() + "\" was loaded by ["
+              + ccc.getClassLoader() + "].");
         }
       }
     } else {
-      addError(
-        "Could not find method [" + "add" + name + "] in class ["
-        + objClass.getName() + "].");
+      addError("Could not find method [" + "add" + name + "] in class ["
+          + objClass.getName() + "].");
     }
   }
 
@@ -306,9 +302,8 @@
     PropertyDescriptor propertyDescriptor = getPropertyDescriptor(name);
 
     if (propertyDescriptor == null) {
-      addWarn(
-        "Could not find PropertyDescriptor for [" + name + "] in "
-        + objClass.getName());
+      addWarn("Could not find PropertyDescriptor for [" + name + "] in "
+          + objClass.getName());
 
       return;
     }
@@ -316,9 +311,8 @@
     Method setter = propertyDescriptor.getWriteMethod();
 
     if (setter == null) {
-      addWarn(
-        "Not setter method for property [" + name + "] in "
-        + obj.getClass().getName());
+      addWarn("Not setter method for property [" + name + "] in "
+          + obj.getClass().getName());
 
       return;
     }
@@ -326,21 +320,20 @@
     Class[] paramTypes = setter.getParameterTypes();
 
     if (paramTypes.length != 1) {
-      addError(
-        "Wrong number of parameters in setter method for property [" + name
-        + "] in " + obj.getClass().getName());
+      addError("Wrong number of parameters in setter method for property ["
+          + name + "] in " + obj.getClass().getName());
 
       return;
     }
 
     try {
       setter.invoke(obj, new Object[] { childComponent });
-      //getLogger().debug(
-      //  "Set child component of type [{}] for [{}].", objClass.getName(),
-      //  childComponent.getClass().getName());
+      // getLogger().debug(
+      // "Set child component of type [{}] for [{}].", objClass.getName(),
+      // childComponent.getClass().getName());
     } catch (Exception e) {
-      addError(
-        "Could not set component " + obj + " for parent component " + obj, e);
+      addError("Could not set component " + obj + " for parent component "
+          + obj, e);
     }
   }
 
@@ -349,9 +342,8 @@
   }
 
   /**
-     Convert <code>val</code> a String parameter to an object of a
-     given type.
-  */
+   * Convert <code>val</code> a String parameter to an object of a given type.
+   */
   protected Object convertArg(String val, Class type) {
     if (val == null) {
       return null;
@@ -365,6 +357,10 @@
       return new Integer(v);
     } else if (Long.TYPE.isAssignableFrom(type)) {
       return new Long(v);
+    } else if (Float.TYPE.isAssignableFrom(type)) {
+      return new Float(v);
+    } else if (Double.TYPE.isAssignableFrom(type)) {
+      return new Double(v);
     } else if (Boolean.TYPE.isAssignableFrom(type)) {
       if ("true".equalsIgnoreCase(v)) {
         return Boolean.TRUE;

Added: logback/trunk/logback-core/src/test/input/joran/fruit1.xml
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/input/joran/fruit1.xml	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<group>
+  <fruitShell name="fs0">
+    <fruit class="ch.qos.logback.core.joran.replay.Fruit">
+      <name>blue</name>
+    </fruit> 
+  </fruitShell>
+</group>
\ No newline at end of file

Added: logback/trunk/logback-core/src/test/input/joran/fruit2.xml
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/input/joran/fruit2.xml	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<group>
+  <fruitShell name="fs0">
+    <fruit class="ch.qos.logback.core.joran.replay.Fruit">
+       <name>blue</name>
+    </fruit> 
+  </fruitShell>
+
+  <fruitShell name="fs1">
+    <fruit class="ch.qos.logback.core.joran.replay.WeightytFruit">
+      <name>orange</name>
+      <weight>1.2</weight>
+    </fruit> 
+  </fruitShell>
+</group>
\ No newline at end of file

Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/AllTest.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/AllTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/AllTest.java	Thu Oct 19 15:45:50 2006
@@ -18,11 +18,11 @@
   public static Test suite() {
     TestSuite suite = new TestSuite();
     suite.addTest(ch.qos.logback.core.util.PackageTest.suite());
-    suite.addTest(ch.qos.logback.core.pattern.AllTest.suite());
+    suite.addTest(ch.qos.logback.core.pattern.PackageTest.suite());
+    suite.addTest(ch.qos.logback.core.joran.PackageTest.suite());
     suite.addTest(ch.qos.logback.core.appender.PackageTest.suite());
     suite.addTest(ch.qos.logback.core.rolling.helper.PackageTest.suite());
     suite.addTest(ch.qos.logback.core.rolling.PackageTest.suite());
-    suite.addTest(ch.qos.logback.core.joran.PackageTest.suite());
     return suite;
   }
 }

Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/PackageTest.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/PackageTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/PackageTest.java	Thu Oct 19 15:45:50 2006
@@ -21,6 +21,7 @@
     suite.addTestSuite(TrivialcConfiguratorTest.class);
     suite.addTest(ch.qos.logback.core.joran.event.PackageTest.suite());
     suite.addTest(ch.qos.logback.core.joran.spi.PackageTest.suite());
+    suite.addTest(ch.qos.logback.core.joran.replay.PackageTest.suite());
     return suite;
   }
 }

Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/event/InPlayFireTest.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/event/InPlayFireTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/event/InPlayFireTest.java	Thu Oct 19 15:45:50 2006
@@ -42,6 +42,27 @@
     assertTrue(listenAction.getSeList().get(1) instanceof StartEvent);
     assertTrue(listenAction.getSeList().get(2) instanceof BodyEvent);
     assertTrue(listenAction.getSeList().get(3) instanceof EndEvent);
+  }
+
+  public void testReplay() throws JoranException {
+    ListenAction listenAction = new ListenAction();
+    
+    rulesMap.put(new Pattern("fire"), listenAction);
+    TrivialConfigurator gc = new TrivialConfigurator(rulesMap);
+
+    gc.setContext(context);
+    gc.doConfigure(Constants.TEST_DIR_PREFIX + "input/joran/fire1.xml");
     
+    for(SaxEvent se: listenAction.getSeList()) {
+      System.out.println(se);
+    }
+    assertEquals(5, listenAction.getSeList().size());
+    assertTrue(listenAction.getSeList().get(0) instanceof StartEvent);
+    assertTrue(listenAction.getSeList().get(1) instanceof StartEvent);
+    assertTrue(listenAction.getSeList().get(2) instanceof BodyEvent);
+    assertTrue(listenAction.getSeList().get(3) instanceof EndEvent);
   }
+  
+  
+  
 }

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/Fruit.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/Fruit.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,28 @@
+package ch.qos.logback.core.joran.replay;
+
+public class Fruit {
+
+  String name;
+
+  public Fruit() {
+    System.out.println("Fruit constructor called");
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String toString() {
+    final String TAB = "    ";
+
+    StringBuilder retValue = new StringBuilder();
+
+    retValue.append("xFruit ( ").append("name = ").append(this.name).append(TAB).append(" )");
+
+    return retValue.toString();
+  }
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitAction.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitAction.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,81 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework for Java.
+ * 
+ * Copyright (C) 2000-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.
+ */
+
+package ch.qos.logback.core.joran.replay;
+
+import org.xml.sax.Attributes;
+
+import ch.qos.logback.core.joran.action.Action;
+import ch.qos.logback.core.joran.spi.ActionException;
+import ch.qos.logback.core.joran.spi.ExecutionContext;
+import ch.qos.logback.core.util.OptionHelper;
+
+public class FruitAction extends Action {
+
+  Fruit fruit;
+  private boolean inError = false;
+
+  @Override
+  public void begin(ExecutionContext ec, String name, Attributes attributes)
+      throws ActionException {
+    String className = attributes.getValue(CLASS_ATTRIBUTE);
+
+    // We are just beginning, reset variables
+    fruit = null;
+    inError = false;
+
+    try {
+      addInfo("About to instantiate fruit of type ["+className+"]");
+
+      fruit = (Fruit) OptionHelper.instantiateByClassName(
+          className, ch.qos.logback.core.joran.replay.Fruit.class);
+
+      String fruitName = attributes.getValue(NAME_ATTRIBUTE);
+
+      if (OptionHelper.isEmpty(fruitName)) {
+        addWarn(
+          "No fruit name given for fruit of type " + className + "].");
+      } else {
+        fruit.setName(fruitName);
+        addInfo("Fruit named as [" + fruitName + "]");
+      }
+
+      ec.pushObject(fruit);
+    } catch (Exception oops) {
+      inError = true;
+      addError(
+        "Could not create an Fruit of type ["+className+"].", oops);
+      throw new ActionException(ActionException.SKIP_CHILDREN, oops);
+    }
+    
+  }
+
+  @Override
+  public void end(ExecutionContext ec, String name) throws ActionException {
+    if (inError) {
+      return;
+    }
+
+    Object o = ec.peekObject();
+
+    if (o != fruit) {
+      addWarn(
+        "The object at the of the stack is not the fruit named ["
+        + fruit.getName() + "] pushed earlier.");
+    } else {
+      addInfo(
+        "Popping fruit named [" + fruit.getName()
+        + "] from the object stack");
+      ec.popObject();
+    }
+  }
+
+
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitConfigurationTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitConfigurationTest.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,79 @@
+package ch.qos.logback.core.joran.replay;
+
+import java.util.HashMap;
+import java.util.List;
+
+import junit.framework.TestCase;
+import ch.qos.logback.core.joran.NOPAction;
+import ch.qos.logback.core.joran.action.Action;
+import ch.qos.logback.core.joran.spi.Pattern;
+import ch.qos.logback.core.util.Constants;
+import ch.qos.logback.core.util.StatusPrinter;
+
+public class FruitConfigurationTest extends TestCase {
+
+  FruitContext fruitContext = new FruitContext();
+
+  public FruitConfigurationTest(String arg0) {
+    super(arg0);
+  }
+
+  protected void setUp() throws Exception {
+    super.setUp();
+  }
+
+  protected void tearDown() throws Exception {
+    super.tearDown();
+  }
+
+  public List<FruitShell> doFirstPart(String filename) throws Exception {
+
+    HashMap<Pattern, Action> rulesMap = new HashMap<Pattern, Action>();
+    rulesMap.put(new Pattern("group/fruitShell"), new FruitShellAction());
+    rulesMap.put(new Pattern("group/fruitShell/fruit"), new FruitFactoryAction());
+    rulesMap.put(new Pattern("group/fruitShell/fruit/*"), new NOPAction());
+    SimpleConfigurator gc = new SimpleConfigurator(rulesMap);
+
+    gc.setContext(fruitContext);
+
+    gc.doConfigure(Constants.TEST_DIR_PREFIX + "input/joran/" + filename);
+
+    StatusPrinter.print(fruitContext);
+    return fruitContext.getFruitShellList();
+
+  }
+
+  public void test1() throws Exception {
+    List<FruitShell> fsList = doFirstPart("fruit1.xml");
+    assertNotNull(fsList);
+    assertEquals(1, fsList.size());
+
+    FruitShell fs0 = fsList.get(0);
+    assertNotNull(fs0);
+    assertEquals("fs0", fs0.getName());
+    Fruit fruit0 = fs0.fruitFactory.buildFruit();
+    assertTrue(fruit0 instanceof Fruit);
+    assertEquals("blue", fruit0.getName());
+  }
+
+  public void test2() throws Exception {
+    List<FruitShell> fsList = doFirstPart("fruit2.xml");
+    assertNotNull(fsList);
+    assertEquals(2, fsList.size());
+
+    FruitShell fs0 = fsList.get(0);
+    assertNotNull(fs0);
+    assertEquals("fs0", fs0.getName());
+    Fruit fruit0 = fs0.fruitFactory.buildFruit();
+    assertTrue(fruit0 instanceof Fruit);
+    assertEquals("blue", fruit0.getName());
+    
+    FruitShell fs1 = fsList.get(1);
+    assertNotNull(fs1);
+    assertEquals("fs1", fs1.getName());
+    Fruit fruit1 = fs1.fruitFactory.buildFruit();
+    assertTrue(fruit1 instanceof WeightytFruit);
+    assertEquals("orange", fruit1.getName());
+    assertEquals(1.2, ((WeightytFruit) fruit1).getWeight());
+  }
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitConfigurator.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitConfigurator.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,58 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ * 
+ * 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.
+ */
+package ch.qos.logback.core.joran.replay;
+
+import java.util.List;
+
+import ch.qos.logback.core.joran.GenericConfigurator;
+import ch.qos.logback.core.joran.NOPAction;
+import ch.qos.logback.core.joran.action.NestedComponentIA;
+import ch.qos.logback.core.joran.action.NestedSimplePropertyIA;
+import ch.qos.logback.core.joran.event.SaxEvent;
+import ch.qos.logback.core.joran.spi.EventPlayer;
+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;
+
+public class FruitConfigurator extends GenericConfigurator {
+
+  FruitFactory ff;
+  public FruitConfigurator(FruitFactory ff) {
+    this.ff = ff;
+  }
+
+  @Override
+  final public void doConfigure(final List<SaxEvent> eventList)
+      throws JoranException {
+    buildInterpreter();
+    interpreter.getExecutionContext().pushObject(ff);
+    EventPlayer player = new EventPlayer(interpreter);
+    player.play(eventList);
+  }
+
+  @Override
+  protected void addImplicitRules(Interpreter interpreter) {
+    NestedComponentIA nestedIA = new NestedComponentIA();
+    nestedIA.setContext(context);
+    interpreter.addImplicitAction(nestedIA);
+    
+    NestedSimplePropertyIA nestedSimpleIA = new NestedSimplePropertyIA();
+    nestedIA.setContext(context);
+    interpreter.addImplicitAction(nestedSimpleIA);
+  }
+
+  
+  @Override
+  protected void addInstanceRules(RuleStore rs) {
+    rs.addRule(new Pattern("fruitShell"), new NOPAction());
+  }
+
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitContext.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitContext.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,23 @@
+package ch.qos.logback.core.joran.replay;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.qos.logback.core.ContextBase;
+
+public class FruitContext extends ContextBase {
+
+  List<FruitShell> fruitShellList = new ArrayList<FruitShell>();
+  
+  public void addFruitShell(FruitShell fs) {
+    fruitShellList.add(fs);
+  }
+
+  public List<FruitShell> getFruitShellList() {
+    return fruitShellList;
+  }
+
+  public void setFruitShellList(List<FruitShell> fruitShellList) {
+    this.fruitShellList = fruitShellList;
+  }
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitFactory.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitFactory.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,49 @@
+package ch.qos.logback.core.joran.replay;
+
+import java.util.List;
+
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.ContextBase;
+import ch.qos.logback.core.joran.event.SaxEvent;
+import ch.qos.logback.core.joran.spi.JoranException;
+
+public class FruitFactory {
+
+  List<SaxEvent> eventList;
+  Fruit fruit;
+  
+  public void setFruit(Fruit fruit) {
+    this.fruit = fruit;
+  }
+
+  public Fruit buildFruit() {
+    for (SaxEvent se : eventList) {
+      System.out.println(se);
+    }
+    Context context = new ContextBase();
+    this.fruit = null;
+    FruitConfigurator fruitConfigurator = new FruitConfigurator(this);
+    fruitConfigurator.setContext(context);
+    try {
+      fruitConfigurator.doConfigure(eventList);
+    } catch(JoranException je) {
+      je.printStackTrace();
+    }
+    return fruit;
+  }
+
+  public String toString() {
+    final String TAB = " ";
+
+    StringBuilder retValue = new StringBuilder();
+
+    retValue.append("FruitFactory ( ");
+    if (eventList != null && eventList.size() > 0) {
+      retValue.append("event1 = ").append(eventList.get(0)).append(TAB);
+    }
+    retValue.append(" )");
+
+    return retValue.toString();
+  }
+
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitFactoryAction.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitFactoryAction.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,55 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework for Java.
+ * 
+ * Copyright (C) 2000-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.
+ */
+
+package ch.qos.logback.core.joran.replay;
+
+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.ExecutionContext;
+
+public class FruitFactoryAction extends Action implements InPlayListener {
+
+  List<SaxEvent> seList = new ArrayList<SaxEvent>();
+
+  @Override
+  public void begin(ExecutionContext ec, String name, Attributes attributes)
+      throws ActionException {
+    ec.addInPlayListener(this);
+  }
+
+  @Override
+  public void end(ExecutionContext ec, String name) throws ActionException {
+    ec.removeInPlayListener(this);
+    
+    Object o = ec.peekObject();
+    if(o instanceof FruitShell) {
+      FruitShell fs = (FruitShell) o;
+      FruitFactory fruitFactory = new FruitFactory();
+      fruitFactory.eventList = new ArrayList<SaxEvent>(seList);
+      fs.setFruitFactory(fruitFactory);
+    }
+  }
+
+  public void inPlay(SaxEvent event) {
+    seList.add(event);
+  }
+
+  public List<SaxEvent> getSeList() {
+    return seList;
+  }
+
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitShell.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitShell.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,49 @@
+package ch.qos.logback.core.joran.replay;
+
+import ch.qos.logback.core.spi.ContextAwareBase;
+
+public class FruitShell extends ContextAwareBase {
+
+  FruitFactory fruitFactory;
+  String name;
+  
+  public void setFruitFactory(FruitFactory fruitFactory) {
+    this.fruitFactory = fruitFactory;
+  }
+
+  void testFruit() {
+    
+    Fruit fruit = fruitFactory.buildFruit();
+    System.out.println(fruit);
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  /**
+   * Constructs a <code>String</code> with all attributes
+   * in name = value format.
+   *
+   * @return a <code>String</code> representation 
+   * of this object.
+   */
+  public String toString()
+  {
+      final String TAB = " ";
+      
+      String retValue = "";
+      
+      retValue = "FruitShell ( "
+          + "fruitFactory = " + this.fruitFactory + TAB
+          + "name = " + this.name + TAB
+          + " )";
+      
+      return retValue;
+  }
+  
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitShellAction.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitShellAction.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,81 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework for Java.
+ * 
+ * Copyright (C) 2000-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.
+ */
+
+package ch.qos.logback.core.joran.replay;
+
+import org.xml.sax.Attributes;
+
+import ch.qos.logback.core.joran.action.Action;
+import ch.qos.logback.core.joran.spi.ActionException;
+import ch.qos.logback.core.joran.spi.ExecutionContext;
+import ch.qos.logback.core.util.OptionHelper;
+
+public class FruitShellAction extends Action {
+
+  FruitShell fruitShell;
+  private boolean inError = false;
+
+  
+  @Override
+  public void begin(ExecutionContext ec, String name, Attributes attributes)
+      throws ActionException {
+
+    // We are just beginning, reset variables
+    fruitShell = new FruitShell();
+    inError = false;
+    
+    try {
+
+
+      fruitShell.setContext(context);
+
+      String shellName = attributes.getValue(NAME_ATTRIBUTE);
+
+      if (OptionHelper.isEmpty(shellName)) {
+        addWarn(
+          "No appender name given for fruitShell].");
+      } else {
+        fruitShell.setName(shellName);
+        addInfo("FruitShell named as [" + shellName + "]");
+      }
+
+      ec.pushObject(fruitShell);
+    } catch (Exception oops) {
+      inError = true;
+      addError(
+        "Could not create an FruitShell", oops);
+      throw new ActionException(ActionException.SKIP_CHILDREN, oops);
+    }
+  }
+
+  @Override
+  public void end(ExecutionContext ec, String name) throws ActionException {
+    if (inError) {
+      return;
+    }
+
+    Object o = ec.peekObject();
+
+    if (o != fruitShell) {
+      addWarn(
+        "The object at the of the stack is not the fruitShell named ["
+        + fruitShell.getName() + "] pushed earlier.");
+    } else {
+      addInfo(
+        "Popping fruitSHell named [" + fruitShell.getName()
+        + "] from the object stack");
+      ec.popObject();
+      FruitContext fruitContext = (FruitContext) ec.getContext();
+      fruitContext.addFruitShell(fruitShell);
+    }
+  }
+
+  
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/PackageTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/PackageTest.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,23 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework for Java.
+ * 
+ * Copyright (C) 2000-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.
+ */
+package ch.qos.logback.core.joran.replay;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class PackageTest extends TestCase {
+
+  public static Test suite() {
+    TestSuite suite = new TestSuite();
+    suite.addTestSuite(FruitConfigurationTest.class);
+    return suite;
+  }
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/SimpleConfigurator.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/SimpleConfigurator.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,49 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ * 
+ * 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.
+ */
+package ch.qos.logback.core.joran.replay;
+
+import java.util.HashMap;
+
+import ch.qos.logback.core.joran.GenericConfigurator;
+import ch.qos.logback.core.joran.action.Action;
+import ch.qos.logback.core.joran.action.NestedComponentIA;
+import ch.qos.logback.core.joran.action.NestedSimplePropertyIA;
+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 SimpleConfigurator extends GenericConfigurator {
+
+  HashMap<Pattern, Action> rulesMap;
+  
+  public SimpleConfigurator(HashMap<Pattern, Action> rules) {
+    this.rulesMap = rules;
+  }
+  
+  @Override
+  protected void addImplicitRules(Interpreter interpreter) {
+    NestedComponentIA nestedIA = new NestedComponentIA();
+    nestedIA.setContext(context);
+    interpreter.addImplicitAction(nestedIA);
+
+    NestedSimplePropertyIA nestedSimpleIA = new NestedSimplePropertyIA();
+    nestedIA.setContext(context);
+    interpreter.addImplicitAction(nestedSimpleIA);
+  }
+
+  @Override
+  protected void addInstanceRules(RuleStore rs) {
+    for(Pattern pattern : rulesMap.keySet()) {
+      Action action = rulesMap.get(pattern);
+      rs.addRule(pattern, action);
+    }
+  }
+
+}

Added: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/WeightytFruit.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/WeightytFruit.java	Thu Oct 19 15:45:50 2006
@@ -0,0 +1,16 @@
+package ch.qos.logback.core.joran.replay;
+
+public class WeightytFruit extends Fruit {
+
+  double weight;
+
+  public double getWeight() {
+    return weight;
+  }
+
+  public void setWeight(double weight) {
+    this.weight = weight;
+  }
+  
+  
+}

Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/PatternTest.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/PatternTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/PatternTest.java	Thu Oct 19 15:45:50 2006
@@ -13,7 +13,6 @@
 import ch.qos.logback.core.joran.spi.Pattern;
 import junit.framework.TestCase;
 
- 
 /**
  * Test pattern manipulation code.
  * 
@@ -22,6 +21,7 @@
 public class PatternTest extends TestCase {
   /**
    * Constructor for PatternTestCase.
+   * 
    * @param name
    */
   public PatternTest(String name) {
@@ -85,6 +85,67 @@
     assertEquals("a", p.get(0));
     assertEquals("b", p.get(1));
   }
+
+  
+  // test tail matching
+  public void testTailMatch() {
+    {
+      Pattern p = new Pattern("/a/b");
+      Pattern rulePattern = new Pattern("*");
+      assertEquals(0, p.getTailMatchLength(rulePattern));
+    }
+
+    {
+      Pattern p = new Pattern("/a");
+      Pattern rulePattern = new Pattern("*/a");
+      assertEquals(1, p.getTailMatchLength(rulePattern));
+    }
+    
+    {
+      Pattern p = new Pattern("/a/b");
+      Pattern rulePattern = new Pattern("*/b");
+      assertEquals(1, p.getTailMatchLength(rulePattern));
+    }
+    
+    
+    {
+      Pattern p = new Pattern("/a/b/c");
+      Pattern rulePattern = new Pattern("*/b/c");
+      assertEquals(2, p.getTailMatchLength(rulePattern));
+    }
+  }
   
+  // test prefix matching
+  public void testPrefixMatch() {
+    {
+      Pattern p = new Pattern("/a/b");
+      Pattern rulePattern = new Pattern("/x/*");
+      assertEquals(0, p.getPrefixMatchLength(rulePattern));
+    }
+
+    {
+      Pattern p = new Pattern("/a");
+      Pattern rulePattern = new Pattern("/x/*");
+      assertEquals(0, p.getPrefixMatchLength(rulePattern));
+    }
+
+    {
+      Pattern p = new Pattern("/a/b");
+      Pattern rulePattern = new Pattern("/a/*");
+      assertEquals(2, p.getPrefixMatchLength(rulePattern));
+    }
+    
+    {
+      Pattern p = new Pattern("/a/b");
+      Pattern rulePattern = new Pattern("/a/b/*");
+      assertEquals(2, p.getPrefixMatchLength(rulePattern));
+    }
+    
+    {
+      Pattern p = new Pattern("/a/b");
+      Pattern rulePattern = new Pattern("/*");
+      assertEquals(1, p.getPrefixMatchLength(rulePattern));
+    }
+  }
 
 }

Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/SimpleStoreTest.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/SimpleStoreTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/SimpleStoreTest.java	Thu Oct 19 15:45:50 2006
@@ -10,22 +10,14 @@
 
 package ch.qos.logback.core.joran.spi;
 
+import java.util.List;
+
 import junit.framework.TestCase;
 
-import org.w3c.dom.Document;
 import org.xml.sax.Attributes;
 
 import ch.qos.logback.core.ContextBase;
 import ch.qos.logback.core.joran.action.Action;
-import ch.qos.logback.core.joran.spi.ExecutionContext;
-import ch.qos.logback.core.joran.spi.Pattern;
-import ch.qos.logback.core.joran.spi.SimpleRuleStore;
-
-
-import java.util.List;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
 
 /**
  * 
@@ -58,7 +50,7 @@
     assertEquals(1, r.size());
 
     if (!(r.get(0) instanceof XAction)) {
-      fail("Wring type");
+      fail("Wrong type");
     }
 
     srs = new SimpleRuleStore(new ContextBase());
@@ -91,7 +83,7 @@
     assertEquals(1, r.size());
 
     if (!(r.get(0) instanceof XAction)) {
-      fail("Wring type");
+      fail("Wrong type");
     }
   }
 
@@ -107,7 +99,7 @@
     assertEquals(1, r.size());
 
     if (!(r.get(0) instanceof YAction)) {
-      fail("Wring type");
+      fail("Wrong type");
     }
   }
 
@@ -124,19 +116,25 @@
     assertEquals(1, r.size());
 
     if (!(r.get(0) instanceof ZAction)) {
-      fail("Wring type");
+      fail("Wrong type");
     }
   }
+  
+  public void testSuffix() throws Exception {
+    SimpleRuleStore srs = new SimpleRuleStore(new ContextBase());
+    srs.addRule(new Pattern("a"), new XAction());
+    srs.addRule(new Pattern("a/*"), new YAction());
 
-  Document getW3Document(String file) throws Exception {
-    DocumentBuilderFactory dbf = null;
-    dbf = DocumentBuilderFactory.newInstance();
+    List r = srs.matchActions(new Pattern("a/b"));
+    assertNotNull(r);
 
-    DocumentBuilder docBuilder = dbf.newDocumentBuilder();
+    assertEquals(1, r.size());
 
-    // inputSource.setSystemId("dummy://log4j.dtd");
-    return docBuilder.parse(file);
+    if (!(r.get(0) instanceof YAction)) {
+      fail("Wrong type");
+    }
   }
+  
 
   class XAction extends Action {
     public void begin(ExecutionContext ec, String name, Attributes attributes) {

Copied: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/pattern/PackageTest.java (from r714, /logback/trunk/logback-core/src/test/java/ch/qos/logback/core/pattern/AllTest.java)
==============================================================================
--- /logback/trunk/logback-core/src/test/java/ch/qos/logback/core/pattern/AllTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/pattern/PackageTest.java	Thu Oct 19 15:45:50 2006
@@ -1,14 +1,12 @@
 package ch.qos.logback.core.pattern;
 
-
-
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 
-public class AllTest extends TestCase {
+public class PackageTest extends TestCase {
 
-	public static Test suite() {
+  public static Test suite() {
     TestSuite suite = new TestSuite();
     suite.addTest(ch.qos.logback.core.pattern.parser.PackageTest.suite());
     return suite;



More information about the logback-dev mailing list