View Javadoc

1   /**
2    * Logback: the generic, reliable, fast and flexible logging framework.
3    * 
4    * Copyright (C) 2000-2009, QOS.ch
5    * 
6    * This library is free software, you can redistribute it and/or modify it under
7    * the terms of the GNU Lesser General Public License as published by the Free
8    * Software Foundation.
9    */
10  
11  package ch.qos.logback.core.joran.action;
12  
13  import java.util.Stack;
14  
15  import org.xml.sax.Attributes;
16  
17  import ch.qos.logback.core.joran.spi.InterpretationContext;
18  import ch.qos.logback.core.joran.spi.Pattern;
19  import ch.qos.logback.core.joran.spi.PropertySetter;
20  import ch.qos.logback.core.spi.ContextAware;
21  import ch.qos.logback.core.spi.LifeCycle;
22  import ch.qos.logback.core.util.AggregationType;
23  import ch.qos.logback.core.util.Loader;
24  import ch.qos.logback.core.util.OptionHelper;
25  
26  /**
27   * This action is responsible for tying together a parent object with a child
28   * element for which there is no explicit rule.
29   * 
30   * @author Ceki Gülcü
31   */
32  public class NestedComplexPropertyIA extends ImplicitAction {
33  
34    // actionDataStack contains ActionData instances
35    // We use a stack of ActionData objects in order to support nested
36    // elements which are handled by the same NestedComplexPropertyIA instance.
37    // We push a ActionData instance in the isApplicable method (if the
38    // action is applicable) and pop it in the end() method.
39    // The XML well-formedness property will guarantee that a push will eventually
40    // be followed by a corresponding pop.
41    Stack<IADataForComplexProperty> actionDataStack = new Stack<IADataForComplexProperty>();
42  
43    public boolean isApplicable(Pattern pattern, Attributes attributes,
44        InterpretationContext ic) {
45  
46      String nestedElementTagName = pattern.peekLast();
47  
48      // calling ic.peekObject with an empty stack will throw an exception
49      if (ic.isEmpty()) {
50        return false;
51      }
52  
53      Object o = ic.peekObject();
54      PropertySetter parentBean = new PropertySetter(o);
55      parentBean.setContext(context);
56  
57      AggregationType aggregationType = parentBean
58          .computeAggregationType(nestedElementTagName);
59  
60      switch (aggregationType) {
61      case NOT_FOUND:
62      case AS_BASIC_PROPERTY:
63      case AS_BASIC_PROPERTY_COLLECTION:
64        return false;
65  
66        // we only push action data if NestComponentIA is applicable
67      case AS_COMPLEX_PROPERTY_COLLECTION:
68      case AS_COMPLEX_PROPERTY:
69        IADataForComplexProperty ad = new IADataForComplexProperty(parentBean,
70            aggregationType, nestedElementTagName);
71        actionDataStack.push(ad);
72  
73        return true;
74      default:
75        addError("PropertySetter.computeAggregationType returned "
76            + aggregationType);
77        return false;
78      }
79    }
80  
81    public void begin(InterpretationContext ec, String localName,
82        Attributes attributes) {
83      // LogLog.debug("in NestComponentIA begin method");
84      // get the action data object pushed in isApplicable() method call
85      IADataForComplexProperty actionData = (IADataForComplexProperty) actionDataStack
86          .peek();
87  
88      String className = attributes.getValue(CLASS_ATTRIBUTE);
89      // perform variable name substitution
90      className = ec.subst(className);
91  
92      Class componentClass = null;
93      try {
94  
95        if (!OptionHelper.isEmpty(className)) {
96          componentClass = Loader.loadClass(className, context);
97        } else {
98          // guess class name via implicit rules
99          PropertySetter parentBean = actionData.parentBean;
100         componentClass = parentBean.getClassNameViaImplicitRules(actionData
101             .getComplexPropertyName(), actionData.getAggregationType(), ec
102             .getDefaultNestedComponentRegistry());
103       }
104 
105       if (componentClass == null) {
106         actionData.inError = true;
107         String errMsg = "Could not find an appropriate class for property ["
108             + localName + "]";
109         addError(errMsg);
110         return;
111       }
112 
113       if(OptionHelper.isEmpty(className)) {
114         addInfo("Assuming default type ["+componentClass.getName()+"] for ["+localName+"] property");
115       }
116       
117       actionData.setNestedComplexProperty(componentClass.newInstance());
118 
119       // pass along the repository
120       if (actionData.getNestedComplexProperty() instanceof ContextAware) {
121         ((ContextAware) actionData.getNestedComplexProperty())
122             .setContext(this.context);
123       }
124       // getLogger().debug(
125       addInfo("Pushing component [" + localName
126           + "] on top of the object stack.");
127       ec.pushObject(actionData.getNestedComplexProperty());
128 
129     } catch (Exception oops) {
130       actionData.inError = true;
131       String msg = "Could not create component [" + localName + "] of type ["
132           + className + "]";
133       addError(msg, oops);
134     }
135 
136   }
137 
138   public void end(InterpretationContext ec, String tagName) {
139 
140     // pop the action data object pushed in isApplicable() method call
141     // we assume that each this begin
142     IADataForComplexProperty actionData = (IADataForComplexProperty) actionDataStack
143         .pop();
144 
145     if (actionData.inError) {
146       return;
147     }
148 
149     PropertySetter nestedBean = new PropertySetter(actionData
150         .getNestedComplexProperty());
151     nestedBean.setContext(context);
152 
153     // have the nested element point to its parent if possible
154     if (nestedBean.computeAggregationType("parent") == AggregationType.AS_COMPLEX_PROPERTY) {
155       nestedBean.setComplexProperty("parent", actionData.parentBean.getObj());
156     }
157     // start the nested complex attribute if it implements LifeCycle
158     if (actionData.getNestedComplexProperty() instanceof LifeCycle) {
159       ((LifeCycle) actionData.getNestedComplexProperty()).start();
160     }
161 
162     Object o = ec.peekObject();
163 
164     if (o != actionData.getNestedComplexProperty()) {
165       addError("The object on the top the of the stack is not the component pushed earlier.");
166     } else {
167       ec.popObject();
168       // Now let us attach the component
169       switch (actionData.aggregationType) {
170       case AS_COMPLEX_PROPERTY:
171         actionData.parentBean.setComplexProperty(tagName, actionData
172             .getNestedComplexProperty());
173 
174         break;
175       case AS_COMPLEX_PROPERTY_COLLECTION:
176         actionData.parentBean.addComplexProperty(tagName, actionData
177             .getNestedComplexProperty());
178 
179         break;
180       }
181     }
182   }
183 
184 }