1
2
3
4
5
6
7
8
9
10
11
12 package ch.qos.logback.core.joran;
13
14 import static ch.qos.logback.core.CoreConstants.SAFE_JORAN_CONFIGURATION;
15 import static ch.qos.logback.core.spi.ConfigurationEvent.*;
16
17 import java.io.File;
18 import java.io.FileInputStream;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.URL;
22 import java.net.URLConnection;
23 import java.util.List;
24 import java.util.concurrent.locks.ReentrantLock;
25
26 import org.xml.sax.InputSource;
27
28 import ch.qos.logback.core.Context;
29 import ch.qos.logback.core.joran.event.SaxEvent;
30 import ch.qos.logback.core.joran.event.SaxEventRecorder;
31 import ch.qos.logback.core.joran.spi.DefaultNestedComponentRegistry;
32 import ch.qos.logback.core.joran.spi.ElementPath;
33 import ch.qos.logback.core.joran.spi.SaxEventInterpretationContext;
34 import ch.qos.logback.core.joran.spi.JoranException;
35 import ch.qos.logback.core.joran.spi.RuleStore;
36 import ch.qos.logback.core.joran.spi.SaxEventInterpreter;
37 import ch.qos.logback.core.joran.spi.SimpleRuleStore;
38 import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil;
39 import ch.qos.logback.core.model.Model;
40 import ch.qos.logback.core.model.processor.DefaultProcessor;
41 import ch.qos.logback.core.model.processor.ModelInterpretationContext;
42 import ch.qos.logback.core.spi.ContextAwareBase;
43 import ch.qos.logback.core.spi.ErrorCodes;
44 import ch.qos.logback.core.status.StatusUtil;
45
46 public abstract class GenericXMLConfigurator extends ContextAwareBase {
47
48 protected SaxEventInterpreter saxEventInterpreter;
49 protected ModelInterpretationContext modelInterpretationContext;
50
51 public ModelInterpretationContext getModelInterpretationContext() {
52 return this.modelInterpretationContext;
53 }
54 private RuleStore ruleStore;
55
56 public URL getTopURL() {
57 return topURL;
58 }
59
60 public void setTopURL(URL topURL) {
61 this.topURL = topURL;
62 }
63
64 URL topURL;
65
66 public final void doConfigure(URL url) throws JoranException {
67 InputStream in = null;
68 try {
69 topURL = url;
70 URLConnection urlConnection = url.openConnection();
71
72
73 urlConnection.setUseCaches(false);
74
75 in = urlConnection.getInputStream();
76 doConfigure(in, url.toExternalForm());
77 } catch (IOException ioe) {
78 String errMsg = "Could not open URL [" + url + "].";
79 addError(errMsg, ioe);
80 throw new JoranException(errMsg, ioe);
81 } finally {
82 if (in != null) {
83 try {
84 in.close();
85 } catch (IOException ioe) {
86 String errMsg = "Could not close input stream";
87 addError(errMsg, ioe);
88 throw new JoranException(errMsg, ioe);
89 }
90 }
91 }
92 }
93
94 public final void doConfigure(String filename) throws JoranException {
95 doConfigure(new File(filename));
96 }
97
98 public final void doConfigure(File file) throws JoranException {
99 FileInputStream fis = null;
100 try {
101 URL url = file.toURI().toURL();
102 topURL = url;
103 fis = new FileInputStream(file);
104 doConfigure(fis, url.toExternalForm());
105 } catch (IOException ioe) {
106 String errMsg = "Could not open [" + file.getPath() + "].";
107 addError(errMsg, ioe);
108 throw new JoranException(errMsg, ioe);
109 } finally {
110 if (fis != null) {
111 try {
112 fis.close();
113 } catch (java.io.IOException ioe) {
114 String errMsg = "Could not close [" + file.getName() + "].";
115 addError(errMsg, ioe);
116 throw new JoranException(errMsg, ioe);
117 }
118 }
119 }
120 }
121
122
123
124
125
126
127 @Deprecated
128 public static void informContextOfURLUsedForConfiguration(Context context, URL url) {
129
130 }
131
132 public final void doConfigure(InputStream inputStream) throws JoranException {
133 doConfigure(new InputSource(inputStream));
134 }
135
136 public final void doConfigure(InputStream inputStream, String systemId) throws JoranException {
137 InputSource inputSource = new InputSource(inputStream);
138 inputSource.setSystemId(systemId);
139 doConfigure(inputSource);
140 }
141
142 protected abstract void addElementSelectorAndActionAssociations(RuleStore rs);
143
144 protected abstract void setImplicitRuleSupplier(SaxEventInterpreter interpreter);
145
146 protected void addDefaultNestedComponentRegistryRules(DefaultNestedComponentRegistry registry) {
147
148 }
149
150 protected ElementPath initialElementPath() {
151 return new ElementPath();
152 }
153
154 protected void buildSaxEventInterpreter(List<SaxEvent> saxEvents) {
155 RuleStore rs = getRuleStore();
156 addElementSelectorAndActionAssociations(rs);
157 this.saxEventInterpreter = new SaxEventInterpreter(context, rs, initialElementPath(), saxEvents);
158 SaxEventInterpretationContext interpretationContext = saxEventInterpreter.getSaxEventInterpretationContext();
159 interpretationContext.setContext(context);
160 setImplicitRuleSupplier(saxEventInterpreter);
161 }
162
163 public RuleStore getRuleStore() {
164 if(this.ruleStore == null) {
165 this.ruleStore = new SimpleRuleStore(context);
166 }
167 return this.ruleStore;
168 }
169
170 protected void buildModelInterpretationContext() {
171 this.modelInterpretationContext = new ModelInterpretationContext(context);
172 this.modelInterpretationContext.setTopURL(topURL);
173 addDefaultNestedComponentRegistryRules(modelInterpretationContext.getDefaultNestedComponentRegistry());
174 }
175
176
177
178 public final void doConfigure(final InputSource inputSource) throws JoranException {
179
180 context.fireConfigurationEvent(newConfigurationStartedEvent(this));
181 long threshold = System.currentTimeMillis();
182
183 SaxEventRecorder recorder = populateSaxEventRecorder(inputSource);
184 List<SaxEvent> saxEvents = recorder.getSaxEventList();
185 if (saxEvents.isEmpty()) {
186 addWarn("Empty sax event list");
187 return;
188 }
189 Model top = buildModelFromSaxEventList(recorder.getSaxEventList());
190 if (top == null) {
191 addError(ErrorCodes.EMPTY_MODEL_STACK);
192 return;
193 }
194 sanityCheck(top);
195 processModel(top);
196
197
198 StatusUtil statusUtil = new StatusUtil(context);
199 if (statusUtil.noXMLParsingErrorsOccurred(threshold)) {
200 addInfo("Registering current configuration as safe fallback point");
201 registerSafeConfiguration(top);
202 context.fireConfigurationEvent(newConfigurationEndedSuccessfullyEvent(this));
203 } else {
204 context.fireConfigurationEvent(newConfigurationEndedWithXMLParsingErrorsEvent(this));
205 }
206
207
208 }
209
210 public SaxEventRecorder populateSaxEventRecorder(final InputSource inputSource) throws JoranException {
211 SaxEventRecorder recorder = new SaxEventRecorder(context);
212 recorder.recordEvents(inputSource);
213 return recorder;
214 }
215
216 public Model buildModelFromSaxEventList(List<SaxEvent> saxEvents) throws JoranException {
217 buildSaxEventInterpreter(saxEvents);
218 playSaxEvents();
219 Model top = saxEventInterpreter.getSaxEventInterpretationContext().peekModel();
220 return top;
221 }
222
223 private void playSaxEvents() throws JoranException {
224 saxEventInterpreter.getEventPlayer().play();
225 }
226
227 public void processModel(Model model) {
228 buildModelInterpretationContext();
229 this.modelInterpretationContext.setTopModel(model);
230 modelInterpretationContext.setConfiguratorHint(this);
231 DefaultProcessor defaultProcessor = new DefaultProcessor(context, this.modelInterpretationContext);
232 addModelHandlerAssociations(defaultProcessor);
233
234
235 ReentrantLock configurationLock = context.getConfigurationLock();
236
237 try {
238 configurationLock.lock();
239 defaultProcessor.process(model);
240 } finally {
241 configurationLock.unlock();
242 }
243 }
244
245
246
247
248
249
250
251
252
253 protected void sanityCheck(Model topModel) {
254
255 }
256
257 protected void addModelHandlerAssociations(DefaultProcessor defaultProcessor) {
258 }
259
260
261
262
263
264
265
266 public void registerSafeConfiguration(Model top) {
267 context.putObject(SAFE_JORAN_CONFIGURATION, top);
268 }
269
270
271
272
273 public Model recallSafeConfiguration() {
274 return (Model) context.getObject(SAFE_JORAN_CONFIGURATION);
275 }
276
277 }