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 final void doConfigure(URL url) throws JoranException {
57 InputStream in = null;
58 try {
59 informContextOfURLUsedForConfiguration(getContext(), url);
60 URLConnection urlConnection = url.openConnection();
61
62
63 urlConnection.setUseCaches(false);
64
65 in = urlConnection.getInputStream();
66 doConfigure(in, url.toExternalForm());
67 } catch (IOException ioe) {
68 String errMsg = "Could not open URL [" + url + "].";
69 addError(errMsg, ioe);
70 throw new JoranException(errMsg, ioe);
71 } finally {
72 if (in != null) {
73 try {
74 in.close();
75 } catch (IOException ioe) {
76 String errMsg = "Could not close input stream";
77 addError(errMsg, ioe);
78 throw new JoranException(errMsg, ioe);
79 }
80 }
81 }
82 }
83
84 public final void doConfigure(String filename) throws JoranException {
85 doConfigure(new File(filename));
86 }
87
88 public final void doConfigure(File file) throws JoranException {
89 FileInputStream fis = null;
90 try {
91 URL url = file.toURI().toURL();
92 informContextOfURLUsedForConfiguration(getContext(), url);
93 fis = new FileInputStream(file);
94 doConfigure(fis, url.toExternalForm());
95 } catch (IOException ioe) {
96 String errMsg = "Could not open [" + file.getPath() + "].";
97 addError(errMsg, ioe);
98 throw new JoranException(errMsg, ioe);
99 } finally {
100 if (fis != null) {
101 try {
102 fis.close();
103 } catch (java.io.IOException ioe) {
104 String errMsg = "Could not close [" + file.getName() + "].";
105 addError(errMsg, ioe);
106 throw new JoranException(errMsg, ioe);
107 }
108 }
109 }
110 }
111
112 public static void informContextOfURLUsedForConfiguration(Context context, URL url) {
113 ConfigurationWatchListUtil.setMainWatchURL(context, url);
114 }
115
116 public final void doConfigure(InputStream inputStream) throws JoranException {
117 doConfigure(new InputSource(inputStream));
118 }
119
120 public final void doConfigure(InputStream inputStream, String systemId) throws JoranException {
121 InputSource inputSource = new InputSource(inputStream);
122 inputSource.setSystemId(systemId);
123 doConfigure(inputSource);
124 }
125
126 protected abstract void addElementSelectorAndActionAssociations(RuleStore rs);
127
128 protected abstract void setImplicitRuleSupplier(SaxEventInterpreter interpreter);
129
130 protected void addDefaultNestedComponentRegistryRules(DefaultNestedComponentRegistry registry) {
131
132 }
133
134 protected ElementPath initialElementPath() {
135 return new ElementPath();
136 }
137
138 protected void buildSaxEventInterpreter(List<SaxEvent> saxEvents) {
139 RuleStore rs = getRuleStore();
140 addElementSelectorAndActionAssociations(rs);
141 this.saxEventInterpreter = new SaxEventInterpreter(context, rs, initialElementPath(), saxEvents);
142 SaxEventInterpretationContext interpretationContext = saxEventInterpreter.getSaxEventInterpretationContext();
143 interpretationContext.setContext(context);
144 setImplicitRuleSupplier(saxEventInterpreter);
145 }
146
147 public RuleStore getRuleStore() {
148 if(this.ruleStore == null) {
149 this.ruleStore = new SimpleRuleStore(context);
150 }
151 return this.ruleStore;
152 }
153
154 protected void buildModelInterpretationContext() {
155 this.modelInterpretationContext = new ModelInterpretationContext(context);
156 addDefaultNestedComponentRegistryRules(modelInterpretationContext.getDefaultNestedComponentRegistry());
157 }
158
159
160
161 public final void doConfigure(final InputSource inputSource) throws JoranException {
162
163 context.fireConfigurationEvent(newConfigurationStartedEvent(this));
164 long threshold = System.currentTimeMillis();
165
166 SaxEventRecorder recorder = populateSaxEventRecorder(inputSource);
167 List<SaxEvent> saxEvents = recorder.getSaxEventList();
168 if (saxEvents.isEmpty()) {
169 addWarn("Empty sax event list");
170 return;
171 }
172 Model top = buildModelFromSaxEventList(recorder.getSaxEventList());
173 if (top == null) {
174 addError(ErrorCodes.EMPTY_MODEL_STACK);
175 return;
176 }
177 sanityCheck(top);
178 processModel(top);
179
180
181 StatusUtil statusUtil = new StatusUtil(context);
182 if (statusUtil.noXMLParsingErrorsOccurred(threshold)) {
183 addInfo("Registering current configuration as safe fallback point");
184 registerSafeConfiguration(top);
185 context.fireConfigurationEvent(newConfigurationEndedSuccessfullyEvent(this));
186 } else {
187 context.fireConfigurationEvent(newConfigurationEndedWithXMLParsingErrorsEvent(this));
188 }
189
190
191 }
192
193 public SaxEventRecorder populateSaxEventRecorder(final InputSource inputSource) throws JoranException {
194 SaxEventRecorder recorder = new SaxEventRecorder(context);
195 recorder.recordEvents(inputSource);
196 return recorder;
197 }
198
199 public Model buildModelFromSaxEventList(List<SaxEvent> saxEvents) throws JoranException {
200 buildSaxEventInterpreter(saxEvents);
201 playSaxEvents();
202 Model top = saxEventInterpreter.getSaxEventInterpretationContext().peekModel();
203 return top;
204 }
205
206 private void playSaxEvents() throws JoranException {
207 saxEventInterpreter.getEventPlayer().play();
208 }
209
210 public void processModel(Model model) {
211 buildModelInterpretationContext();
212 this.modelInterpretationContext.setTopModel(model);
213 modelInterpretationContext.setConfiguratorHint(this);
214 DefaultProcessor defaultProcessor = new DefaultProcessor(context, this.modelInterpretationContext);
215 addModelHandlerAssociations(defaultProcessor);
216
217
218 ReentrantLock configurationLock = context.getConfigurationLock();
219
220 try {
221 configurationLock.lock();
222 defaultProcessor.process(model);
223 } finally {
224 configurationLock.unlock();
225 }
226 }
227
228
229
230
231
232
233
234
235
236 protected void sanityCheck(Model topModel) {
237
238 }
239
240 protected void addModelHandlerAssociations(DefaultProcessor defaultProcessor) {
241 }
242
243
244
245
246
247
248
249 public void registerSafeConfiguration(Model top) {
250 context.putObject(SAFE_JORAN_CONFIGURATION, top);
251 }
252
253
254
255
256 public Model recallSafeConfiguration() {
257 return (Model) context.getObject(SAFE_JORAN_CONFIGURATION);
258 }
259 }