[logback-dev] svn commit: r1710 - in logback/trunk/logback-core/src: main/java/ch/qos/logback/core/db 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/pattern/parser main/java/ch/qos/logback/core/util test/input/joran/implicitAction test/java/ch/qos/logback/core/joran test/java/ch/qos/logback/core/joran/implicitAction test/java/ch/qos/logback/core/joran/replay test/java/ch/qos/logback/core/joran/spi test/java/ch/qos/logback/core/util

noreply.ceki at qos.ch noreply.ceki at qos.ch
Thu Jul 17 22:37:36 CEST 2008


Author: ceki
Date: Thu Jul 17 22:37:35 2008
New Revision: 1710

Added:
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/IADataForBasicProperty.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/IADataForComplexProperty.java
      - copied, changed from r1709, /logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/ImplicitActionData.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedBasicPropertyIA.java
      - copied, changed from r1709, /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/NestedComplexPropertyIA.java
      - copied, changed from r1709, /logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedComponentIA.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/PropertySetter.java
      - copied, changed from r1709, /logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/PropertySetter.java
   logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComplex.xml
      - copied unchanged from r1704, /logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComponent.xml
   logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComplexCollection.xml
      - copied unchanged from r1704, /logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComponentCollection.xml
   logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComplexCollectionWithoutClassAtrribute.xml
   logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComplexWithoutClassAtrribute.xml
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/PropertySetterTest.java
      - copied, changed from r1709, /logback/trunk/logback-core/src/test/java/ch/qos/logback/core/util/PropertySetterTest.java
Removed:
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/ImplicitActionData.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedComponentIA.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/util/PropertySetter.java
   logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComponent.xml
   logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComponentCollection.xml
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/util/PropertySetterTest.java
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/joran/JoranConfiguratorBase.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/ParamAction.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/pattern/parser/OptionTokenizer.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/AggregationType.java
   logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/PropertySetterException.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/SimpleConfigurator.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/implicitAction/ImplicitActionTest.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/spi/PackageTest.java
   logback/trunk/logback-core/src/test/java/ch/qos/logback/core/util/PackageTest.java

Log:
- Refactoring of Joran, in particular of PropertySetter. The code should be
  hopefully clearer.
- Joran now support complex types without the need to declare their class
  in the XML element, if the complex type can be instantiated unequivocally.
  This can make config files shorter.

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	Thu Jul 17 22:37:35 2008
@@ -19,8 +19,8 @@
 
 import ch.qos.logback.core.joran.action.Action;
 import ch.qos.logback.core.joran.spi.InterpretationContext;
+import ch.qos.logback.core.joran.spi.PropertySetter;
 import ch.qos.logback.core.util.OptionHelper;
-import ch.qos.logback.core.util.PropertySetter;
 
 /**
  * 

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/JoranConfiguratorBase.java	Thu Jul 17 22:37:35 2008
@@ -18,8 +18,8 @@
 import ch.qos.logback.core.joran.action.AppenderAction;
 import ch.qos.logback.core.joran.action.AppenderRefAction;
 import ch.qos.logback.core.joran.action.ConversionRuleAction;
-import ch.qos.logback.core.joran.action.NestedComponentIA;
-import ch.qos.logback.core.joran.action.NestedSimplePropertyIA;
+import ch.qos.logback.core.joran.action.NestedComplexPropertyIA;
+import ch.qos.logback.core.joran.action.NestedBasicPropertyIA;
 import ch.qos.logback.core.joran.action.NewRuleAction;
 import ch.qos.logback.core.joran.action.ParamAction;
 import ch.qos.logback.core.joran.action.ContextPropertyAction;
@@ -68,11 +68,11 @@
   @Override
   protected void addImplicitRules(Interpreter interpreter) {
     // The following line adds the capability to parse nested components
-    NestedComponentIA nestedIA = new NestedComponentIA();
+    NestedComplexPropertyIA nestedIA = new NestedComplexPropertyIA();
     nestedIA.setContext(context);
     interpreter.addImplicitAction(nestedIA);
 
-    NestedSimplePropertyIA nestedSimpleIA = new NestedSimplePropertyIA();
+    NestedBasicPropertyIA nestedSimpleIA = new NestedBasicPropertyIA();
     nestedIA.setContext(context);
     interpreter.addImplicitAction(nestedSimpleIA);
   }

Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/IADataForBasicProperty.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/IADataForBasicProperty.java	Thu Jul 17 22:37:35 2008
@@ -0,0 +1,22 @@
+package ch.qos.logback.core.joran.action;
+
+import ch.qos.logback.core.joran.spi.PropertySetter;
+import ch.qos.logback.core.util.AggregationType;
+
+/**
+ * Lump together several fields for use by {@link NestedBasicPropertyIA}.
+ * 
+ * @author Ceki Gulcu
+ */
+class IADataForBasicProperty {
+  final PropertySetter parentBean;
+  final AggregationType aggregationType;
+  final String propertyName;
+  boolean inError;
+
+  IADataForBasicProperty(PropertySetter parentBean, AggregationType aggregationType, String propertyName) {
+    this.parentBean = parentBean;
+    this.aggregationType = aggregationType;
+    this.propertyName = propertyName;
+  }
+}

Copied: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/IADataForComplexProperty.java (from r1709, /logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/ImplicitActionData.java)
==============================================================================
--- /logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/ImplicitActionData.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/IADataForComplexProperty.java	Thu Jul 17 22:37:35 2008
@@ -1,23 +1,37 @@
 package ch.qos.logback.core.joran.action;
 
+import ch.qos.logback.core.joran.spi.PropertySetter;
 import ch.qos.logback.core.util.AggregationType;
-import ch.qos.logback.core.util.PropertySetter;
 
 /**
- * ImplicitActionData is a data class aggregating several fields.
- * 
+ * Lump together several fields for use by {@link NestedComplexPropertyIA}.
  * 
  * @author Ceki
  */
