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