1 /**
2  * Logback: the reliable, generic, fast and flexible logging framework.
3  * Copyright (C) 1999-2015, 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.joran.spi;
15
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Properties;
21 import java.util.Stack;
22
23 import org.xml.sax.Locator;
24
25 import ch.qos.logback.core.Context;
26 import ch.qos.logback.core.joran.action.Action;
27 import ch.qos.logback.core.joran.event.InPlayListener;
28 import ch.qos.logback.core.joran.event.SaxEvent;
29 import ch.qos.logback.core.spi.ContextAwareBase;
30 import ch.qos.logback.core.spi.PropertyContainer;
31 import ch.qos.logback.core.util.OptionHelper;
32
33 /**
34  * 
35  * An InterpretationContext contains the contextual state of a Joran parsing
36  * session. {@link Action} objects depend on this context to exchange and store
37  * information.
38  * 
39  * @author Ceki Gülcü
40  */

41 public class InterpretationContext extends ContextAwareBase implements PropertyContainer {
42     Stack<Object> objectStack;
43     Map<String, Object> objectMap;
44     Map<String, String> propertiesMap;
45
46     Interpreter joranInterpreter;
47     final List<InPlayListener> listenerList = new ArrayList<InPlayListener>();
48     DefaultNestedComponentRegistry defaultNestedComponentRegistry = new DefaultNestedComponentRegistry();
49
50     public InterpretationContext(Context context, Interpreter joranInterpreter) {
51         this.context = context;
52         this.joranInterpreter = joranInterpreter;
53         objectStack = new Stack<Object>();
54         objectMap = new HashMap<String, Object>(5);
55         propertiesMap = new HashMap<String, String>(5);
56     }
57
58     public DefaultNestedComponentRegistry getDefaultNestedComponentRegistry() {
59         return defaultNestedComponentRegistry;
60     }
61
62     public Map<String, String> getCopyOfPropertyMap() {
63         return new HashMap<String, String>(propertiesMap);
64     }
65
66     void setPropertiesMap(Map<String, String> propertiesMap) {
67         this.propertiesMap = propertiesMap;
68     }
69
70     String updateLocationInfo(String msg) {
71         Locator locator = joranInterpreter.getLocator();
72
73         if (locator != null) {
74             return msg + locator.getLineNumber() + ":" + locator.getColumnNumber();
75         } else {
76             return msg;
77         }
78     }
79
80     public Locator getLocator() {
81         return joranInterpreter.getLocator();
82     }
83
84     public Interpreter getJoranInterpreter() {
85         return joranInterpreter;
86     }
87
88     public Stack<Object> getObjectStack() {
89         return objectStack;
90     }
91
92     public boolean isEmpty() {
93         return objectStack.isEmpty();
94     }
95
96     public Object peekObject() {
97         return objectStack.peek();
98     }
99
100     public void pushObject(Object o) {
101         objectStack.push(o);
102     }
103
104     public Object popObject() {
105         return objectStack.pop();
106     }
107
108     public Object getObject(int i) {
109         return objectStack.get(i);
110     }
111
112     public Map<String, Object> getObjectMap() {
113         return objectMap;
114     }
115
116     /**
117      * Add a property to the properties of this execution context. If the property
118      * exists already, it is overwritten.
119      */

120     public void addSubstitutionProperty(String key, String value) {
121         if (key == null || value == null) {
122             return;
123         }
124         // values with leading or trailing spaces are bad. We remove them now.
125         value = value.trim();
126         propertiesMap.put(key, value);
127     }
128
129     public void addSubstitutionProperties(Properties props) {
130         if (props == null) {
131             return;
132         }
133         for (Object keyObject : props.keySet()) {
134             String key = (String) keyObject;
135             String val = props.getProperty(key);
136             addSubstitutionProperty(key, val);
137         }
138     }
139
140     /**
141      * If a key is found in propertiesMap then return it. Otherwise, delegate to
142      * the context.
143      */

144     public String getProperty(String key) {
145         String v = propertiesMap.get(key);
146         if (v != null) {
147             return v;
148         } else {
149             return context.getProperty(key);
150         }
151     }
152
153     public String subst(String value) {
154         if (value == null) {
155             return null;
156         }
157         return OptionHelper.substVars(value, this, context);
158     }
159
160     public boolean isListenerListEmpty() {
161         return listenerList.isEmpty();
162     }
163
164     public void addInPlayListener(InPlayListener ipl) {
165         if (listenerList.contains(ipl)) {
166             addWarn("InPlayListener " + ipl + " has been already registered");
167         } else {
168             listenerList.add(ipl);
169         }
170     }
171
172     public boolean removeInPlayListener(InPlayListener ipl) {
173         return listenerList.remove(ipl);
174     }
175
176     void fireInPlay(SaxEvent event) {
177         for (InPlayListener ipl : listenerList) {
178             ipl.inPlay(event);
179         }
180     }
181 }
182