-public class ImplicitActionData {
-  PropertySetter parentBean;
-  String propertyName;
-  Object nestedComponent;
-  AggregationType containmentType;
+public class IADataForComplexProperty {
+  final PropertySetter parentBean;
+  final AggregationType aggregationType;
+  final String complexPropertyName;
+  Object nestedComplexProperty;
   boolean inError;
 
-  ImplicitActionData(PropertySetter parentBean, AggregationType containmentType) {
+  public IADataForComplexProperty(PropertySetter parentBean, AggregationType aggregationType, String complexPropertyName) {
     this.parentBean = parentBean;
-    this.containmentType = containmentType;
+    this.aggregationType = aggregationType;
+    this.complexPropertyName = complexPropertyName;
+  }
+
+  public AggregationType getAggregationType() {
+    return aggregationType;
+  }
+
+  public Object getNestedComplexProperty() {
+    return nestedComplexProperty;
+  }
+
+  public String getComplexPropertyName() {
+    return complexPropertyName;
   }
+  
+  
 }

Copied: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedBasicPropertyIA.java (from r1709, /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/NestedBasicPropertyIA.java	Thu Jul 17 22:37:35 2008
@@ -10,92 +10,91 @@
 
 package ch.qos.logback.core.joran.action;
 
-
-
 import java.util.Stack;
 
 import org.xml.sax.Attributes;
 
 import ch.qos.logback.core.joran.spi.InterpretationContext;
 import ch.qos.logback.core.joran.spi.Pattern;
+import ch.qos.logback.core.joran.spi.PropertySetter;
 import ch.qos.logback.core.util.AggregationType;
-import ch.qos.logback.core.util.PropertySetter;
-
-
 
 /**
- * This action is responsible for tying together a parent object with
- * one of its <em>simple</em> properties specified as an element but for 
- * which there is no explicit rule.
+ * This action is responsible for tying together a parent object with one of its
+ * <em>simple</em> properties specified as an element but for which there is
+ * no explicit rule.
  * 
  * @author Ceki G&uuml;lc&uuml;
  */
-public class NestedSimplePropertyIA extends ImplicitAction {
-  
-  // actionDataStack contains ActionData instances
-  // We use a stack of ActionData objects in order to support nested
-  // elements which are handled by the same NestedPropertyIA instance.
-  // We push a ActionData instance in the isApplicable method (if the
+public class NestedBasicPropertyIA extends ImplicitAction {
+
+
+  // We use a stack of IADataForBasicProperty objects in order to 
+  // support nested elements which are handled by the same NestedBasicPropertyIA instance.
+  // We push a IADataForBasicProperty instance in the isApplicable method (if the
   // action is applicable) and pop it in the end() method.
   // The XML well-formedness property will guarantee that a push will eventually
   // be followed by the corresponding pop.
-  Stack<ImplicitActionData> actionDataStack = new Stack<ImplicitActionData>();
+  Stack<IADataForBasicProperty> actionDataStack = new Stack<IADataForBasicProperty>();
 
-  public boolean isApplicable(
-    Pattern pattern, Attributes attributes, InterpretationContext ec) {
-    //System.out.println("in NestedSimplePropertyIA.isApplicable [" + pattern + "]");
+  public boolean isApplicable(Pattern pattern, Attributes attributes,
+      InterpretationContext ec) {
+    // System.out.println("in NestedSimplePropertyIA.isApplicable [" + pattern +
+    // "]");
     String nestedElementTagName = pattern.peekLast();
 
     // no point in attempting if there is no parent object
-    if(ec.isEmpty()) {
+    if (ec.isEmpty()) {
       return false;
     }
-    
+
     Object o = ec.peekObject();
     PropertySetter parentBean = new PropertySetter(o);
     parentBean.setContext(context);
-    
-    AggregationType containmentType = parentBean.canContainComponent(nestedElementTagName);
 
-    switch (containmentType) {
+    AggregationType aggregationType = parentBean
+        .computeAggregationType(nestedElementTagName);
+
+    switch (aggregationType) {
     case NOT_FOUND:
-    case AS_SINGLE_COMPONENT:
-    case AS_COMPONENT_COLLECTION:
+    case AS_COMPLEX_PROPERTY:
+    case AS_COMPLEX_PROPERTY_COLLECTION:
       return false;
 
-    case AS_SINGLE_PROPERTY:
-    case AS_PROPERTY_COLLECTION:
-      ImplicitActionData ad = new ImplicitActionData(parentBean, containmentType);
-      ad.propertyName = nestedElementTagName;
+    case AS_BASIC_PROPERTY:
+    case AS_BASIC_PROPERTY_COLLECTION:
+      IADataForBasicProperty ad = new IADataForBasicProperty(parentBean,
+          aggregationType, nestedElementTagName);
       actionDataStack.push(ad);
-      //addInfo("NestedSimplePropertyIA deemed applicable [" + pattern + "]");
+      // addInfo("NestedSimplePropertyIA deemed applicable [" + pattern + "]");
       return true;
     default:
-      addError("PropertySetter.canContainComponent returned " + containmentType);
+      addError("PropertySetter.canContainComponent returned " + aggregationType);
       return false;
     }
   }
 
-  public void begin(
-    InterpretationContext ec, String localName, Attributes attributes) {
+  public void begin(InterpretationContext ec, String localName,
+      Attributes attributes) {
     // NOP
   }
 
   public void body(InterpretationContext ec, String body) {
-   
+
     String finalBody = ec.subst(body);
-    //System.out.println("body "+body+", finalBody="+finalBody);
+    // System.out.println("body "+body+", finalBody="+finalBody);
     // get the action data object pushed in isApplicable() method call
-    ImplicitActionData actionData = (ImplicitActionData) actionDataStack.peek();
-    switch (actionData.containmentType) {
-    case AS_SINGLE_PROPERTY:
+    IADataForBasicProperty actionData = (IADataForBasicProperty) actionDataStack.peek();
+    switch (actionData.aggregationType) {
+    case AS_BASIC_PROPERTY:
       actionData.parentBean.setProperty(actionData.propertyName, finalBody);
       break;
-    case AS_PROPERTY_COLLECTION:
-      actionData.parentBean.addProperty(actionData.propertyName, finalBody);
+    case AS_BASIC_PROPERTY_COLLECTION:
+      actionData.parentBean
+          .addBasicProperty(actionData.propertyName, finalBody);
     }
   }
-  
+
   public void end(InterpretationContext ec, String tagName) {
     // pop the action data object pushed in isApplicable() method call
     actionDataStack.pop();

Copied: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedComplexPropertyIA.java (from r1709, /logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedComponentIA.java)
==============================================================================
--- /logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedComponentIA.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedComplexPropertyIA.java	Thu Jul 17 22:37:35 2008
@@ -16,12 +16,12 @@
 
 import ch.qos.logback.core.joran.spi.InterpretationContext;
 import ch.qos.logback.core.joran.spi.Pattern;
+import ch.qos.logback.core.joran.spi.PropertySetter;
 import ch.qos.logback.core.spi.ContextAware;
 import ch.qos.logback.core.spi.LifeCycle;
 import ch.qos.logback.core.util.AggregationType;
 import ch.qos.logback.core.util.Loader;
 import ch.qos.logback.core.util.OptionHelper;
-import ch.qos.logback.core.util.PropertySetter;
 
 /**
  * This action is responsible for tying together a parent object with a child
@@ -29,20 +29,21 @@
  * 
  * @author Ceki G&uuml;lc&uuml;
  */
-public class NestedComponentIA extends ImplicitAction {
+public class NestedComplexPropertyIA extends ImplicitAction {
 
   // actionDataStack contains ActionData instances
   // We use a stack of ActionData objects in order to support nested
-  // elements which are handled by the same NestComponentIA instance.
+  // elements which are handled by the same NestedComplexPropertyIA instance.
   // We push a ActionData instance in the isApplicable method (if the
   // action is applicable) and pop it in the end() method.
   // The XML well-formedness property will guarantee that a push will eventually
-  // be followed by the corresponding pop.
-  Stack<ImplicitActionData> actionDataStack = new Stack<ImplicitActionData>();
+  // be followed by a corresponding pop.
+  Stack<IADataForComplexProperty> actionDataStack = new Stack<IADataForComplexProperty>();
 
   public boolean isApplicable(Pattern pattern, Attributes attributes,
       InterpretationContext ec) {
-    // System.out.println("in NestComponentIA.isApplicable [" + pattern + "]");
+    // System.out.println("in NestedComplexPropertyIA.isApplicable [" + pattern
+    // + "]");
     String nestedElementTagName = pattern.peekLast();
 
     // calling ec.peekObject with an empty stack will throw an exception
@@ -54,26 +55,26 @@
     PropertySetter parentBean = new PropertySetter(o);
     parentBean.setContext(context);
 
-    AggregationType containmentType = parentBean
-        .canContainComponent(nestedElementTagName);
+    AggregationType aggregationType = parentBean
+        .computeAggregationType(nestedElementTagName);
 
-    switch (containmentType) {
+    switch (aggregationType) {
     case NOT_FOUND:
-    case AS_SINGLE_PROPERTY:
-    case AS_PROPERTY_COLLECTION:
+    case AS_BASIC_PROPERTY:
+    case AS_BASIC_PROPERTY_COLLECTION:
       return false;
 
       // we only push action data if NestComponentIA is applicable
-    case AS_COMPONENT_COLLECTION:
-    case AS_SINGLE_COMPONENT:
-      //addInfo("was deemed applicable for " + pattern);
-      ImplicitActionData ad = new ImplicitActionData(parentBean,
-          containmentType);
+    case AS_COMPLEX_PROPERTY_COLLECTION:
+    case AS_COMPLEX_PROPERTY:
+      // addInfo("was deemed applicable for " + pattern);
+      IADataForComplexProperty ad = new IADataForComplexProperty(parentBean,
+          aggregationType, nestedElementTagName);
       actionDataStack.push(ad);
 
       return true;
     default:
-      addError("PropertySetter.canContainComponent returned " + containmentType);
+      addError("PropertySetter.canContainComponent returned " + aggregationType);
       return false;
     }
   }
@@ -82,7 +83,8 @@
       Attributes attributes) {
     // LogLog.debug("in NestComponentIA begin method");
     // get the action data object pushed in isApplicable() method call
-    ImplicitActionData actionData = (ImplicitActionData) actionDataStack.peek();
+    IADataForComplexProperty actionData = (IADataForComplexProperty) actionDataStack
+        .peek();
 
     String className = attributes.getValue(CLASS_ATTRIBUTE);
 
@@ -90,11 +92,17 @@
     className = ec.subst(className);
 
     if (OptionHelper.isEmpty(className)) {
-      actionData.inError = true;
-      String errMsg = "No class name attribute in [" + localName + "]";
-      addError(errMsg);
+      Class clazz = actionData.parentBean
+          .findUnequivocallyInstantiableClass(actionData);
+      if (clazz != null) {
+        className = clazz.getName();
+      } else {
+        actionData.inError = true;
+        String errMsg = "No class name attribute in [" + localName + "]";
+        addError(errMsg);
 
-      return;
+        return;
+      }
     }
 
     try {
@@ -102,18 +110,18 @@
       // "About to instantiate component [{}] of type [{}]", localName,
       // className);
 
-      // TODO: Loading classes should be governed by config file rules.
-      
-      actionData.nestedComponent = Loader.loadClass(className, context).newInstance();
+      actionData.nestedComplexProperty = Loader.loadClass(className, context)
+          .newInstance();
 
       // pass along the repository
-      if (actionData.nestedComponent instanceof ContextAware) {
-        ((ContextAware) actionData.nestedComponent).setContext(this.context);
+      if (actionData.nestedComplexProperty instanceof ContextAware) {
+        ((ContextAware) actionData.nestedComplexProperty)
+            .setContext(this.context);
       }
       // getLogger().debug(
       addInfo("Pushing component [" + localName
           + "] on top of the object stack.");
-      ec.pushObject(actionData.nestedComponent);
+      ec.pushObject(actionData.nestedComplexProperty);
     } catch (Exception oops) {
       actionData.inError = true;
       String msg = "Could not create component [" + localName + "] of type ["
@@ -126,44 +134,50 @@
 
     // pop the action data object pushed in isApplicable() method call
     // we assume that each this begin
-    ImplicitActionData actionData = (ImplicitActionData) actionDataStack.pop();
+    IADataForComplexProperty actionData = (IADataForComplexProperty) actionDataStack
+        .pop();
 
     if (actionData.inError) {
       return;
     }
 
-    PropertySetter nestedBean = new PropertySetter(actionData.nestedComponent);
+    PropertySetter nestedBean = new PropertySetter(
+        actionData.nestedComplexProperty);
     nestedBean.setContext(context);
 
-    if (nestedBean.canContainComponent("parent") == AggregationType.AS_SINGLE_COMPONENT) {
-      nestedBean.setComponent("parent", actionData.parentBean.getObj());
-    }
-    if (actionData.nestedComponent instanceof LifeCycle) {
-      ((LifeCycle) actionData.nestedComponent).start();
+    // have the nested element point to its parent if possible
+    if (nestedBean.computeAggregationType("parent") == AggregationType.AS_COMPLEX_PROPERTY) {
+      nestedBean.setComplexProperty("parent", actionData.parentBean.getObj());
+    }
+    // start the nested complex attribute if it implements LifeCycle
+    if (actionData.nestedComplexProperty instanceof LifeCycle) {
+      ((LifeCycle) actionData.nestedComplexProperty).start();
     }
 
     Object o = ec.peekObject();
 
-    if (o != actionData.nestedComponent) {
+    if (o != actionData.nestedComplexProperty) {
       addError("The object on the top the of the stack is not the component pushed earlier.");
     } else {
       // getLogger().debug("Removing component from the object stack");
       ec.popObject();
 
       // Now let us attach the component
-      switch (actionData.containmentType) {
-      case AS_SINGLE_COMPONENT:
+      switch (actionData.aggregationType) {
+      case AS_COMPLEX_PROPERTY:
         // addInfo("Setting ["+tagName+"}] to parent of type
         // ["+actionData.parentBean.getObjClass()+"]");
 
-        actionData.parentBean.setComponent(tagName, actionData.nestedComponent);
+        actionData.parentBean.setComplexProperty(tagName,
+            actionData.nestedComplexProperty);
 
         break;
-      case AS_COMPONENT_COLLECTION:
+      case AS_COMPLEX_PROPERTY_COLLECTION:
         // getLogger().debug(
         // "Adding [{}] to parent of type [{}]", tagName,
         // actionData.parentBean.getObjClass());
-        actionData.parentBean.addComponent(tagName, actionData.nestedComponent);
+        actionData.parentBean.addComplexProperty(tagName,
+            actionData.nestedComplexProperty);
 
         break;
       }

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/ParamAction.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/ParamAction.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/action/ParamAction.java	Thu Jul 17 22:37:35 2008
@@ -14,7 +14,7 @@
 import org.xml.sax.Attributes;
 
 import ch.qos.logback.core.joran.spi.InterpretationContext;
-import ch.qos.logback.core.util.PropertySetter;
+import ch.qos.logback.core.joran.spi.PropertySetter;
 
 
 

Copied: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/joran/spi/PropertySetter.java (from r1709, /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/joran/spi/PropertySetter.java	Thu Jul 17 22:37:35 2008
@@ -15,18 +15,21 @@
  */
 
 // Contributors:  Georg Lundesgaard
-package ch.qos.logback.core.util;
+package ch.qos.logback.core.joran.spi;
 
 import java.beans.BeanInfo;
 import java.beans.IntrospectionException;
 import java.beans.Introspector;
 import java.beans.MethodDescriptor;
 import java.beans.PropertyDescriptor;
-import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 
+import ch.qos.logback.core.joran.action.IADataForComplexProperty;
 import ch.qos.logback.core.spi.ContextAwareBase;
-
+import ch.qos.logback.core.util.AggregationType;
+import ch.qos.logback.core.util.Duration;
+import ch.qos.logback.core.util.FileSize;
+import ch.qos.logback.core.util.PropertySetterException;
 
 /**
  * General purpose Object property setter. Clients repeatedly invokes
@@ -52,13 +55,8 @@
  * @author Ceki Gulcu
  */
 public class PropertySetter extends ContextAwareBase {
-  private static final int X_NOT_FOUND = 0;
-  private static final int X_AS_COMPONENT = 1;
-  private static final int X_AS_PROPERTY = 2;
-  
-  private static final Class[] STING_CLASS_PARAMETER = new Class[] {String.class};
+  private static final Class[] STING_CLASS_PARAMETER = new Class[] { String.class };
 
-  
   protected Object obj;
   protected Class objClass;
   protected PropertyDescriptor[] propertyDescriptors;
@@ -69,7 +67,7 @@
    * preparation for invoking {@link #setProperty} one or more times.
    * 
    * @param obj
-   *          the object for which to set properties
+   *                the object for which to set properties
    */
   public PropertySetter(Object obj) {
     this.obj = obj;
@@ -106,9 +104,9 @@
    * Boolean(value).
    * 
    * @param name
-   *          name of the property
+   *                name of the property
    * @param value
-   *          String value of the property
+   *                String value of the property
    */
   public void setProperty(String name, String value) {
     if (value == null) {
@@ -135,12 +133,12 @@
    * Set the named property given a {@link PropertyDescriptor}.
    * 
    * @param prop
-   *          A PropertyDescriptor describing the characteristics of the
-   *          property to set.
+   *                A PropertyDescriptor describing the characteristics of the
+   *                property to set.
    * @param name
-   *          The named of the property to set.
+   *                The named of the property to set.
    * @param value
-   *          The value of the property.
+   *                The value of the property.
    */
   public void setProperty(PropertyDescriptor prop, String name, String value)
       throws PropertySetterException {
@@ -152,12 +150,11 @@
     }
 
     Class[] paramTypes = setter.getParameterTypes();
-  
-    
+
     if (paramTypes.length != 1) {
       throw new PropertySetterException("#params for setter != 1");
     }
-    
+
     Object arg;
 
     try {
@@ -171,141 +168,168 @@
       throw new PropertySetterException("Conversion to type [" + paramTypes[0]
           + "] failed.");
     }
-
-    // getLogger().debug("Setting property [{}] to [{}].", name, arg);
-
     try {
-      setter.invoke(obj, new Object[] { arg });
+      setter.invoke(obj, arg);
     } catch (Exception ex) {
       throw new PropertySetterException(ex);
     }
   }
 
-  public AggregationType canContainComponent(String name) {
+  public AggregationType computeAggregationType(String name) {
     String cName = capitalizeFirstLetter(name);
 
     Method addMethod = getMethod("add" + cName);
 
+    // if the
     if (addMethod != null) {
-      int type = computeContainmentTpye(addMethod);
+      AggregationType type = computeRawAggregationType(addMethod);
       switch (type) {
-      case X_NOT_FOUND:
+      case NOT_FOUND:
         return AggregationType.NOT_FOUND;
-      case X_AS_PROPERTY:
-        return AggregationType.AS_PROPERTY_COLLECTION;
-      case X_AS_COMPONENT:
-        return AggregationType.AS_COMPONENT_COLLECTION;
+      case AS_BASIC_PROPERTY:
+        return AggregationType.AS_BASIC_PROPERTY_COLLECTION;
+      case AS_COMPLEX_PROPERTY:
+        return AggregationType.AS_COMPLEX_PROPERTY_COLLECTION;
       }
     }
 
-    String dName = Introspector.decapitalize(name);
+    Method setterMethod = findSetterMethod(name);
+    if (setterMethod != null) {
+      return computeRawAggregationType(setterMethod);
+    } else {
+      // we have failed
+      return AggregationType.NOT_FOUND;
+    }
+  }
 
+  private Method findAdderMethod(String name) {
+    name = capitalizeFirstLetter(name);
+    Method adderMethod = getMethod("add" + name);
+    return adderMethod;
+  }
+  
+  private Method findSetterMethod(String name) {
+    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());
-        int type = computeContainmentTpye(setterMethod);
-        // getLogger().debug(
-        // "Found add {} method in class {}", cName, objClass.getName());
-        switch (type) {
-        case X_NOT_FOUND:
-          return AggregationType.NOT_FOUND;
-        case X_AS_PROPERTY:
-          return AggregationType.AS_SINGLE_PROPERTY;
-        case X_AS_COMPONENT:
-          return AggregationType.AS_SINGLE_COMPONENT;
-        }
-      }
+      return propertyDescriptor.getWriteMethod();
+    } else {
+      return null;
     }
-
-    // we have failed
-    return AggregationType.NOT_FOUND;
   }
 
-  int computeContainmentTpye(Method setterMethod) {
-    Class[] classArray = setterMethod.getParameterTypes();
+  Class<?> getParameterClassForMethod(Method method) {
+    if(method == null) {
+      return null;
+    }
+    Class[] classArray = method.getParameterTypes();
     if (classArray.length != 1) {
-      return X_NOT_FOUND;
+      return null;
+    } else {
+      return classArray[0];
+    }
+  }
+  private AggregationType computeRawAggregationType(Method method) {
+    Class<?> clazz = getParameterClassForMethod(method);
+    if (clazz == null) {
+      return AggregationType.NOT_FOUND;
     } else {
-      Class clazz = classArray[0];
       Package p = clazz.getPackage();
       if (clazz.isPrimitive()) {
-        return X_AS_PROPERTY;
+        return AggregationType.AS_BASIC_PROPERTY;
       } else if (p != null && "java.lang".equals(p.getName())) {
-        return X_AS_PROPERTY;
+        return AggregationType.AS_BASIC_PROPERTY;
       } else if (Duration.class.isAssignableFrom(clazz)) {
-        return X_AS_PROPERTY;
+        return AggregationType.AS_BASIC_PROPERTY;
       } else if (FileSize.class.isAssignableFrom(clazz)) {
-        return X_AS_PROPERTY;
-      } else if (clazz.isEnum()){
-        return X_AS_PROPERTY;
+        return AggregationType.AS_BASIC_PROPERTY;
+      } else if (clazz.isEnum()) {
+        return AggregationType.AS_BASIC_PROPERTY;
       } else {
-        return X_AS_COMPONENT;
+        return AggregationType.AS_COMPLEX_PROPERTY;
       }
     }
   }
-  
-  <T> boolean isUnequivocallyInstantiable(Class<T> clazz) {
-    if(clazz.isInterface()) {
+
+  public Class findUnequivocallyInstantiableClass(
+      IADataForComplexProperty actionData) {
+    Class<?> clazz;
+    AggregationType at = actionData.getAggregationType();
+    switch (at) {
+    case AS_COMPLEX_PROPERTY:
+      Method setterMethod = findSetterMethod(actionData.getComplexPropertyName());
+       clazz = getParameterClassForMethod(setterMethod);
+      if(clazz != null && isUnequivocallyInstantiable(clazz)) {
+        return clazz;
+      } else {
+        return null;
+      }
+    case AS_COMPLEX_PROPERTY_COLLECTION:
+      Method adderMethod = findAdderMethod(actionData.getComplexPropertyName());
+      clazz = getParameterClassForMethod(adderMethod);
+      if(clazz != null && isUnequivocallyInstantiable(clazz)) {
+        return clazz;
+      } else {
+        return null;
+      }
+    default:
+      throw new IllegalArgumentException(at
+          + " is not valid type in this method");
+    }
+  }
+
+  boolean isUnequivocallyInstantiable(Class<?> clazz) {
+    if (clazz.isInterface()) {
       return false;
     }
     try {
-      Constructor<T> pubConstructor = clazz.getConstructor();
-      return true;
-    } catch (SecurityException e) {
-      return false;
-    } catch (NoSuchMethodException e) {
+      // checking for constructors would be slightly more elegant, but in classes
+      // without any declared constructors, Class.getConstructor() returns null.
+      Object o = clazz.newInstance();
+      if(o != null) {
+        return true;
+      } else {
+        return false;
+      }
+    } catch (Exception e) {
       return false;
-    }
+    } 
   }
 
   public Class getObjClass() {
     return objClass;
   }
 
-  @SuppressWarnings("unchecked")
-  public void addComponent(String name, Object childComponent) {
-    Class ccc = childComponent.getClass();
-    name = capitalizeFirstLetter(name);
-
-    Method method = getMethod("add" + name);
-
+  public void addComplexProperty(String name, Object complexProperty) {
+    Method adderMethod = findAdderMethod(name);
     // first let us use the addXXX method
-    if (method != null) {
-      Class[] params = method.getParameterTypes();
-
-      if (params.length == 1) {
-        if (params[0].isAssignableFrom(childComponent.getClass())) {
-          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);
-          }
-        } 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() + "].");
-        }
+    if (adderMethod != null) {
+      Class[] paramTypes = adderMethod.getParameterTypes();
+      if (!isSanityCheckSuccessful(name, adderMethod, paramTypes,
+          complexProperty)) {
+        return;
       }
+      invokeMethodWithSingleParameterOnThisObject(adderMethod, complexProperty);
     } else {
       addError("Could not find method [" + "add" + name + "] in class ["
           + objClass.getName() + "].");
     }
   }
 
+  void invokeMethodWithSingleParameterOnThisObject(Method method,
+      Object parameter) {
+    Class ccc = parameter.getClass();
+    try {
+      method.invoke(this.obj, parameter);
+    } catch (Exception e) {
+      addError("Could not invoke method " + method.getName() + " in class "
+          + obj.getClass().getName() + " with parameter of type "
+          + ccc.getName(), e);
+    }
+  }
+
   @SuppressWarnings("unchecked")
-  public void addProperty(String name, String strValue) {
+  public void addBasicProperty(String name, String strValue) {
 
     if (strValue == null) {
       return;
@@ -320,11 +344,8 @@
     }
 
     Class[] paramTypes = adderMethod.getParameterTypes();
-    if (paramTypes.length != 1) {
-      addError("#params for setter != 1");
-      return;
+    isSanityCheckSuccessful(name, adderMethod, paramTypes, strValue);
 
-    }
     Object arg;
     try {
       arg = convertArg(strValue, paramTypes[0]);
@@ -332,20 +353,12 @@
       addError("Conversion to type [" + paramTypes[0] + "] failed. ", t);
       return;
     }
-
-    if (arg == null) {
-      addError("Conversion to type [" + paramTypes[0] + "] failed.");
-    } else {
-      try {
-        adderMethod.invoke(obj, arg);
-      } catch (Exception ex) {
-        addError("Failed to invoke adder for " + name, ex);
-      }
+    if (arg != null) {
+      invokeMethodWithSingleParameterOnThisObject(adderMethod, strValue);
     }
-
   }
 
-  public void setComponent(String name, Object childComponent) {
+  public void setComplexProperty(String name, Object complexProperty) {
     String dName = Introspector.decapitalize(name);
     PropertyDescriptor propertyDescriptor = getPropertyDescriptor(dName);
 
@@ -367,24 +380,41 @@
 
     Class[] paramTypes = setter.getParameterTypes();
 
-    if (paramTypes.length != 1) {
-      addError("Wrong number of parameters in setter method for property ["
-          + name + "] in " + obj.getClass().getName());
-
+    if (!isSanityCheckSuccessful(name, setter, paramTypes, complexProperty)) {
       return;
     }
-
     try {
-      setter.invoke(obj, new Object[] { childComponent });
-      // getLogger().debug(
-      // "Set child component of type [{}] for [{}].", objClass.getName(),
-      // childComponent.getClass().getName());
+      invokeMethodWithSingleParameterOnThisObject(setter, complexProperty);
+
     } catch (Exception e) {
       addError("Could not set component " + obj + " for parent component "
           + obj, e);
     }
   }
 
+  private boolean isSanityCheckSuccessful(String name, Method method,
+      Class<?>[] params, Object complexProperty) {
+    Class ccc = complexProperty.getClass();
+    if (params.length != 1) {
+      addError("Wrong number of parameters in setter method for property ["
+          + name + "] in " + obj.getClass().getName());
+
+      return false;
+    }
+
+    if (!params[0].isAssignableFrom(complexProperty.getClass())) {
+      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() + "].");
+      return false;
+    }
+
+    return true;
+  }
+
   private String capitalizeFirstLetter(String name) {
     return name.substring(0, 1).toUpperCase() + name.substring(1);
   }
@@ -419,7 +449,7 @@
       return Duration.valueOf(val);
     } else if (FileSize.class.isAssignableFrom(type)) {
       return FileSize.valueOf(val);
-    } else if(type.isEnum()) {
+    } else if (type.isEnum()) {
       return convertEnum(val, type);
     }
 
@@ -431,10 +461,12 @@
       Method m = type.getMethod("valueOf", STING_CLASS_PARAMETER);
       return m.invoke(null, val);
     } catch (Exception e) {
-      addError("Failed to convert value ["+val+"] to enum ["+type.getName()+"]", e);
+      addError("Failed to convert value [" + val + "] to enum ["
+          + type.getName() + "]", e);
     }
     return null;
   }
+
   
   protected Method getMethod(String methodName) {
     if (methodDescriptors == null) {

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/pattern/parser/OptionTokenizer.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/pattern/parser/OptionTokenizer.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/pattern/parser/OptionTokenizer.java	Thu Jul 17 22:37:35 2008
@@ -3,7 +3,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import ch.qos.logback.core.CoreGlobal;
 import ch.qos.logback.core.pattern.util.IEscapeUtil;
 import ch.qos.logback.core.pattern.util.RegularEscapeUtil;
 

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/AggregationType.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/AggregationType.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/AggregationType.java	Thu Jul 17 22:37:35 2008
@@ -1,9 +1,23 @@
 package ch.qos.logback.core.util;
 
+/**
+ * AggregationType classifies how one object is contained within 
+ * another object.
+ * 
+ * 
+ * 
+ * See also http://en.wikipedia.org/wiki/Class_diagram
+ * and http://en.wikipedia.org/wiki/Object_composition
+ * 
+ * @author Ceki Gulcu
+ */
 public enum AggregationType {
   NOT_FOUND, 
-  AS_SINGLE_COMPONENT, 
-  AS_SINGLE_PROPERTY, 
-  AS_PROPERTY_COLLECTION, 
-  AS_COMPONENT_COLLECTION;
+  AS_BASIC_PROPERTY, // Long, Integer, Double,..., java primitive, String,
+                      // Duration or FileSize
+  AS_COMPLEX_PROPERTY, // a complex property, a.k.a. attribute, is any attribute 
+                       // not covered by basic attributes, i.e. 
+                       // object types defined by the user
+  AS_BASIC_PROPERTY_COLLECTION, // a collection of basic attributes
+  AS_COMPLEX_PROPERTY_COLLECTION; // a collection of complex attributes
 }

Modified: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/PropertySetterException.java
==============================================================================
--- logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/PropertySetterException.java	(original)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/util/PropertySetterException.java	Thu Jul 17 22:37:35 2008
@@ -7,6 +7,8 @@
 
 package ch.qos.logback.core.util;
 
+import ch.qos.logback.core.joran.spi.PropertySetter;
+
 /**
  * Thrown when an error is encountered whilst attempting to set a property
  * using the {@link PropertySetter} utility class.

Added: logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComplexCollectionWithoutClassAtrribute.xml
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComplexCollectionWithoutClassAtrribute.xml	Thu Jul 17 22:37:35 2008
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<context>
+    <fruit>
+      <name>blue</name>
+      <text>hello</text>
+      <text>world</text>
+      <cake>
+      	<type>A</type>
+      	<code>1</code>
+      </cake>
+      <cake>
+      	<type>B</type>
+      	<code>2</code>
+      </cake>		
+    </fruit> 
+</context>
\ No newline at end of file

Added: logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComplexWithoutClassAtrribute.xml
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/test/input/joran/implicitAction/nestedComplexWithoutClassAtrribute.xml	Thu Jul 17 22:37:35 2008
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<context>
+    <fruit>
+      <name>blue</name>
+      <text>hello</text>
+      <text>world</text>
+    </fruit> 
+</context>
\ No newline at end of file

Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/SimpleConfigurator.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/SimpleConfigurator.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/SimpleConfigurator.java	Thu Jul 17 22:37:35 2008
@@ -13,8 +13,8 @@
 
 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.action.NestedComplexPropertyIA;
+import ch.qos.logback.core.joran.action.NestedBasicPropertyIA;
 import ch.qos.logback.core.joran.spi.Interpreter;
 import ch.qos.logback.core.joran.spi.Pattern;
 import ch.qos.logback.core.joran.spi.RuleStore;
@@ -29,11 +29,11 @@
   
   @Override
   protected void addImplicitRules(Interpreter interpreter) {
-    NestedComponentIA nestedIA = new NestedComponentIA();
+    NestedComplexPropertyIA nestedIA = new NestedComplexPropertyIA();
     nestedIA.setContext(context);
     interpreter.addImplicitAction(nestedIA);
 
-    NestedSimplePropertyIA nestedSimpleIA = new NestedSimplePropertyIA();
+    NestedBasicPropertyIA nestedSimpleIA = new NestedBasicPropertyIA();
     nestedSimpleIA.setContext(context);
     interpreter.addImplicitAction(nestedSimpleIA);
   }

Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/implicitAction/ImplicitActionTest.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/implicitAction/ImplicitActionTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/implicitAction/ImplicitActionTest.java	Thu Jul 17 22:37:35 2008
@@ -17,11 +17,12 @@
 
 public class ImplicitActionTest {
 
-  static final String IMPLCIT_DIR = Constants.TEST_DIR_PREFIX +"input/joran/implicitAction/";
-  
+  static final String IMPLCIT_DIR = Constants.TEST_DIR_PREFIX
+      + "input/joran/implicitAction/";
+
   FruitContext fruitContext = new FruitContext();
   SimpleConfigurator simpleConfigurator;
-  
+
   public ImplicitActionTest() {
   }
 
@@ -34,49 +35,82 @@
     simpleConfigurator.setContext(fruitContext);
   }
 
+  void verifyFruit() {
+    List<Fruit> fList = fruitContext.getFruitList();
+    assertNotNull(fList);
+    assertEquals(1, fList.size());
+
+    Fruit f0 = fList.get(0);
+    assertEquals("blue", f0.getName());
+    assertEquals(2, f0.textList.size());
+    assertEquals("hello", f0.textList.get(0));
+    assertEquals("world", f0.textList.get(1));
+  }
+
+  @Test
+  public void nestedComplex() throws Exception {
+    try {
+      simpleConfigurator.doConfigure(IMPLCIT_DIR + "nestedComplex.xml");
+      verifyFruit();
+
+    } catch (Exception je) {
+      StatusPrinter.print(fruitContext);
+      throw je;
+    }
+  }
+
   @Test
-  public void nested() throws Exception {
-      try {
-          simpleConfigurator.doConfigure(IMPLCIT_DIR + "nestedComponent.xml");
-      
-      List<Fruit> fList = fruitContext.getFruitList();
-      assertNotNull(fList);
-      assertEquals(1, fList.size());
-      
-      Fruit f0 = fList.get(0);
-      assertEquals("blue", f0.getName());
-      assertEquals(2, f0.textList.size());
-      assertEquals("hello", f0.textList.get(0));
-      assertEquals("world", f0.textList.get(1));
-      
+  public void nestedComplexWithoutClassAtrribute() throws Exception {
+    try {
+      simpleConfigurator.doConfigure(IMPLCIT_DIR
+          + "nestedComplexWithoutClassAtrribute.xml");
+
+      verifyFruit();
+
     } catch (Exception je) {
       StatusPrinter.print(fruitContext);
       throw je;
     }
   }
+
   
+  void verifyFruitList() {
+    List<Fruit> fList = fruitContext.getFruitList();
+    assertNotNull(fList);
+    assertEquals(1, fList.size());
+
+    Fruit f0 = fList.get(0);
+    assertEquals(2, f0.cakeList.size());
+
+    Cake cakeA = f0.cakeList.get(0);
+    assertEquals("A", cakeA.getType());
+
+    Cake cakeB = f0.cakeList.get(1);
+    assertEquals("B", cakeB.getType());
+  }
   @Test
-  public void nestedCollection() throws Exception {
-      try {
-          simpleConfigurator.doConfigure(IMPLCIT_DIR + "nestedComponentCollection.xml");
-      
-      List<Fruit> fList = fruitContext.getFruitList();
-      assertNotNull(fList);
-      assertEquals(1, fList.size());
-      
-      Fruit f0 = fList.get(0);
-      assertEquals(2, f0.cakeList.size());
-      
-      Cake cakeA = f0.cakeList.get(0);
-      assertEquals("A", cakeA.getType());
-      
-      Cake cakeB = f0.cakeList.get(1);
-      assertEquals("B", cakeB.getType());
-      
+  public void nestedComplexCollection() throws Exception {
+    try {
+      simpleConfigurator.doConfigure(IMPLCIT_DIR
+          + "nestedComplexCollection.xml");
+      verifyFruitList();
     } catch (Exception je) {
       StatusPrinter.print(fruitContext);
       throw je;
     }
   }
+
   
+  @Test
+  public void nestedComplexCollectionWithoutClassAtrribute() throws Exception {
+    try {
+      simpleConfigurator.doConfigure(IMPLCIT_DIR
+          + "nestedComplexCollectionWithoutClassAtrribute.xml");
+      verifyFruitList();
+    } catch (Exception je) {
+      StatusPrinter.print(fruitContext);
+      throw je;
+    }
+  }
+
 }

Modified: 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/FruitConfigurator.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/replay/FruitConfigurator.java	Thu Jul 17 22:37:35 2008
@@ -13,8 +13,8 @@
 
 import ch.qos.logback.core.joran.GenericConfigurator;
 import ch.qos.logback.core.joran.action.NOPAction;
-import ch.qos.logback.core.joran.action.NestedComponentIA;
-import ch.qos.logback.core.joran.action.NestedSimplePropertyIA;
+import ch.qos.logback.core.joran.action.NestedComplexPropertyIA;
+import ch.qos.logback.core.joran.action.NestedBasicPropertyIA;
 import ch.qos.logback.core.joran.event.SaxEvent;
 import ch.qos.logback.core.joran.spi.EventPlayer;
 import ch.qos.logback.core.joran.spi.Interpreter;
@@ -40,11 +40,11 @@
 
   @Override
   protected void addImplicitRules(Interpreter interpreter) {
-    NestedComponentIA nestedIA = new NestedComponentIA();
+    NestedComplexPropertyIA nestedIA = new NestedComplexPropertyIA();
     nestedIA.setContext(context);
     interpreter.addImplicitAction(nestedIA);
     
-    NestedSimplePropertyIA nestedSimpleIA = new NestedSimplePropertyIA();
+    NestedBasicPropertyIA nestedSimpleIA = new NestedBasicPropertyIA();
     nestedIA.setContext(context);
     interpreter.addImplicitAction(nestedSimpleIA);
   }

Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/PackageTest.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/PackageTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/PackageTest.java	Thu Jul 17 22:37:35 2008
@@ -19,6 +19,7 @@
     TestSuite suite = new TestSuite();
     suite.addTestSuite(PatternTest.class);
     suite.addTestSuite(SimpleStoreTest.class);
+    suite.addTestSuite(PropertySetterTest.class);
     return suite;
   }
 }

Copied: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/PropertySetterTest.java (from r1709, /logback/trunk/logback-core/src/test/java/ch/qos/logback/core/util/PropertySetterTest.java)
==============================================================================
--- /logback/trunk/logback-core/src/test/java/ch/qos/logback/core/util/PropertySetterTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/joran/spi/PropertySetterTest.java	Thu Jul 17 22:37:35 2008
@@ -1,36 +1,42 @@
-package ch.qos.logback.core.util;
+package ch.qos.logback.core.joran.spi;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import ch.qos.logback.core.spi.FilterReply;
-import ch.qos.logback.core.util.PropertySetter;
 import junit.framework.TestCase;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.ContextBase;
+import ch.qos.logback.core.joran.action.IADataForComplexProperty;
+import ch.qos.logback.core.spi.FilterReply;
+import ch.qos.logback.core.util.AggregationType;
+import ch.qos.logback.core.util.Duration;
+import ch.qos.logback.core.util.FileSize;
+import ch.qos.logback.core.util.StatusPrinter;
 
 public class PropertySetterTest extends TestCase {
 
-  public void testCanContainComponent() {
+  public void testCanAggregateComponent() {
     House house = new House();
     PropertySetter setter = new PropertySetter(house);
-    assertEquals(AggregationType.AS_SINGLE_COMPONENT, setter.canContainComponent("door"));
+    assertEquals(AggregationType.AS_COMPLEX_PROPERTY, setter.computeAggregationType("door"));
     
-    assertEquals(AggregationType.AS_SINGLE_PROPERTY, setter.canContainComponent("count"));
-    assertEquals(AggregationType.AS_SINGLE_PROPERTY, setter.canContainComponent("Count"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY, setter.computeAggregationType("count"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY, setter.computeAggregationType("Count"));
     
-    assertEquals(AggregationType.AS_SINGLE_PROPERTY, setter.canContainComponent("name"));
-    assertEquals(AggregationType.AS_SINGLE_PROPERTY, setter.canContainComponent("Name"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY, setter.computeAggregationType("name"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY, setter.computeAggregationType("Name"));
     
-    assertEquals(AggregationType.AS_SINGLE_PROPERTY, setter.canContainComponent("Duration"));
-    assertEquals(AggregationType.AS_SINGLE_PROPERTY, setter.canContainComponent("fs"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY, setter.computeAggregationType("Duration"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY, setter.computeAggregationType("fs"));
     
-    assertEquals(AggregationType.AS_SINGLE_PROPERTY, setter.canContainComponent("open"));
-    assertEquals(AggregationType.AS_SINGLE_PROPERTY, setter.canContainComponent("Open"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY, setter.computeAggregationType("open"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY, setter.computeAggregationType("Open"));
     
-    assertEquals(AggregationType.AS_COMPONENT_COLLECTION, setter.canContainComponent("Window"));
-    assertEquals(AggregationType.AS_PROPERTY_COLLECTION, setter.canContainComponent("adjective"));
+    assertEquals(AggregationType.AS_COMPLEX_PROPERTY_COLLECTION, setter.computeAggregationType("Window"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY_COLLECTION, setter.computeAggregationType("adjective"));
     
-    assertEquals(AggregationType.AS_SINGLE_PROPERTY, setter.canContainComponent("filterReply"));
-    assertEquals(AggregationType.AS_SINGLE_PROPERTY, setter.canContainComponent("houseColor"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY, setter.computeAggregationType("filterReply"));
+    assertEquals(AggregationType.AS_BASIC_PROPERTY, setter.computeAggregationType("houseColor"));
     
     System.out.println();
   }
@@ -72,25 +78,42 @@
     assertEquals("gh", house.getCamelCase());
   }
   
-  public void testSetComponent() {
+  public void testSetComplexProperty() {
     House house = new House();
     Door door = new Door();
     PropertySetter setter = new PropertySetter(house);
-    setter.setComponent("door", door);
+    setter.setComplexProperty("door", door);
     assertEquals(door, house.getDoor());
   }
 
+  public void testSetComplexProperty2() {
+    House house = new House();
+    //Door door = new Door();
+    PropertySetter setter = new PropertySetter(house);
+    
+    IADataForComplexProperty actionData = new IADataForComplexProperty(setter,
+        AggregationType.AS_COMPLEX_PROPERTY, "door");
+    
+    Class clazz = setter.findUnequivocallyInstantiableClass(actionData);
+    assertNotNull(clazz);
+    assertEquals(Door.class.getName(), clazz.getName());
+    //setter.setComplexProperty("door", door);
+    //assertEquals(door, house.getDoor());
+  }
   public void testPropertyCollection() {
     House house = new House();
+    Context context = new ContextBase();
     PropertySetter setter = new PropertySetter(house);
-    setter.addProperty("adjective", "nice");
-    setter.addProperty("adjective", "big");
+    setter.setContext(context);
+    setter.addBasicProperty("adjective", "nice");
+    setter.addBasicProperty("adjective", "big");
+    StatusPrinter.print(context);
     assertEquals(2, house.adjectiveList.size());
     assertEquals("nice", house.adjectiveList.get(0));
     assertEquals("big", house.adjectiveList.get(1));
   }
 
-  public void testComponentCollection() {
+  public void testComplexCollection() {
     House house = new House();
     PropertySetter setter = new PropertySetter(house);
     Window w1 = new Window();
@@ -98,21 +121,21 @@
     Window w2 = new Window();
     w2.handle=20;
     
-    setter.addComponent("window", w1);
-    setter.addComponent("window", w2);
+    setter.addComplexProperty("window", w1);
+    setter.addComplexProperty("window", w2);
     assertEquals(2, house.windowList.size());
     assertEquals(10, house.windowList.get(0).handle);
     assertEquals(20, house.windowList.get(1).handle);
   }
   
-  public void testSetComponentWithCamelCaseName() {
+  public void testSetComplexWithCamelCaseName() {
     House house = new House();
     SwimmingPool pool = new SwimmingPool();
     PropertySetter setter = new PropertySetter(house);
-    setter.setComponent("swimmingPool", pool);
+    setter.setComplexProperty("swimmingPool", pool);
     assertEquals(pool, house.getSwimmingPool());
   }
-
+  
   public void testDuration() {
     House house = new House();
     PropertySetter setter = new PropertySetter(house);

Modified: logback/trunk/logback-core/src/test/java/ch/qos/logback/core/util/PackageTest.java
==============================================================================
--- logback/trunk/logback-core/src/test/java/ch/qos/logback/core/util/PackageTest.java	(original)
+++ logback/trunk/logback-core/src/test/java/ch/qos/logback/core/util/PackageTest.java	Thu Jul 17 22:37:35 2008
@@ -21,7 +21,6 @@
     suite.addTestSuite(DurationTest.class);
     suite.addTestSuite(FileSizeTest.class);
     suite.addTestSuite(OptionHelperTest.class);
-    suite.addTestSuite(PropertySetterTest.class);
     suite.addTestSuite(StatusPrinterTest.class);
     suite.addTestSuite(TimeUtilTest.class);
     return suite;


More information about the logback-dev mailing list