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