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