1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.config;
18
19 import org.apache.logging.log4j.Logger;
20 import org.apache.logging.log4j.core.config.plugins.PluginManager;
21 import org.apache.logging.log4j.core.config.plugins.PluginType;
22 import org.apache.logging.log4j.core.helpers.FileUtils;
23 import org.apache.logging.log4j.core.helpers.Loader;
24 import org.apache.logging.log4j.status.StatusLogger;
25 import org.apache.logging.log4j.util.PropertiesUtil;
26
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileNotFoundException;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.net.MalformedURLException;
33 import java.net.URI;
34 import java.net.URISyntaxException;
35 import java.net.URL;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.TreeSet;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public abstract class ConfigurationFactory {
66
67
68
69 public static final String CONFIGURATION_FACTORY_PROPERTY = "log4j.configurationFactory";
70
71
72
73
74 public static final String CONFIGURATION_FILE_PROPERTY = "log4j.configurationFile";
75
76
77
78
79 protected static final Logger LOGGER = StatusLogger.getLogger();
80
81
82
83
84 protected static final String TEST_PREFIX = "log4j2-test";
85
86
87
88
89 protected static final String DEFAULT_PREFIX = "log4j2";
90
91 private static volatile List<ConfigurationFactory> factories = null;
92
93 private static ConfigurationFactory configFactory = new Factory();
94
95
96
97
98
99 public static ConfigurationFactory getInstance() {
100 if (factories == null) {
101 synchronized(TEST_PREFIX) {
102 if (factories == null) {
103 List<ConfigurationFactory> list = new ArrayList<ConfigurationFactory>();
104 final String factoryClass = PropertiesUtil.getProperties().getStringProperty(CONFIGURATION_FACTORY_PROPERTY);
105 if (factoryClass != null) {
106 addFactory(list, factoryClass);
107 }
108 final PluginManager manager = new PluginManager("ConfigurationFactory");
109 manager.collectPlugins();
110 final Map<String, PluginType> plugins = manager.getPlugins();
111 final Set<WeightedFactory> ordered = new TreeSet<WeightedFactory>();
112 for (final PluginType type : plugins.values()) {
113 try {
114 @SuppressWarnings("unchecked")
115 final Class<ConfigurationFactory> clazz = (Class<ConfigurationFactory>)type.getPluginClass();
116 final Order order = clazz.getAnnotation(Order.class);
117 if (order != null) {
118 final Integer weight = order.value();
119 ordered.add(new WeightedFactory(weight, clazz));
120 }
121 } catch (final Exception ex) {
122 LOGGER.warn("Unable to add class " + type.getPluginClass());
123 }
124 }
125 for (final WeightedFactory wf : ordered) {
126 addFactory(list, wf.factoryClass);
127 }
128 factories = Collections.unmodifiableList(list);
129 }
130 }
131 }
132
133 return configFactory;
134 }
135
136 @SuppressWarnings("unchecked")
137 private static void addFactory(final List<ConfigurationFactory> list, final String factoryClass) {
138 try {
139 addFactory(list, (Class<ConfigurationFactory>) Class.forName(factoryClass));
140 } catch (final ClassNotFoundException ex) {
141 LOGGER.error("Unable to load class " + factoryClass, ex);
142 } catch (final Exception ex) {
143 LOGGER.error("Unable to load class " + factoryClass, ex);
144 }
145 }
146
147 private static void addFactory(final List<ConfigurationFactory> list,
148 final Class<ConfigurationFactory> factoryClass) {
149 try {
150 list.add(factoryClass.newInstance());
151 } catch (final Exception ex) {
152 LOGGER.error("Unable to create instance of " + factoryClass.getName(), ex);
153 }
154 }
155
156
157
158
159
160 public static void setConfigurationFactory(final ConfigurationFactory factory) {
161 configFactory = factory;
162 }
163
164
165
166
167
168 public static void resetConfigurationFactory() {
169 configFactory = new Factory();
170 }
171
172
173
174
175
176 public static void removeConfigurationFactory(final ConfigurationFactory factory) {
177 if (configFactory == factory) {
178 configFactory = new Factory();
179 }
180 }
181
182 protected abstract String[] getSupportedTypes();
183
184 protected boolean isActive() {
185 return true;
186 }
187
188 public abstract Configuration getConfiguration(ConfigurationSource source);
189
190
191
192
193
194
195
196 public Configuration getConfiguration(final String name, final URI configLocation) {
197 if (!isActive()) {
198 return null;
199 }
200 if (configLocation != null) {
201 final ConfigurationSource source = getInputFromURI(configLocation);
202 if (source != null) {
203 return getConfiguration(source);
204 }
205 }
206 return null;
207 }
208
209
210
211
212
213
214 protected ConfigurationSource getInputFromURI(final URI configLocation) {
215 final File configFile = FileUtils.fileFromURI(configLocation);
216 if (configFile != null && configFile.exists() && configFile.canRead()) {
217 try {
218 return new ConfigurationSource(new FileInputStream(configFile), configFile);
219 } catch (final FileNotFoundException ex) {
220 LOGGER.error("Cannot locate file " + configLocation.getPath(), ex);
221 }
222 }
223 final String scheme = configLocation.getScheme();
224 if (scheme == null || scheme.equals("classloader")) {
225 final ClassLoader loader = this.getClass().getClassLoader();
226 final ConfigurationSource source = getInputFromResource(configLocation.getPath(), loader);
227 if (source != null) {
228 return source;
229 }
230 }
231 try {
232 return new ConfigurationSource(configLocation.toURL().openStream(), configLocation.getPath());
233 } catch (final MalformedURLException ex) {
234 LOGGER.error("Invalid URL " + configLocation.toString(), ex);
235 } catch (final IOException ex) {
236 LOGGER.error("Unable to access " + configLocation.toString(), ex);
237 } catch (final Exception ex) {
238 LOGGER.error("Unable to access " + configLocation.toString(), ex);
239 }
240 return null;
241 }
242
243
244
245
246
247
248
249 protected ConfigurationSource getInputFromString(final String config, final ClassLoader loader) {
250 try {
251 final URL url = new URL(config);
252 return new ConfigurationSource(url.openStream(), FileUtils.fileFromURI(url.toURI()));
253 } catch (final Exception ex) {
254 final ConfigurationSource source = getInputFromResource(config, loader);
255 if (source == null) {
256 try {
257 final File file = new File(config);
258 return new ConfigurationSource(new FileInputStream(file), file);
259 } catch (final FileNotFoundException fnfe) {
260
261 }
262 }
263 return source;
264 }
265 }
266
267
268
269
270
271
272
273 protected ConfigurationSource getInputFromResource(final String resource, final ClassLoader loader) {
274 final URL url = Loader.getResource(resource, loader);
275 if (url == null) {
276 return null;
277 }
278 InputStream is = null;
279 try {
280 is = url.openStream();
281 } catch (final IOException ioe) {
282 return null;
283 }
284 if (is == null) {
285 return null;
286 }
287
288 if (FileUtils.isFile(url)) {
289 try {
290 return new ConfigurationSource(is, FileUtils.fileFromURI((url.toURI())));
291 } catch (final URISyntaxException ex) {
292
293 }
294 }
295 return new ConfigurationSource(is, resource);
296 }
297
298
299
300
301 private static class WeightedFactory implements Comparable<WeightedFactory> {
302 private final int weight;
303 private final Class<ConfigurationFactory> factoryClass;
304
305
306
307
308
309
310 public WeightedFactory(final int weight, final Class<ConfigurationFactory> clazz) {
311 this.weight = weight;
312 this.factoryClass = clazz;
313 }
314
315 @Override
316 public int compareTo(final WeightedFactory wf) {
317 final int w = wf.weight;
318 if (weight == w) {
319 return 0;
320 } else if (weight > w) {
321 return -1;
322 } else {
323 return 1;
324 }
325 }
326 }
327
328
329
330
331 private static class Factory extends ConfigurationFactory {
332
333
334
335
336
337
338
339 @Override
340 public Configuration getConfiguration(final String name, final URI configLocation) {
341
342 if (configLocation == null) {
343 final String config = PropertiesUtil.getProperties().getStringProperty(CONFIGURATION_FILE_PROPERTY);
344 if (config != null) {
345 final ClassLoader loader = this.getClass().getClassLoader();
346 final ConfigurationSource source = getInputFromString(config, loader);
347 if (source != null) {
348 for (final ConfigurationFactory factory : factories) {
349 final String[] types = factory.getSupportedTypes();
350 if (types != null) {
351 for (final String type : types) {
352 if (type.equals("*") || config.endsWith(type)) {
353 final Configuration c = factory.getConfiguration(source);
354 if (c != null) {
355 return c;
356 }
357 }
358 }
359 }
360 }
361 }
362 }
363 } else {
364 for (final ConfigurationFactory factory : factories) {
365 final String[] types = factory.getSupportedTypes();
366 if (types != null) {
367 for (final String type : types) {
368 if (type.equals("*") || configLocation.getPath().endsWith(type)) {
369 final Configuration config = factory.getConfiguration(name, configLocation);
370 if (config != null) {
371 return config;
372 }
373 }
374 }
375 }
376 }
377 }
378
379 Configuration config = getConfiguration(true, name);
380 if (config == null) {
381 config = getConfiguration(true, null);
382 if (config == null) {
383 config = getConfiguration(false, name);
384 if (config == null) {
385 config = getConfiguration(false, null);
386 }
387 }
388 }
389 return config != null ? config : new DefaultConfiguration();
390 }
391
392 private Configuration getConfiguration(final boolean isTest, final String name) {
393 final boolean named = name != null && name.length() > 0;
394 final ClassLoader loader = this.getClass().getClassLoader();
395 for (final ConfigurationFactory factory : factories) {
396 String configName;
397 final String prefix = isTest ? TEST_PREFIX : DEFAULT_PREFIX;
398 final String [] types = factory.getSupportedTypes();
399 if (types == null) {
400 continue;
401 }
402
403 for (final String suffix : types) {
404 if (suffix.equals("*")) {
405 continue;
406 }
407 configName = named ? prefix + name + suffix : prefix + suffix;
408
409 final ConfigurationSource source = getInputFromResource(configName, loader);
410 if (source != null) {
411 return factory.getConfiguration(source);
412 }
413 }
414 }
415 return null;
416 }
417
418 @Override
419 public String[] getSupportedTypes() {
420 return null;
421 }
422
423 @Override
424 public Configuration getConfiguration(final ConfigurationSource source) {
425 if (source != null) {
426 final String config = source.getLocation();
427 for (final ConfigurationFactory factory : factories) {
428 final String[] types = factory.getSupportedTypes();
429 if (types != null) {
430 for (final String type : types) {
431 if (type.equals("*") || (config != null && config.endsWith(type))) {
432 final Configuration c = factory.getConfiguration(source);
433 if (c != null) {
434 return c;
435 } else {
436 LOGGER.error("Cannot determine the ConfigurationFactory to use for {}", config);
437 return null;
438 }
439 }
440 }
441 }
442 }
443 }
444 LOGGER.error("Cannot process configuration, input source is null");
445 return null;
446 }
447 }
448
449
450
451
452 public static class ConfigurationSource {
453
454 private File file;
455
456 private String location;
457
458 private InputStream stream;
459
460 public ConfigurationSource() {
461 }
462
463 public ConfigurationSource(final InputStream stream) {
464 this.stream = stream;
465 this .file = null;
466 this.location = null;
467 }
468
469 public ConfigurationSource(final InputStream stream, final File file) {
470 this.stream = stream;
471 this.file = file;
472 this.location = file.getAbsolutePath();
473 }
474
475 public ConfigurationSource(final InputStream stream, final String location) {
476 this.stream = stream;
477 this.location = location;
478 this.file = null;
479 }
480
481 public File getFile() {
482 return file;
483 }
484
485 public void setFile(final File file) {
486 this.file = file;
487 }
488
489 public String getLocation() {
490 return location;
491 }
492
493 public void setLocation(final String location) {
494 this.location = location;
495 }
496
497 public InputStream getInputStream() {
498 return stream;
499 }
500
501 public void setInputStream(final InputStream stream) {
502 this.stream = stream;
503 }
504 }
505 }