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