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());
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 try {
265 return new ConfigurationSource(configLocation.toURL().openStream(), configLocation.toURL());
266 } catch (final MalformedURLException ex) {
267 LOGGER.error("Invalid URL {}", configLocation.toString(), ex);
268 } catch (final Exception ex) {
269 LOGGER.error("Unable to access {}", configLocation.toString(), ex);
270 }
271 return null;
272 }
273
274
275
276
277
278
279
280 protected ConfigurationSource getInputFromString(final String config, final ClassLoader loader) {
281 try {
282 final URL url = new URL(config);
283 return new ConfigurationSource(url.openStream(), FileUtils.fileFromUri(url.toURI()));
284 } catch (final Exception ex) {
285 final ConfigurationSource source = getInputFromResource(config, loader);
286 if (source == null) {
287 try {
288 final File file = new File(config);
289 return new ConfigurationSource(new FileInputStream(file), file);
290 } catch (final FileNotFoundException fnfe) {
291
292 LOGGER.catching(Level.DEBUG, fnfe);
293 }
294 }
295 return source;
296 }
297 }
298
299
300
301
302
303
304
305 protected ConfigurationSource getInputFromResource(final String resource, final ClassLoader loader) {
306 final URL url = Loader.getResource(resource, loader);
307 if (url == null) {
308 return null;
309 }
310 InputStream is = null;
311 try {
312 is = url.openStream();
313 } catch (final IOException ioe) {
314 LOGGER.catching(Level.DEBUG, ioe);
315 return null;
316 }
317 if (is == null) {
318 return null;
319 }
320
321 if (FileUtils.isFile(url)) {
322 try {
323 return new ConfigurationSource(is, FileUtils.fileFromUri(url.toURI()));
324 } catch (final URISyntaxException ex) {
325
326 LOGGER.catching(Level.DEBUG, ex);
327 }
328 }
329 return new ConfigurationSource(is, url);
330 }
331
332
333
334
335 private static class WeightedFactory implements Comparable<WeightedFactory> {
336 private final int weight;
337 private final Class<ConfigurationFactory> factoryClass;
338
339
340
341
342
343
344 public WeightedFactory(final int weight, final Class<ConfigurationFactory> clazz) {
345 this.weight = weight;
346 this.factoryClass = clazz;
347 }
348
349 @Override
350 public int compareTo(final WeightedFactory wf) {
351 final int w = wf.weight;
352 if (weight == w) {
353 return 0;
354 } else if (weight > w) {
355 return -1;
356 } else {
357 return 1;
358 }
359 }
360 }
361
362
363
364
365 private static class Factory extends ConfigurationFactory {
366
367
368
369
370
371
372
373 @Override
374 public Configuration getConfiguration(final String name, final URI configLocation) {
375
376 if (configLocation == null) {
377 final String config = this.substitutor.replace(
378 PropertiesUtil.getProperties().getStringProperty(CONFIGURATION_FILE_PROPERTY));
379 if (config != null) {
380 ConfigurationSource source = null;
381 try {
382 source = getInputFromUri(FileUtils.getCorrectedFilePathUri(config));
383 } catch (final Exception ex) {
384
385 LOGGER.catching(Level.DEBUG, ex);
386 }
387 if (source == null) {
388 final ClassLoader loader = this.getClass().getClassLoader();
389 source = getInputFromString(config, loader);
390 }
391 if (source != null) {
392 for (final ConfigurationFactory factory : factories) {
393 final String[] types = factory.getSupportedTypes();
394 if (types != null) {
395 for (final String type : types) {
396 if (type.equals("*") || config.endsWith(type)) {
397 final Configuration c = factory.getConfiguration(source);
398 if (c != null) {
399 return c;
400 }
401 }
402 }
403 }
404 }
405 }
406 }
407 } else {
408 for (final ConfigurationFactory factory : factories) {
409 final String[] types = factory.getSupportedTypes();
410 if (types != null) {
411 for (final String type : types) {
412 if (type.equals("*") || configLocation.toString().endsWith(type)) {
413 final Configuration config = factory.getConfiguration(name, configLocation);
414 if (config != null) {
415 return config;
416 }
417 }
418 }
419 }
420 }
421 }
422
423 Configuration config = getConfiguration(true, name);
424 if (config == null) {
425 config = getConfiguration(true, null);
426 if (config == null) {
427 config = getConfiguration(false, name);
428 if (config == null) {
429 config = getConfiguration(false, null);
430 }
431 }
432 }
433 return config != null ? config : new DefaultConfiguration();
434 }
435
436 private Configuration getConfiguration(final boolean isTest, final String name) {
437 final boolean named = name != null && name.length() > 0;
438 final ClassLoader loader = this.getClass().getClassLoader();
439 for (final ConfigurationFactory factory : factories) {
440 String configName;
441 final String prefix = isTest ? TEST_PREFIX : DEFAULT_PREFIX;
442 final String [] types = factory.getSupportedTypes();
443 if (types == null) {
444 continue;
445 }
446
447 for (final String suffix : types) {
448 if (suffix.equals("*")) {
449 continue;
450 }
451 configName = named ? prefix + name + suffix : prefix + suffix;
452
453 final ConfigurationSource source = getInputFromResource(configName, loader);
454 if (source != null) {
455 return factory.getConfiguration(source);
456 }
457 }
458 }
459 return null;
460 }
461
462 @Override
463 public String[] getSupportedTypes() {
464 return null;
465 }
466
467 @Override
468 public Configuration getConfiguration(final ConfigurationSource source) {
469 if (source != null) {
470 final String config = source.getLocation();
471 for (final ConfigurationFactory factory : factories) {
472 final String[] types = factory.getSupportedTypes();
473 if (types != null) {
474 for (final String type : types) {
475 if (type.equals("*") || config != null && config.endsWith(type)) {
476 final Configuration c = factory.getConfiguration(source);
477 if (c != null) {
478 LOGGER.debug("Loaded configuration from {}", source);
479 return c;
480 }
481 LOGGER.error("Cannot determine the ConfigurationFactory to use for {}", config);
482 return null;
483 }
484 }
485 }
486 }
487 }
488 LOGGER.error("Cannot process configuration, input source is null");
489 return null;
490 }
491 }
492 }