View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2022, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.model.processor;
15  
16  import java.util.ArrayList;
17  import java.util.Collections;
18  import java.util.HashMap;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.Properties;
22  import java.util.Stack;
23  
24  import ch.qos.logback.core.Context;
25  import ch.qos.logback.core.joran.action.ImplicitActionDataBase;
26  import ch.qos.logback.core.joran.spi.DefaultNestedComponentRegistry;
27  import ch.qos.logback.core.joran.util.beans.BeanDescriptionCache;
28  import ch.qos.logback.core.model.Model;
29  import ch.qos.logback.core.spi.ContextAwareBase;
30  import ch.qos.logback.core.spi.PropertyContainer;
31  import ch.qos.logback.core.spi.ScanException;
32  import ch.qos.logback.core.util.OptionHelper;
33  
34  public class ModelInterpretationContext extends ContextAwareBase implements PropertyContainer {
35  
36      Stack<Object> objectStack;
37      Stack<Model> modelStack;
38  
39      Stack<ImplicitActionDataBase> implicitActionDataStack;
40  
41      Map<String, Object> objectMap;
42      Map<String, String> propertiesMap;
43      Map<String, String> importMap;
44  
45  
46      final private BeanDescriptionCache beanDescriptionCache;
47      final DefaultNestedComponentRegistry defaultNestedComponentRegistry = new DefaultNestedComponentRegistry();
48      List<DependencyDefinition> dependencyDefinitionList = new ArrayList<>();
49      final List<String> startedDependees = new ArrayList<>();
50  
51      public ModelInterpretationContext(Context context) {
52          this.context = context;
53          this.objectStack = new Stack<>();
54          this.modelStack = new Stack<>();
55          this.implicitActionDataStack = new Stack<>();
56          this.beanDescriptionCache = new BeanDescriptionCache(context);
57          objectMap = new HashMap<>(5);
58          propertiesMap = new HashMap<>(5);
59          importMap = new HashMap<>(5);
60      }
61  
62      public Map<String, Object> getObjectMap() {
63          return objectMap;
64      }
65  
66      // moodelStack =================================
67  
68      public void pushModel(Model m) {
69          modelStack.push(m);
70      }
71  
72      public Model peekModel() {
73          return modelStack.peek();
74      }
75  
76      public boolean isModelStackEmpty() {
77          return modelStack.isEmpty();
78      }
79  
80      public Model popModel() {
81          return modelStack.pop();
82      }
83  
84      // =================== object stack
85  
86      public Stack<Object> getObjectStack() {
87          return objectStack;
88      }
89  
90      public boolean isObjectStackEmpty() {
91          return objectStack.isEmpty();
92      }
93  
94      public Object peekObject() {
95          return objectStack.peek();
96      }
97  
98      public void pushObject(Object o) {
99          objectStack.push(o);
100     }
101 
102     public Object popObject() {
103         return objectStack.pop();
104     }
105 
106     public Object getObject(int i) {
107         return objectStack.get(i);
108     }
109 
110     // ===================== END object stack
111 
112     public BeanDescriptionCache getBeanDescriptionCache() {
113         return beanDescriptionCache;
114     }
115 
116     public String subst(String ref) {
117         if (ref == null) {
118             return null;
119         }
120 
121         try {
122             return OptionHelper.substVars(ref, this, context);
123         } catch (ScanException | IllegalArgumentException e) {
124             addError("Problem while parsing [" + ref + "]", e);
125             return ref;
126         }
127 
128     }
129 
130     /**
131      * Add a property to the properties of this execution context. If the property
132      * exists already, it is overwritten.
133      */
134     public void addSubstitutionProperty(String key, String value) {
135         if (key == null || value == null) {
136             return;
137         }
138         // values with leading or trailing spaces are bad. We remove them now.
139         value = value.trim();
140         propertiesMap.put(key, value);
141     }
142 
143     public void addSubstitutionProperties(Properties props) {
144         if (props == null) {
145             return;
146         }
147         for (Object keyObject : props.keySet()) {
148             String key = (String) keyObject;
149             String val = props.getProperty(key);
150             addSubstitutionProperty(key, val);
151         }
152     }
153 
154     public DefaultNestedComponentRegistry getDefaultNestedComponentRegistry() {
155         return defaultNestedComponentRegistry;
156     }
157 
158     /**
159      * actionDataStack contains ActionData instances We use a stack of ActionData
160      * objects in order to support nested elements which are handled by the same
161      * NestedComplexPropertyIA instance. We push a ActionData instance in the
162      * isApplicable method (if the action is applicable) and pop it in the end()
163      * method. The XML well-formedness property will guarantee that a push will
164      * eventually be followed by a corresponding pop.
165      */
166     public Stack<ImplicitActionDataBase> getImplcitActionDataStack() {
167         return implicitActionDataStack;
168     }
169 
170     // ================================== dependencies
171 
172     public void addDependencyDefinition(DependencyDefinition dd) {
173         dependencyDefinitionList.add(dd);
174     }
175 
176     public List<DependencyDefinition> getDependencyDefinitions() {
177         return Collections.unmodifiableList(dependencyDefinitionList);
178     }
179 
180     public List<String> getDependeeNamesForModel(Model model) {
181         List<String> dependencyList = new ArrayList<>();
182         for (DependencyDefinition dd : dependencyDefinitionList) {
183             if (dd.getDepender() == model) {
184                dependencyList.add(dd.getDependee());
185             }
186         }
187         return dependencyList;
188     }
189 
190     public boolean hasDependers(String dependeeName) {
191 
192         if (dependeeName == null || dependeeName.trim().length() == 0) {
193             new IllegalArgumentException("Empty dependeeName name not allowed here");
194         }
195 
196         for (DependencyDefinition dd : dependencyDefinitionList) {
197             if (dd.dependee.equals(dependeeName))
198                 return true;
199         }
200 
201         return false;
202     }
203 
204 
205     public void markStartOfNamedDependee(String name) {
206         startedDependees.add(name);
207     }
208 
209     public boolean isNamedDependeeStarted(String name) {
210         return startedDependees.contains(name);
211     }
212 
213     // ========================================== object map
214 
215     /**
216      * If a key is found in propertiesMap then return it. Otherwise, delegate to the
217      * context.
218      */
219     public String getProperty(String key) {
220         String v = propertiesMap.get(key);
221         if (v != null) {
222             return v;
223         } else {
224             return context.getProperty(key);
225         }
226     }
227 
228     @Override
229     public Map<String, String> getCopyOfPropertyMap() {
230         return new HashMap<String, String>(propertiesMap);
231     }
232 
233     // imports
234 
235     /**
236      * Add an import to the importMao
237      * 
238      * @param stem the class to import
239      * @param fqcn the fully qualified name of the class
240      * 
241      * @since 1.3
242      */
243     public void addImport(String stem, String fqcn) {
244         importMap.put(stem, fqcn);
245     }
246 
247     /**
248      * Given a stem, get the fully qualified name of the class corresponding to the
249      * stem. For unknown stems, returns the stem as is. If stem is null, null is
250      * returned.
251      * 
252      * @param stem may be null
253      * @return fully qualified name of the class corresponding to the stem. For
254      *         unknown stems, returns the stem as is. If stem is null, null is
255      *         returned.
256      * @since 1.3
257      */
258     public String getImport(String stem) {
259         if (stem == null)
260             return null;
261 
262         String result = importMap.get(stem);
263         if (result == null)
264             return stem;
265         else
266             return result;
267     }
268 
269 }