1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.config.builder.impl;
18
19 import java.io.IOException;
20 import java.io.OutputStream;
21 import java.io.StringWriter;
22 import java.lang.reflect.Constructor;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.concurrent.TimeUnit;
26
27 import javax.xml.stream.XMLOutputFactory;
28 import javax.xml.stream.XMLStreamException;
29 import javax.xml.stream.XMLStreamWriter;
30
31 import org.apache.logging.log4j.Level;
32 import org.apache.logging.log4j.core.Filter;
33 import org.apache.logging.log4j.core.LoggerContext;
34 import org.apache.logging.log4j.core.config.Configuration;
35 import org.apache.logging.log4j.core.config.ConfigurationException;
36 import org.apache.logging.log4j.core.config.ConfigurationSource;
37 import org.apache.logging.log4j.core.config.LoggerConfig;
38 import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
39 import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
40 import org.apache.logging.log4j.core.config.builder.api.Component;
41 import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
42 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
43 import org.apache.logging.log4j.core.config.builder.api.CustomLevelComponentBuilder;
44 import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
45 import org.apache.logging.log4j.core.config.builder.api.KeyValuePairComponentBuilder;
46 import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
47 import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder;
48 import org.apache.logging.log4j.core.config.builder.api.PropertyComponentBuilder;
49 import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
50 import org.apache.logging.log4j.core.config.builder.api.ScriptComponentBuilder;
51 import org.apache.logging.log4j.core.config.builder.api.ScriptFileComponentBuilder;
52 import org.apache.logging.log4j.core.util.Throwables;
53
54
55
56
57
58 public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implements ConfigurationBuilder<T> {
59
60 private static final String INDENT = " ";
61 private static final String EOL = System.lineSeparator();
62
63 private final Component root = new Component();
64 private Component loggers;
65 private Component appenders;
66 private Component filters;
67 private Component properties;
68 private Component customLevels;
69 private Component scripts;
70 private final Class<T> clazz;
71 private ConfigurationSource source;
72 private int monitorInterval;
73 private Level level;
74 private String verbosity;
75 private String destination;
76 private String packages;
77 private String shutdownFlag;
78 private long shutdownTimeoutMillis;
79 private String advertiser;
80 private LoggerContext loggerContext;
81 private String name;
82
83 @SuppressWarnings("unchecked")
84 public DefaultConfigurationBuilder() {
85 this((Class<T>) BuiltConfiguration.class);
86 root.addAttribute("name", "Built");
87 }
88
89 public DefaultConfigurationBuilder(final Class<T> clazz) {
90 if (clazz == null) {
91 throw new IllegalArgumentException("A Configuration class must be provided");
92 }
93 this.clazz = clazz;
94 final List<Component> components = root.getComponents();
95 properties = new Component("Properties");
96 components.add(properties);
97 scripts = new Component("Scripts");
98 components.add(scripts);
99 customLevels = new Component("CustomLevels");
100 components.add(customLevels);
101 filters = new Component("Filters");
102 components.add(filters);
103 appenders = new Component("Appenders");
104 components.add(appenders);
105 loggers = new Component("Loggers");
106 components.add(loggers);
107 }
108
109 protected ConfigurationBuilder<T> add(final Component parent, final ComponentBuilder<?> builder) {
110 parent.getComponents().add(builder.build());
111 return this;
112 }
113
114 @Override
115 public ConfigurationBuilder<T> add(final AppenderComponentBuilder builder) {
116 return add(appenders, builder);
117 }
118
119 @Override
120 public ConfigurationBuilder<T> add(final CustomLevelComponentBuilder builder) {
121 return add(customLevels, builder);
122 }
123
124 @Override
125 public ConfigurationBuilder<T> add(final FilterComponentBuilder builder) {
126 return add(filters, builder);
127 }
128
129 @Override
130 public ConfigurationBuilder<T> add(final ScriptComponentBuilder builder) {
131 return add(scripts, builder);
132 }
133
134 @Override
135 public ConfigurationBuilder<T> add(final ScriptFileComponentBuilder builder) {
136 return add(scripts, builder);
137 }
138
139 @Override
140 public ConfigurationBuilder<T> add(final LoggerComponentBuilder builder) {
141 return add(loggers, builder);
142 }
143
144 @Override
145 public ConfigurationBuilder<T> add(final RootLoggerComponentBuilder builder) {
146 for (final Component c : loggers.getComponents()) {
147 if (c.getPluginType().equals(LoggerConfig.ROOT)) {
148 throw new ConfigurationException("Root Logger was previously defined");
149 }
150 }
151 return add(loggers, builder);
152 }
153
154 @Override
155 public ConfigurationBuilder<T> addProperty(final String key, final String value) {
156 properties.addComponent(newComponent(key, "Property", value).build());
157 return this;
158 }
159
160 @Override
161 public T build() {
162 return build(true);
163 }
164
165 @Override
166 public T build(final boolean initialize) {
167 T configuration;
168 try {
169 if (source == null) {
170 source = ConfigurationSource.NULL_SOURCE;
171 }
172 final Constructor<T> constructor = clazz.getConstructor(LoggerContext.class, ConfigurationSource.class, Component.class);
173 configuration = constructor.newInstance(loggerContext, source, root);
174 configuration.getRootNode().getAttributes().putAll(root.getAttributes());
175 if (name != null) {
176 configuration.setName(name);
177 }
178 if (level != null) {
179 configuration.getStatusConfiguration().withStatus(level);
180 }
181 if (verbosity != null) {
182 configuration.getStatusConfiguration().withVerbosity(verbosity);
183 }
184 if (destination != null) {
185 configuration.getStatusConfiguration().withDestination(destination);
186 }
187 if (packages != null) {
188 configuration.setPluginPackages(packages);
189 }
190 if (shutdownFlag != null) {
191 configuration.setShutdownHook(shutdownFlag);
192 }
193 if (shutdownTimeoutMillis > 0) {
194 configuration.setShutdownTimeoutMillis(shutdownTimeoutMillis);
195 }
196 if (advertiser != null) {
197 configuration.createAdvertiser(advertiser, source);
198 }
199 configuration.setMonitorInterval(monitorInterval);
200 } catch (final Exception ex) {
201 throw new IllegalArgumentException("Invalid Configuration class specified", ex);
202 }
203 configuration.getStatusConfiguration().initialize();
204 if (initialize) {
205 configuration.initialize();
206 }
207 return configuration;
208 }
209
210 @Override
211 public void writeXmlConfiguration(final OutputStream output) throws IOException {
212 try {
213 final XMLStreamWriter xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(output);
214 writeXmlConfiguration(xmlWriter);
215 xmlWriter.close();
216 } catch (final XMLStreamException e) {
217 if (e.getNestedException() instanceof IOException) {
218 throw (IOException)e.getNestedException();
219 }
220 Throwables.rethrow(e);
221 }
222 }
223
224 @Override
225 public String toXmlConfiguration() {
226 final StringWriter sw = new StringWriter();
227 try {
228 final XMLStreamWriter xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(sw);
229 writeXmlConfiguration(xmlWriter);
230 xmlWriter.close();
231 } catch (final XMLStreamException e) {
232 Throwables.rethrow(e);
233 }
234 return sw.toString();
235 }
236
237 private void writeXmlConfiguration(final XMLStreamWriter xmlWriter) throws XMLStreamException {
238 xmlWriter.writeStartDocument();
239 xmlWriter.writeCharacters(EOL);
240
241 xmlWriter.writeStartElement("Configuration");
242 if (name != null) {
243 xmlWriter.writeAttribute("name", name);
244 }
245 if (level != null) {
246 xmlWriter.writeAttribute("status", level.name());
247 }
248 if (verbosity != null) {
249 xmlWriter.writeAttribute("verbose", verbosity);
250 }
251 if (destination != null) {
252 xmlWriter.writeAttribute("dest", destination);
253 }
254 if (packages != null) {
255 xmlWriter.writeAttribute("packages", packages);
256 }
257 if (shutdownFlag != null) {
258 xmlWriter.writeAttribute("shutdownHook", shutdownFlag);
259 }
260 if (shutdownTimeoutMillis > 0) {
261 xmlWriter.writeAttribute("shutdownTimeout", String.valueOf(shutdownTimeoutMillis));
262 }
263 if (advertiser != null) {
264 xmlWriter.writeAttribute("advertiser", advertiser);
265 }
266 if (monitorInterval > 0) {
267 xmlWriter.writeAttribute("monitorInterval", String.valueOf(monitorInterval));
268 }
269
270 xmlWriter.writeCharacters(EOL);
271
272 writeXmlSection(xmlWriter, properties);
273 writeXmlSection(xmlWriter, scripts);
274 writeXmlSection(xmlWriter, customLevels);
275 if (filters.getComponents().size() == 1) {
276 writeXmlComponent(xmlWriter, filters.getComponents().get(0), 1);
277 } else if (filters.getComponents().size() > 1) {
278 writeXmlSection(xmlWriter, filters);
279 }
280 writeXmlSection(xmlWriter, appenders);
281 writeXmlSection(xmlWriter, loggers);
282
283 xmlWriter.writeEndElement();
284 xmlWriter.writeCharacters(EOL);
285
286 xmlWriter.writeEndDocument();
287 }
288
289 private void writeXmlSection(final XMLStreamWriter xmlWriter, final Component component) throws XMLStreamException {
290 if (!component.getAttributes().isEmpty() || !component.getComponents().isEmpty() || component.getValue() != null) {
291 writeXmlComponent(xmlWriter, component, 1);
292 }
293 }
294
295 private void writeXmlComponent(final XMLStreamWriter xmlWriter, final Component component, final int nesting) throws XMLStreamException {
296 if (!component.getComponents().isEmpty() || component.getValue() != null) {
297 writeXmlIndent(xmlWriter, nesting);
298 xmlWriter.writeStartElement(component.getPluginType());
299 writeXmlAttributes(xmlWriter, component);
300 if (!component.getComponents().isEmpty()) {
301 xmlWriter.writeCharacters(EOL);
302 }
303 for (final Component subComponent : component.getComponents()) {
304 writeXmlComponent(xmlWriter, subComponent, nesting + 1);
305 }
306 if (component.getValue() != null) {
307 xmlWriter.writeCharacters(component.getValue());
308 }
309 if (!component.getComponents().isEmpty()) {
310 writeXmlIndent(xmlWriter, nesting);
311 }
312 xmlWriter.writeEndElement();
313 } else {
314 writeXmlIndent(xmlWriter, nesting);
315 xmlWriter.writeEmptyElement(component.getPluginType());
316 writeXmlAttributes(xmlWriter, component);
317 }
318 xmlWriter.writeCharacters(EOL);
319 }
320
321 private void writeXmlIndent(final XMLStreamWriter xmlWriter, final int nesting) throws XMLStreamException {
322 for (int i = 0; i < nesting; i++) {
323 xmlWriter.writeCharacters(INDENT);
324 }
325 }
326
327 private void writeXmlAttributes(final XMLStreamWriter xmlWriter, final Component component) throws XMLStreamException {
328 for (final Map.Entry<String, String> attribute : component.getAttributes().entrySet()) {
329 xmlWriter.writeAttribute(attribute.getKey(), attribute.getValue());
330 }
331 }
332
333 @Override
334 public ScriptComponentBuilder newScript(final String name, final String language, final String text) {
335 return new DefaultScriptComponentBuilder(this, name, language, text);
336 }
337
338
339 @Override
340 public ScriptFileComponentBuilder newScriptFile(final String path) {
341 return new DefaultScriptFileComponentBuilder(this, path, path);
342 }
343
344 @Override
345 public ScriptFileComponentBuilder newScriptFile(final String name, final String path) {
346 return new DefaultScriptFileComponentBuilder(this, name, path);
347 }
348
349 @Override
350 public AppenderComponentBuilder newAppender(final String name, final String type) {
351 return new DefaultAppenderComponentBuilder(this, name, type);
352 }
353
354 @Override
355 public AppenderRefComponentBuilder newAppenderRef(final String ref) {
356 return new DefaultAppenderRefComponentBuilder(this, ref);
357 }
358
359 @Override
360 public LoggerComponentBuilder newAsyncLogger(final String name) {
361 return new DefaultLoggerComponentBuilder(this, name, null, "AsyncLogger");
362 }
363
364 @Override
365 public LoggerComponentBuilder newAsyncLogger(final String name, final boolean includeLocation) {
366 return new DefaultLoggerComponentBuilder(this, name, null, "AsyncLogger", includeLocation);
367 }
368
369 @Override
370 public LoggerComponentBuilder newAsyncLogger(final String name, final Level level) {
371 return new DefaultLoggerComponentBuilder(this, name, level.toString(), "AsyncLogger");
372 }
373
374 @Override
375 public LoggerComponentBuilder newAsyncLogger(final String name, final Level level, final boolean includeLocation) {
376 return new DefaultLoggerComponentBuilder(this, name, level.toString(), "AsyncLogger", includeLocation);
377 }
378
379 @Override
380 public LoggerComponentBuilder newAsyncLogger(final String name, final String level) {
381 return new DefaultLoggerComponentBuilder(this, name, level, "AsyncLogger");
382 }
383
384 @Override
385 public LoggerComponentBuilder newAsyncLogger(final String name, final String level, final boolean includeLocation) {
386 return new DefaultLoggerComponentBuilder(this, name, level, "AsyncLogger", includeLocation);
387 }
388
389 @Override
390 public RootLoggerComponentBuilder newAsyncRootLogger() {
391 return new DefaultRootLoggerComponentBuilder(this, "AsyncRoot");
392 }
393
394 @Override
395 public RootLoggerComponentBuilder newAsyncRootLogger(final boolean includeLocation) {
396 return new DefaultRootLoggerComponentBuilder(this, null, "AsyncRoot", includeLocation);
397 }
398
399 @Override
400 public RootLoggerComponentBuilder newAsyncRootLogger(final Level level) {
401 return new DefaultRootLoggerComponentBuilder(this, level.toString(), "AsyncRoot");
402 }
403
404 @Override
405 public RootLoggerComponentBuilder newAsyncRootLogger(final Level level, final boolean includeLocation) {
406 return new DefaultRootLoggerComponentBuilder(this, level.toString(), "AsyncRoot", includeLocation);
407 }
408
409 @Override
410 public RootLoggerComponentBuilder newAsyncRootLogger(final String level) {
411 return new DefaultRootLoggerComponentBuilder(this, level, "AsyncRoot");
412 }
413
414 @Override
415 public RootLoggerComponentBuilder newAsyncRootLogger(final String level, final boolean includeLocation) {
416 return new DefaultRootLoggerComponentBuilder(this, level, "AsyncRoot", includeLocation);
417 }
418
419
420 @Override
421 public <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(final String type) {
422 return new DefaultComponentBuilder<>(this, type);
423 }
424
425 @Override
426 public <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(final String name, final String type) {
427 return new DefaultComponentBuilder<>(this, name, type);
428 }
429
430 @Override
431 public <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(final String name, final String type,
432 final String value) {
433 return new DefaultComponentBuilder<>(this, name, type, value);
434 }
435
436 @Override
437 public PropertyComponentBuilder newProperty(final String name, final String value) {
438 return new DefaultPropertyComponentBuilder(this, name, value);
439 }
440
441 @Override
442 public KeyValuePairComponentBuilder newKeyValuePair(final String key, final String value) {
443 return new DefaultKeyValuePairComponentBuilder(this, key, value);
444 }
445
446 @Override
447 public CustomLevelComponentBuilder newCustomLevel(final String name, final int level) {
448 return new DefaultCustomLevelComponentBuilder(this, name, level);
449 }
450
451 @Override
452 public FilterComponentBuilder newFilter(final String type, final Filter.Result onMatch,
453 final Filter.Result onMismatch) {
454 return new DefaultFilterComponentBuilder(this, type, onMatch.name(), onMismatch.name());
455 }
456
457 @Override
458 public FilterComponentBuilder newFilter(final String type, final String onMatch, final String onMismatch) {
459 return new DefaultFilterComponentBuilder(this, type, onMatch, onMismatch);
460 }
461
462 @Override
463 public LayoutComponentBuilder newLayout(final String type) {
464 return new DefaultLayoutComponentBuilder(this, type);
465 }
466
467 @Override
468 public LoggerComponentBuilder newLogger(final String name) {
469 return new DefaultLoggerComponentBuilder(this, name, null);
470 }
471
472 @Override
473 public LoggerComponentBuilder newLogger(final String name, final boolean includeLocation) {
474 return new DefaultLoggerComponentBuilder(this, name, null, includeLocation);
475 }
476
477 @Override
478 public LoggerComponentBuilder newLogger(final String name, final Level level) {
479 return new DefaultLoggerComponentBuilder(this, name, level.toString());
480 }
481
482 @Override
483 public LoggerComponentBuilder newLogger(final String name, final Level level, final boolean includeLocation) {
484 return new DefaultLoggerComponentBuilder(this, name, level.toString(), includeLocation);
485 }
486
487 @Override
488 public LoggerComponentBuilder newLogger(final String name, final String level) {
489 return new DefaultLoggerComponentBuilder(this, name, level);
490 }
491
492 @Override
493 public LoggerComponentBuilder newLogger(final String name, final String level, final boolean includeLocation) {
494 return new DefaultLoggerComponentBuilder(this, name, level, includeLocation);
495 }
496
497 @Override
498 public RootLoggerComponentBuilder newRootLogger() {
499 return new DefaultRootLoggerComponentBuilder(this, null);
500 }
501
502 @Override
503 public RootLoggerComponentBuilder newRootLogger(final boolean includeLocation) {
504 return new DefaultRootLoggerComponentBuilder(this, null, includeLocation);
505 }
506
507 @Override
508 public RootLoggerComponentBuilder newRootLogger(final Level level) {
509 return new DefaultRootLoggerComponentBuilder(this, level.toString());
510 }
511
512 @Override
513 public RootLoggerComponentBuilder newRootLogger(final Level level, final boolean includeLocation) {
514 return new DefaultRootLoggerComponentBuilder(this, level.toString(), includeLocation);
515 }
516
517 @Override
518 public RootLoggerComponentBuilder newRootLogger(final String level) {
519 return new DefaultRootLoggerComponentBuilder(this, level);
520 }
521
522 @Override
523 public RootLoggerComponentBuilder newRootLogger(final String level, final boolean includeLocation) {
524 return new DefaultRootLoggerComponentBuilder(this, level, includeLocation);
525 }
526
527 @Override
528 public ConfigurationBuilder<T> setAdvertiser(final String advertiser) {
529 this.advertiser = advertiser;
530 return this;
531 }
532
533
534
535
536
537
538
539 @Override
540 public ConfigurationBuilder<T> setConfigurationName(final String name) {
541 this.name = name;
542 return this;
543 }
544
545
546
547
548
549
550
551 @Override
552 public ConfigurationBuilder<T> setConfigurationSource(final ConfigurationSource configurationSource) {
553 source = configurationSource;
554 return this;
555 }
556
557 @Override
558 public ConfigurationBuilder<T> setMonitorInterval(final String intervalSeconds) {
559 monitorInterval = Integer.parseInt(intervalSeconds);
560 return this;
561 }
562
563 @Override
564 public ConfigurationBuilder<T> setPackages(final String packages) {
565 this.packages = packages;
566 return this;
567 }
568
569 @Override
570 public ConfigurationBuilder<T> setShutdownHook(final String flag) {
571 this.shutdownFlag = flag;
572 return this;
573 }
574
575 @Override
576 public ConfigurationBuilder<T> setShutdownTimeout(final long timeout, final TimeUnit timeUnit) {
577 this.shutdownTimeoutMillis = timeUnit.toMillis(timeout);
578 return this;
579 }
580
581 @Override
582 public ConfigurationBuilder<T> setStatusLevel(final Level level) {
583 this.level = level;
584 return this;
585 }
586
587 @Override
588 public ConfigurationBuilder<T> setVerbosity(final String verbosity) {
589 this.verbosity = verbosity;
590 return this;
591 }
592
593 @Override
594 public ConfigurationBuilder<T> setDestination(final String destination) {
595 this.destination = destination;
596 return this;
597 }
598
599 @Override
600 public void setLoggerContext(final LoggerContext loggerContext) {
601 this.loggerContext = loggerContext;
602 }
603
604 @Override
605 public ConfigurationBuilder<T> addRootProperty(final String key, final String value) {
606 root.getAttributes().put(key, value);
607 return this;
608 }
609
610 }