View Javadoc

1   /**
2    * LOGBack: the generic, reliable, fast and flexible logging framework.
3    * 
4    * Copyright (C) 1999-2006, 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.spi.ContextAware;
20  import ch.qos.logback.core.spi.LifeCycle;
21  import ch.qos.logback.core.util.ContainmentType;
22  import ch.qos.logback.core.util.Loader;
23  import ch.qos.logback.core.util.OptionHelper;
24  import ch.qos.logback.core.util.PropertySetter;
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 NestedComponentIA 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 NestComponentIA 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 the corresponding pop.
41    Stack<ImplicitActionData> actionDataStack = new Stack<ImplicitActionData>();
42  
43    public boolean isApplicable(Pattern pattern, Attributes attributes,
44        InterpretationContext ec) {
45      // System.out.println("in NestComponentIA.isApplicable [" + pattern + "]");
46      String nestedElementTagName = pattern.peekLast();
47  
48      // calling ec.peekObject with an empty stack will throw an exception
49      if (ec.isEmpty()) {
50        return false;
51      }
52  
53      Object o = ec.peekObject();
54      PropertySetter parentBean = new PropertySetter(o);
55      parentBean.setContext(context);
56  
57      ContainmentType containmentType = parentBean
58          .canContainComponent(nestedElementTagName);
59  
60      switch (containmentType) {
61      case NOT_FOUND:
62      case AS_SINGLE_PROPERTY:
63      case AS_PROPERTY_COLLECTION:
64        return false;
65  
66        // we only push action data if NestComponentIA is applicable
67      case AS_COMPONENT_COLLECTION:
68      case AS_SINGLE_COMPONENT:
69        //addInfo("was deemed applicable for " + pattern);
70        ImplicitActionData ad = new ImplicitActionData(parentBean,
71            containmentType);
72        actionDataStack.push(ad);
73  
74        return true;
75      default:
76        addError("PropertySetter.canContainComponent returned " + containmentType);
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      ImplicitActionData actionData = (ImplicitActionData) actionDataStack.peek();
86  
87      String className = attributes.getValue(CLASS_ATTRIBUTE);
88  
89      // perform variable name substitution
90      className = ec.subst(className);
91  
92      if (OptionHelper.isEmpty(className)) {
93        actionData.inError = true;
94        String errMsg = "No class name attribute in [" + localName + "]";
95        addError(errMsg);
96  
97        return;
98      }
99  
100     try {
101       // getLogger().debug(
102       // "About to instantiate component [{}] of type [{}]", localName,
103       // className);
104 
105       // FIXME: Loading classes should be governed by config file rules.
106       
107       actionData.nestedComponent = Loader.loadClass(className, context).newInstance();
108 
109       // pass along the repository
110       if (actionData.nestedComponent instanceof ContextAware) {
111         ((ContextAware) actionData.nestedComponent).setContext(this.context);
112       }
113       // getLogger().debug(
114       addInfo("Pushing component [" + localName
115           + "] on top of the object stack.");
116       ec.pushObject(actionData.nestedComponent);
117     } catch (Exception oops) {
118       actionData.inError = true;
119       String msg = "Could not create component [" + localName + "] of type ["
120           + className + "]";
121       addError(msg, oops);
122     }
123   }
124 
125   public void end(InterpretationContext ec, String tagName) {
126 
127     // pop the action data object pushed in isApplicable() method call
128     // we assume that each this begin
129     ImplicitActionData actionData = (ImplicitActionData) actionDataStack.pop();
130 
131     if (actionData.inError) {
132       return;
133     }
134 
135     PropertySetter nestedBean = new PropertySetter(actionData.nestedComponent);
136     nestedBean.setContext(context);
137 
138     if (nestedBean.canContainComponent("parent") == ContainmentType.AS_SINGLE_COMPONENT) {
139       nestedBean.setComponent("parent", actionData.parentBean.getObj());
140     }
141     if (actionData.nestedComponent instanceof LifeCycle) {
142       ((LifeCycle) actionData.nestedComponent).start();
143     }
144 
145     Object o = ec.peekObject();
146 
147     if (o != actionData.nestedComponent) {
148       addError("The object on the top the of the stack is not the component pushed earlier.");
149     } else {
150       // getLogger().debug("Removing component from the object stack");
151       ec.popObject();
152 
153       // Now let us attach the component
154       switch (actionData.containmentType) {
155       case AS_SINGLE_COMPONENT:
156         // addInfo("Setting ["+tagName+"}] to parent of type
157         // ["+actionData.parentBean.getObjClass()+"]");
158 
159         actionData.parentBean.setComponent(tagName, actionData.nestedComponent);
160 
161         break;
162       case AS_COMPONENT_COLLECTION:
163         // getLogger().debug(
164         // "Adding [{}] to parent of type [{}]", tagName,
165         // actionData.parentBean.getObjClass());
166         actionData.parentBean.addComponent(tagName, actionData.nestedComponent);
167 
168         break;
169       }
170     }
171   }
172 
173 }