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