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