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