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