View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
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   * @param <T> The BuiltConfiguration type.
56   * @since 2.4
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(); // "Configuration"
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      * Set the name of the configuration.
535      *
536      * @param name the name of the {@link Configuration}. By default is {@code "Assembled"}.
537      * @return this builder instance
538      */
539     @Override
540     public ConfigurationBuilder<T> setConfigurationName(final String name) {
541         this.name = name;
542         return this;
543     }
544 
545     /**
546      * Set the ConfigurationSource.
547      *
548      * @param configurationSource the {@link ConfigurationSource}
549      * @return this builder instance
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 }