1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.core.model.processor;
15
16 import java.lang.reflect.Constructor;
17 import java.lang.reflect.InvocationTargetException;
18 import java.util.HashMap;
19 import java.util.List;
20
21 import ch.qos.logback.core.Context;
22 import ch.qos.logback.core.joran.util.beans.BeanDescriptionCache;
23 import ch.qos.logback.core.model.Model;
24 import ch.qos.logback.core.model.ModelFactoryMethod;
25 import ch.qos.logback.core.model.NamedComponentModel;
26 import ch.qos.logback.core.spi.ContextAwareBase;
27 import ch.qos.logback.core.spi.FilterReply;
28
29
30
31
32
33
34
35
36 public class DefaultProcessor extends ContextAwareBase {
37
38 interface TraverseMethod {
39 int traverse(Model model, ModelFilter modelFiler);
40 }
41
42 final ModelInterpretationContext mic;
43 final HashMap<Class<? extends Model>, ModelFactoryMethod> modelClassToHandlerMap = new HashMap<>();
44 final HashMap<Class<? extends Model>, ModelHandlerBase> modelClassToDependencyAnalyserMap = new HashMap<>();
45
46 ModelFilter phaseOneFilter = new AllowAllModelFilter();
47 ModelFilter phaseTwoFilter = new DenyAllModelFilter();
48
49 public DefaultProcessor(Context context, ModelInterpretationContext mic) {
50 this.setContext(context);
51 this.mic = mic;
52 }
53
54 public void addHandler(Class<? extends Model> modelClass, ModelFactoryMethod modelFactoryMethod) {
55 modelClassToHandlerMap.put(modelClass, modelFactoryMethod);
56 }
57
58 public void addAnalyser(Class<? extends Model> modelClass, ModelHandlerBase handler) {
59 modelClassToDependencyAnalyserMap.put(modelClass, handler);
60 }
61
62 private void traversalLoop(TraverseMethod traverseMethod, Model model, ModelFilter modelfFilter, String phaseName) {
63 int LIMIT = 3;
64 for (int i = 0; i < LIMIT; i++) {
65 int handledModelCount = traverseMethod.traverse(model, modelfFilter);
66 if (handledModelCount == 0)
67 break;
68 }
69 }
70
71 public void process(Model model) {
72
73 if (model == null) {
74 addError("Expecting non null model to process");
75 return;
76 }
77 initialObjectPush();
78
79 mainTraverse(model, getPhaseOneFilter());
80 analyseDependencies(model);
81 traversalLoop(this::secondPhaseTraverse, model, getPhaseTwoFilter(), "phase 2");
82
83 addInfo("End of configuration.");
84 finalObjectPop();
85 }
86
87 private void finalObjectPop() {
88 mic.popObject();
89 }
90
91 private void initialObjectPush() {
92 mic.pushObject(context);
93 }
94
95 public ModelFilter getPhaseOneFilter() {
96 return phaseOneFilter;
97 }
98
99 public ModelFilter getPhaseTwoFilter() {
100 return phaseTwoFilter;
101 }
102
103 public void setPhaseOneFilter(ModelFilter phaseOneFilter) {
104 this.phaseOneFilter = phaseOneFilter;
105 }
106
107 public void setPhaseTwoFilter(ModelFilter phaseTwoFilter) {
108 this.phaseTwoFilter = phaseTwoFilter;
109 }
110
111 protected void analyseDependencies(Model model) {
112 ModelHandlerBase handler = modelClassToDependencyAnalyserMap.get(model.getClass());
113
114 if (handler != null) {
115 try {
116 handler.handle(mic, model);
117 } catch (ModelHandlerException e) {
118 addError("Failed to traverse model " + model.getTag(), e);
119 }
120 }
121
122 for (Model m : model.getSubModels()) {
123 analyseDependencies(m);
124 }
125 if (handler != null) {
126 try {
127 handler.postHandle(mic, model);
128 } catch (ModelHandlerException e) {
129 addError("Failed to invole postHandle on model " + model.getTag(), e);
130 }
131 }
132 }
133
134 static final int DENIED = -1;
135
136 private ModelHandlerBase createHandler(Model model) {
137 ModelFactoryMethod modelFactoryMethod = modelClassToHandlerMap.get(model.getClass());
138
139 if (modelFactoryMethod == null) {
140 addError("Can't handle model of type " + model.getClass() + " with tag: " + model.getTag() + " at line "
141 + model.getLineNumber());
142 return null;
143 }
144
145 ModelHandlerBase handler = modelFactoryMethod.make(context, mic);
146 if (handler == null)
147 return null;
148 if (!handler.isSupportedModelType(model)) {
149 addWarn("Handler [" + handler.getClass() + "] does not support " + model.idString());
150 return null;
151 }
152 return handler;
153 }
154
155 protected int mainTraverse(Model model, ModelFilter modelFiler) {
156
157 FilterReply filterReply = modelFiler.decide(model);
158 if (filterReply == FilterReply.DENY)
159 return DENIED;
160
161 int count = 0;
162
163 try {
164 ModelHandlerBase handler = null;
165 if (model.isUnhandled()) {
166 handler = createHandler(model);
167 if (handler != null) {
168 handler.handle(mic, model);
169 model.markAsHandled();
170 count++;
171 }
172 }
173
174
175 if (!model.isSkipped()) {
176 for (Model m : model.getSubModels()) {
177 count += mainTraverse(m, modelFiler);
178 }
179 }
180 if (handler != null) {
181 handler.postHandle(mic, model);
182 }
183 } catch (ModelHandlerException e) {
184 addError("Failed to traverse model " + model.getTag(), e);
185 }
186 return count;
187 }
188
189 protected int secondPhaseTraverse(Model model, ModelFilter modelFilter) {
190
191 FilterReply filterReply = modelFilter.decide(model);
192 if (filterReply == FilterReply.DENY) {
193 return 0;
194 }
195
196 int count = 0;
197
198 try {
199
200 boolean allDependenciesStarted = allDependenciesStarted(model);
201
202 ModelHandlerBase handler = null;
203 if (model.isUnhandled() && allDependenciesStarted) {
204 handler = createHandler(model);
205 if (handler != null) {
206 handler.handle(mic, model);
207 model.markAsHandled();
208 count++;
209 }
210 }
211
212 if (!allDependenciesStarted && !dependencyIsADirectSubmodel(model)) {
213 return count;
214 }
215
216 if (!model.isSkipped()) {
217 for (Model m : model.getSubModels()) {
218 count += secondPhaseTraverse(m, modelFilter);
219 }
220 }
221 if (handler != null) {
222 handler.postHandle(mic, model);
223 }
224 } catch (ModelHandlerException e) {
225 addError("Failed to traverse model " + model.getTag(), e);
226 }
227 return count;
228 }
229
230 private boolean dependencyIsADirectSubmodel(Model model) {
231 List<String> dependecyNames = this.mic.getDependeeNamesForModel(model);
232 if (dependecyNames == null || dependecyNames.isEmpty()) {
233 return false;
234 }
235 for (Model submodel : model.getSubModels()) {
236 if (submodel instanceof NamedComponentModel) {
237 NamedComponentModel namedComponentModel = (NamedComponentModel) submodel;
238 String subModelName = namedComponentModel.getName();
239 if (dependecyNames.contains(subModelName)) {
240 return true;
241 }
242 }
243 }
244
245 return false;
246 }
247
248 private boolean allDependenciesStarted(Model model) {
249 List<String> dependencyNames = mic.getDependeeNamesForModel(model);
250
251 if (dependencyNames == null || dependencyNames.isEmpty()) {
252 return true;
253 }
254 for (String name : dependencyNames) {
255 boolean isStarted = mic.isNamedDependeeStarted(name);
256 if (isStarted == false) {
257 return false;
258 }
259 }
260 return true;
261 }
262
263 ModelHandlerBase instantiateHandler(Class<? extends ModelHandlerBase> handlerClass) {
264 try {
265 Constructor<? extends ModelHandlerBase> commonConstructor = getWithContextConstructor(handlerClass);
266 if (commonConstructor != null) {
267 return commonConstructor.newInstance(context);
268 }
269 Constructor<? extends ModelHandlerBase> constructorWithBDC = getWithContextAndBDCConstructor(handlerClass);
270 if (constructorWithBDC != null) {
271 return constructorWithBDC.newInstance(context, mic.getBeanDescriptionCache());
272 }
273 addError("Failed to find suitable constructor for class [" + handlerClass + "]");
274 return null;
275 } catch (InstantiationException | IllegalAccessException | SecurityException | IllegalArgumentException
276 | InvocationTargetException e1) {
277 addError("Failed to instantiate " + handlerClass);
278 return null;
279 }
280 }
281
282 private Constructor<? extends ModelHandlerBase> getWithContextConstructor(
283 Class<? extends ModelHandlerBase> handlerClass) {
284 try {
285 Constructor<? extends ModelHandlerBase> constructor = handlerClass.getConstructor(Context.class);
286 return constructor;
287 } catch (NoSuchMethodException e) {
288 return null;
289 }
290 }
291
292 private Constructor<? extends ModelHandlerBase> getWithContextAndBDCConstructor(
293 Class<? extends ModelHandlerBase> handlerClass) {
294 try {
295 Constructor<? extends ModelHandlerBase> constructor = handlerClass.getConstructor(Context.class,
296 BeanDescriptionCache.class);
297 return constructor;
298 } catch (NoSuchMethodException e) {
299 return null;
300 }
301 }
302
303 }