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  import java.util.function.Supplier;
24  
25  import ch.qos.logback.core.Appender;
26  import ch.qos.logback.core.Context;
27  import ch.qos.logback.core.joran.GenericXMLConfigurator;
28  import ch.qos.logback.core.joran.JoranConfiguratorBase;
29  import ch.qos.logback.core.joran.JoranConstants;
30  import ch.qos.logback.core.joran.spi.DefaultNestedComponentRegistry;
31  import ch.qos.logback.core.joran.util.beans.BeanDescriptionCache;
32  import ch.qos.logback.core.model.Model;
33  import ch.qos.logback.core.model.util.VariableSubstitutionsHelper;
34  import ch.qos.logback.core.spi.AppenderAttachable;
35  import ch.qos.logback.core.spi.ContextAwareBase;
36  import ch.qos.logback.core.spi.ContextAwarePropertyContainer;
37  import ch.qos.logback.core.spi.PropertyContainer;
38  
39  public class ModelInterpretationContext extends ContextAwareBase implements ContextAwarePropertyContainer {
40  
41      Stack<Object> objectStack;
42      Stack<Model> modelStack;
43  
44      /**
45       * A supplier of JoranConfigurator instances.
46       *
47       * May be null.
48       *
49       * @since 1.5.5
50       */
51      Supplier<? extends GenericXMLConfigurator> configuratorSupplier;
52  
53  
54      Map<String, Object> objectMap;
55      protected VariableSubstitutionsHelper variableSubstitutionsHelper;
56      protected Map<String, String> importMap;
57  
58      final private BeanDescriptionCache beanDescriptionCache;
59      final DefaultNestedComponentRegistry defaultNestedComponentRegistry = new DefaultNestedComponentRegistry();
60      List<DependencyDefinition> dependencyDefinitionList = new ArrayList<>();
61      final List<String> startedDependees = new ArrayList<>();
62  
63      Object configuratorHint;
64  
65      Model topModel;
66  
67      public ModelInterpretationContext(Context context) {
68          this(context, null);
69      }
70  
71      public ModelInterpretationContext(Context context, Object configuratorHint) {
72          this.context = context;
73          this.configuratorHint = configuratorHint;
74          this.objectStack = new Stack<>();
75          this.modelStack = new Stack<>();
76          this.beanDescriptionCache = new BeanDescriptionCache(context);
77          objectMap = new HashMap<>(5);
78          variableSubstitutionsHelper = new VariableSubstitutionsHelper(context);
79          importMap = new HashMap<>(5);
80      }
81  
82      public ModelInterpretationContext(ModelInterpretationContext otherMic) {
83          this(otherMic.context, otherMic.configuratorHint);
84          importMap = new HashMap<>(otherMic.importMap);
85          variableSubstitutionsHelper =  new VariableSubstitutionsHelper(context, otherMic.getCopyOfPropertyMap());
86          defaultNestedComponentRegistry.duplicate(otherMic.getDefaultNestedComponentRegistry());
87          createAppenderBags();
88      } 
89          
90      public Map<String, Object> getObjectMap() {
91          return objectMap;
92      }
93  
94      public void createAppenderBags() {
95          objectMap.put(JoranConstants.APPENDER_BAG, new HashMap<String, Appender<?>>());
96          objectMap.put(JoranConstants.APPENDER_REF_BAG, new HashMap<String, AppenderAttachable<?>>());
97      }
98  
99      public Model getTopModel() {
100         return topModel;
101     }
102 
103     public void setTopModel(Model topModel) {
104         this.topModel = topModel;
105     }
106 
107     // modelStack =================================
108 
109     public void pushModel(Model m) {
110         modelStack.push(m);
111     }
112 
113     public Model peekModel() {
114         return modelStack.peek();
115     }
116 
117     public boolean isModelStackEmpty() {
118         return modelStack.isEmpty();
119     }
120 
121     public Model popModel() {
122         return modelStack.pop();
123     }
124 
125     // =================== object stack
126 
127     public Stack<Object> getObjectStack() {
128         return objectStack;
129     }
130 
131     public boolean isObjectStackEmpty() {
132         return objectStack.isEmpty();
133     }
134 
135     public Object peekObject() {
136         return objectStack.peek();
137     }
138 
139     public void pushObject(Object o) {
140         objectStack.push(o);
141     }
142 
143     public Object popObject() {
144         return objectStack.pop();
145     }
146 
147     public Object getObject(int i) {
148         return objectStack.get(i);
149     }
150 
151     // ===================== END object stack
152 
153     public Object getConfiguratorHint() {
154         return configuratorHint;
155     }
156 
157     public void setConfiguratorHint(Object configuratorHint) {
158         this.configuratorHint = configuratorHint;
159     }
160 
161     public BeanDescriptionCache getBeanDescriptionCache() {
162         return beanDescriptionCache;
163     }
164 
165     public String subst(String ref)  {
166         return variableSubstitutionsHelper.subst(ref);
167     }
168 
169 
170     public DefaultNestedComponentRegistry getDefaultNestedComponentRegistry() {
171         return defaultNestedComponentRegistry;
172     }
173 
174     // ================================== dependencies
175 
176     public void addDependencyDefinition(DependencyDefinition dd) {
177         dependencyDefinitionList.add(dd);
178     }
179 
180     public List<DependencyDefinition> getDependencyDefinitions() {
181         return Collections.unmodifiableList(dependencyDefinitionList);
182     }
183 
184     public List<String> getDependeeNamesForModel(Model model) {
185         List<String> dependencyList = new ArrayList<>();
186         for (DependencyDefinition dd : dependencyDefinitionList) {
187             if (dd.getDepender() == model) {
188                dependencyList.add(dd.getDependee());
189             }
190         }
191         return dependencyList;
192     }
193 
194     public boolean hasDependers(String dependeeName) {
195 
196         if (dependeeName == null || dependeeName.trim().length() == 0) {
197             new IllegalArgumentException("Empty dependeeName name not allowed here");
198         }
199 
200         for (DependencyDefinition dd : dependencyDefinitionList) {
201             if (dd.dependee.equals(dependeeName))
202                 return true;
203         }
204 
205         return false;
206     }
207 
208 
209     public void markStartOfNamedDependee(String name) {
210         startedDependees.add(name);
211     }
212 
213     public boolean isNamedDependeeStarted(String name) {
214         return startedDependees.contains(name);
215     }
216 
217     // ========================================== object map
218 
219     /**
220      * Add a property to the properties of this execution context. If the property
221      * exists already, it is overwritten.
222      */
223     @Override
224     public void addSubstitutionProperty(String key, String value) {
225         variableSubstitutionsHelper.addSubstitutionProperty(key, value);
226     }
227 
228     /**
229      * If a key is found in propertiesMap then return it. Otherwise, delegate to the
230      * context.
231      */
232     public String getProperty(String key) {
233       return  variableSubstitutionsHelper.getProperty(key);
234     }
235 
236     @Override
237     public Map<String, String> getCopyOfPropertyMap() {
238         return variableSubstitutionsHelper.getCopyOfPropertyMap();
239     }
240 
241     // imports ===================================================================
242 
243     /**
244      * Add an import to the importMao
245      * 
246      * @param stem the class to import
247      * @param fqcn the fully qualified name of the class
248      * 
249      * @since 1.3
250      */
251     public void addImport(String stem, String fqcn) {
252         importMap.put(stem, fqcn);
253     }
254 
255     public Map<String, String> getImportMapCopy() {
256         return new HashMap<>(importMap);
257     }
258 
259     
260     /**
261      * Given a stem, get the fully qualified name of the class corresponding to the
262      * stem. For unknown stems, returns the stem as is. If stem is null, null is
263      * returned.
264      * 
265      * @param stem may be null
266      * @return fully qualified name of the class corresponding to the stem. For
267      *         unknown stems, returns the stem as is. If stem is null, null is
268      *         returned.
269      * @since 1.3
270      */
271     public String getImport(String stem) {
272         if (stem == null)
273             return null;
274 
275         String result = importMap.get(stem);
276         if (result == null)
277             return stem;
278         else
279             return result;
280     }
281 
282     /**
283      * Returns a supplier of {@link GenericXMLConfigurator} instance. The returned value may be null.
284      *
285      * @return a supplier of {@link GenericXMLConfigurator} instance, may be null
286      */
287     public Supplier<? extends GenericXMLConfigurator> getConfiguratorSupplier() {
288         return this.configuratorSupplier;
289     }
290 
291     /**
292      *
293      * @param configuratorSupplier
294      */
295     public void setConfiguratorSupplier(Supplier<? extends GenericXMLConfigurator> configuratorSupplier) {
296         this.configuratorSupplier = configuratorSupplier;
297     }
298 }