1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.classic.joran;
15
16 import java.io.File;
17 import java.net.URL;
18 import java.util.ArrayList;
19 import java.util.List;
20
21 import ch.qos.logback.classic.LoggerContext;
22 import ch.qos.logback.core.CoreConstants;
23 import ch.qos.logback.core.joran.spi.ConfigurationWatchList;
24 import ch.qos.logback.core.joran.spi.JoranException;
25 import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil;
26 import ch.qos.logback.core.model.Model;
27 import ch.qos.logback.core.model.ModelUtil;
28 import ch.qos.logback.core.spi.ContextAwareBase;
29 import ch.qos.logback.core.status.StatusUtil;
30
31 public class ReconfigureOnChangeTask extends ContextAwareBase implements Runnable {
32
33 public static final String DETECTED_CHANGE_IN_CONFIGURATION_FILES = "Detected change in configuration files.";
34 static final String RE_REGISTERING_PREVIOUS_SAFE_CONFIGURATION = "Re-registering previous fallback configuration once more as a fallback configuration point";
35 static final String FALLING_BACK_TO_SAFE_CONFIGURATION = "Given previous errors, falling back to previously registered safe configuration.";
36
37 long birthdate = System.currentTimeMillis();
38 List<ReconfigureOnChangeTaskListener> listeners = null;
39
40 void addListener(ReconfigureOnChangeTaskListener listener) {
41 if (listeners == null)
42 listeners = new ArrayList<ReconfigureOnChangeTaskListener>(1);
43 listeners.add(listener);
44 }
45
46 @Override
47 public void run() {
48 fireEnteredRunMethod();
49
50 ConfigurationWatchList configurationWatchList = ConfigurationWatchListUtil.getConfigurationWatchList(context);
51 if (configurationWatchList == null) {
52 addWarn("Empty ConfigurationWatchList in context");
53 return;
54 }
55
56 List<File> filesToWatch = configurationWatchList.getCopyOfFileWatchList();
57 if (filesToWatch == null || filesToWatch.isEmpty()) {
58 addInfo("Empty watch file list. Disabling ");
59 return;
60 }
61
62 if (!configurationWatchList.changeDetected()) {
63 return;
64 }
65 fireChangeDetected();
66 URL mainConfigurationURL = configurationWatchList.getMainURL();
67
68 addInfo(DETECTED_CHANGE_IN_CONFIGURATION_FILES);
69 addInfo(CoreConstants.RESET_MSG_PREFIX + "named [" + context.getName() + "]");
70
71 LoggerContext lc = (LoggerContext) context;
72 if (mainConfigurationURL.toString().endsWith("xml")) {
73 performXMLConfiguration(lc, mainConfigurationURL);
74 } else if (mainConfigurationURL.toString().endsWith("groovy")) {
75 addError("Groovy configuration disabled due to Java 9 compilation issues.");
76 }
77 fireDoneReconfiguring();
78 }
79
80 private void fireEnteredRunMethod() {
81 if (listeners == null)
82 return;
83
84 for (ReconfigureOnChangeTaskListener listener : listeners)
85 listener.enteredRunMethod();
86 }
87
88 private void fireChangeDetected() {
89 if (listeners == null)
90 return;
91
92 for (ReconfigureOnChangeTaskListener listener : listeners)
93 listener.changeDetected();
94 }
95
96 private void fireDoneReconfiguring() {
97 if (listeners == null)
98 return;
99
100 for (ReconfigureOnChangeTaskListener listener : listeners)
101 listener.doneReconfiguring();
102 }
103
104 private void performXMLConfiguration(LoggerContext lc, URL mainConfigurationURL) {
105 JoranConfigurator jc = new JoranConfigurator();
106 jc.setContext(context);
107 StatusUtil statusUtil = new StatusUtil(context);
108 Model failsafeTop = jc.recallSafeConfiguration();
109 URL mainURL = ConfigurationWatchListUtil.getMainWatchURL(context);
110 lc.reset();
111 long threshold = System.currentTimeMillis();
112 try {
113 jc.doConfigure(mainConfigurationURL);
114 if (statusUtil.hasXMLParsingErrors(threshold)) {
115 fallbackConfiguration(lc, failsafeTop, mainURL);
116 }
117 } catch (JoranException e) {
118 fallbackConfiguration(lc, failsafeTop, mainURL);
119 }
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 private void fallbackConfiguration(LoggerContext lc, Model failsafeTop, URL mainURL) {
136
137
138
139
140 JoranConfigurator joranConfigurator = new JoranConfigurator();
141 joranConfigurator.setContext(context);
142 ConfigurationWatchList oldCWL = ConfigurationWatchListUtil.getConfigurationWatchList(context);
143 ConfigurationWatchList newCWL = oldCWL.buildClone();
144
145 if (failsafeTop == null) {
146 addWarn("No previous configuration to fall back on.");
147 return;
148 } else {
149 addWarn(FALLING_BACK_TO_SAFE_CONFIGURATION);
150 addInfo("Safe model "+failsafeTop);
151 try {
152 lc.reset();
153 ConfigurationWatchListUtil.registerConfigurationWatchList(context, newCWL);
154 ModelUtil.resetForReuse(failsafeTop);
155 joranConfigurator.processModel(failsafeTop);
156 addInfo(RE_REGISTERING_PREVIOUS_SAFE_CONFIGURATION);
157 joranConfigurator.registerSafeConfiguration(failsafeTop);
158
159 addInfo("after registerSafeConfiguration");
160 } catch (Exception e) {
161 addError("Unexpected exception thrown by a configuration considered safe.", e);
162 }
163 }
164 }
165
166 @Override
167 public String toString() {
168 return "ReconfigureOnChangeTask(born:" + birthdate + ")";
169 }
170 }