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.properties;
18  
19  import org.apache.logging.log4j.Level;
20  import org.apache.logging.log4j.core.config.ConfigurationException;
21  import org.apache.logging.log4j.core.config.ConfigurationFactory;
22  import org.apache.logging.log4j.core.config.ConfigurationSource;
23  import org.apache.logging.log4j.core.config.LoggerConfig;
24  import org.apache.logging.log4j.core.config.Order;
25  import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
26  import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
27  import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
28  import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
29  import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
30  import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
31  import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder;
32  import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
33  import org.apache.logging.log4j.core.config.builder.api.ScriptComponentBuilder;
34  import org.apache.logging.log4j.core.config.builder.api.ScriptFileComponentBuilder;
35  import org.apache.logging.log4j.core.config.plugins.Plugin;
36  import org.apache.logging.log4j.util.PropertiesUtil;
37  import org.apache.logging.log4j.util.Strings;
38  
39  import java.io.IOException;
40  import java.io.InputStream;
41  import java.util.Properties;
42  
43  /**
44   * Creates a PropertiesConfiguration from a properties file.
45   * 
46   * @since 2.4
47   */
48  @Plugin(name = "PropertiesConfigurationFactory", category = ConfigurationFactory.CATEGORY)
49  @Order(8)
50  public class PropertiesConfigurationFactory extends ConfigurationFactory {
51      private static final String ADVERTISER_KEY = "advertiser";
52      private static final String STATUS_KEY = "status";
53      private static final String SHUTDOWN_HOOK = "shutdownHook";
54      private static final String VERBOSE = "verbose";
55      private static final String PACKAGES = "packages";
56      private static final String CONFIG_NAME = "name";
57      private static final String MONITOR_INTERVAL = "monitorInterval";
58      private static final String CONFIG_TYPE = "type";
59  
60      @Override
61      protected String[] getSupportedTypes() {
62          return new String[] {".properties"};
63      }
64  
65      @Override
66      public PropertiesConfiguration getConfiguration(ConfigurationSource source) {
67          final InputStream configStream = source.getInputStream();
68          Properties properties = new Properties();
69          try {
70              properties.load(configStream);
71          } catch (IOException ioe) {
72              throw new ConfigurationException("Unable to load " + source.toString(), ioe);
73          }
74          ConfigurationBuilder<PropertiesConfiguration> builder = newConfigurationBuilder(PropertiesConfiguration.class);
75          String value = properties.getProperty(STATUS_KEY);
76          if (value != null) {
77              builder.setStatusLevel(Level.toLevel(value, Level.ERROR));
78          } else {
79              builder.setStatusLevel(Level.ERROR);
80          }
81          value = properties.getProperty(SHUTDOWN_HOOK);
82          if (value != null) {
83              builder.setShutdownHook(value);
84          }
85          value = properties.getProperty(VERBOSE);
86          if (value != null) {
87              builder.setVerbosity(value);
88          }
89          value = properties.getProperty(PACKAGES);
90          if (value != null) {
91              builder.setPackages(value);
92          }
93          value = properties.getProperty(CONFIG_NAME);
94          if (value != null) {
95              builder.setConfigurationName(value);
96          }
97          value = properties.getProperty(MONITOR_INTERVAL);
98          if (value != null) {
99              builder.setMonitorInterval(value);
100         }
101         value = properties.getProperty(ADVERTISER_KEY);
102         if (value != null) {
103             builder.setAdvertiser(value);
104         }
105         Properties props = PropertiesUtil.extractSubset(properties, "property");
106         for (String key : props.stringPropertyNames()) {
107             builder.addProperty(key, props.getProperty(key));
108         }
109 
110         String scriptProp = properties.getProperty("scripts");
111         if (scriptProp != null) {
112             String[] scriptNames = scriptProp.split(",");
113             for (String scriptName : scriptNames) {
114                 String name = scriptName.trim();
115                 Properties scriptProps = PropertiesUtil.extractSubset(properties, "script." + name);
116                 String type = scriptProps.getProperty("type");
117                 if (type == null) {
118                     throw new ConfigurationException("No type provided for script - must be Script or ScriptFile");
119                 }
120                 scriptProps.remove("type");
121                 if (type.equalsIgnoreCase("script")) {
122                     builder.add(createScript(builder, name, scriptProps));
123                 } else {
124                     builder.add(createScriptFile(builder, name, scriptProps));
125                 }
126             }
127         }
128 
129         Properties levelProps = PropertiesUtil.extractSubset(properties, "customLevel");
130         if (levelProps.size() > 0) {
131             for (String key : levelProps.stringPropertyNames()) {
132                 builder.add(builder.newCustomLevel(key, Integer.parseInt(props.getProperty(key))));
133             }
134         }
135 
136         String filterProp = properties.getProperty("filters");
137         if (filterProp != null) {
138             String[] filterNames = filterProp.split(",");
139             for (String filterName : filterNames) {
140                 String name = filterName.trim();
141                 builder.add(createFilter(builder, name, PropertiesUtil.extractSubset(properties, "filter." + name)));
142             }
143         }
144         String appenderProp = properties.getProperty("appenders");
145         if (appenderProp != null) {
146             String[] appenderNames = appenderProp.split(",");
147             for (String appenderName : appenderNames) {
148                 String name = appenderName.trim();
149                 builder.add(createAppender(builder, name, PropertiesUtil.extractSubset(properties, "appender." +
150                         name)));
151             }
152         }
153         String loggerProp = properties.getProperty("loggers");
154         if (loggerProp != null) {
155             String[] loggerNames = loggerProp.split(",");
156             for (String loggerName : loggerNames) {
157                 String name = loggerName.trim();
158                 if (!name.equals(LoggerConfig.ROOT)) {
159                     builder.add(createLogger(builder, name, PropertiesUtil.extractSubset(properties, "logger." +
160                             name)));
161                 }
162             }
163         }
164 
165         props = PropertiesUtil.extractSubset(properties, "rootLogger");
166         if (props.size() > 0) {
167             builder.add(createRootLogger(builder, props));
168         }
169 
170         return builder.build();
171     }
172 
173 
174     private ScriptComponentBuilder createScript(ConfigurationBuilder<PropertiesConfiguration> builder, String key,
175                                                 Properties properties) {
176         String name = properties.getProperty("name");
177         if (name != null) {
178             properties.remove("name");
179         }
180         String language = properties.getProperty("language");
181         if (language!= null) {
182             properties.remove("language");
183         }
184         String text = properties.getProperty("text");
185         if (text != null) {
186             properties.remove("text");
187         }
188         ScriptComponentBuilder scriptBuilder = builder.newScript(name, language, text);
189         processRemainingProperties(scriptBuilder, key, properties);
190         return scriptBuilder;
191     }
192 
193     private ScriptFileComponentBuilder createScriptFile(ConfigurationBuilder<PropertiesConfiguration> builder, String key,
194                                                 Properties properties) {
195         String name = properties.getProperty("name");
196         if (name != null) {
197             properties.remove("name");
198         }
199         String path = properties.getProperty("path");
200         if (path != null) {
201             properties.remove("path");
202         }
203         ScriptFileComponentBuilder scriptFileBuilder = builder.newScriptFile(name, path);
204         processRemainingProperties(scriptFileBuilder, key, properties);
205         return scriptFileBuilder;
206     }
207 
208 
209     private AppenderComponentBuilder createAppender(ConfigurationBuilder<PropertiesConfiguration> builder, String key,
210             Properties properties) {
211         String name = properties.getProperty(CONFIG_NAME);
212         if (Strings.isEmpty(name)) {
213             throw new ConfigurationException("No name attribute provided for Appender " + key);
214         }
215         properties.remove(CONFIG_NAME);
216         String type = properties.getProperty(CONFIG_TYPE);
217         if (Strings.isEmpty(type)) {
218             throw new ConfigurationException("No type attribute provided for Appender " + key);
219         }
220         properties.remove(CONFIG_TYPE);
221         AppenderComponentBuilder appenderBuilder = builder.newAppender(name, type);
222         String filters = properties.getProperty("filters");
223         if (filters != null) {
224             properties.remove("filters");
225             String[] filterNames = filters.split(",");
226             for (String filterName : filterNames) {
227                 filterName = filterName.trim();
228                 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
229                 appenderBuilder.add(createFilter(builder, filterName, filterProps));
230             }
231         }
232         Properties layoutProps = PropertiesUtil.extractSubset(properties, "layout");
233         if (layoutProps.size() > 0) {
234             appenderBuilder.add(createLayout(builder, name, layoutProps));
235         }
236 
237         processRemainingProperties(appenderBuilder, name, properties);
238         return appenderBuilder;
239     }
240 
241     private FilterComponentBuilder createFilter(ConfigurationBuilder<PropertiesConfiguration> builder, String key,
242             Properties properties) {
243         String type = properties.getProperty(CONFIG_TYPE);
244         if (Strings.isEmpty(type)) {
245             throw new ConfigurationException("No type attribute provided for Appender " + key);
246         }
247         properties.remove(CONFIG_TYPE);
248         String onMatch = properties.getProperty("onMatch");
249         if (onMatch != null) {
250             properties.remove("onMatch");
251         }
252         String onMisMatch = properties.getProperty("onMisMatch");
253         if (onMisMatch != null) {
254             properties.remove("onMisMatch");
255         }
256         FilterComponentBuilder filterBuilder = builder.newFilter(type, onMatch, onMisMatch);
257         processRemainingProperties(filterBuilder, key, properties);
258         return filterBuilder;
259     }
260 
261     private AppenderRefComponentBuilder createAppenderRef(ConfigurationBuilder<PropertiesConfiguration> builder,
262             String key, Properties properties) {
263         String ref = properties.getProperty("ref");
264         if (Strings.isEmpty(ref)) {
265             throw new ConfigurationException("No ref attribute provided for AppenderRef " + key);
266         }
267         properties.remove("ref");
268         AppenderRefComponentBuilder appenderRefBuilder = builder.newAppenderRef(ref);
269         String level = properties.getProperty("level");
270         if (!Strings.isEmpty(level)) {
271             appenderRefBuilder.addAttribute("level", level);
272         }
273         String filters = properties.getProperty("filters");
274         if (filters != null) {
275             properties.remove("filters");
276             String[] filterNames = filters.split(",");
277             for (String filterName : filterNames) {
278                 filterName = filterName.trim();
279                 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
280                 appenderRefBuilder.add(createFilter(builder, filterName, filterProps));
281             }
282         }
283         return appenderRefBuilder;
284     }
285 
286     private LoggerComponentBuilder createLogger(ConfigurationBuilder<PropertiesConfiguration> builder, String key,
287             Properties properties) {
288         String name = properties.getProperty(CONFIG_NAME);
289         if (Strings.isEmpty(name)) {
290             throw new ConfigurationException("No name attribute provided for Logger " + key);
291         }
292         properties.remove(CONFIG_NAME);
293         String level = properties.getProperty("level");
294         if (level != null) {
295             properties.remove("level");
296         }
297         LoggerComponentBuilder loggerBuilder;
298         String type = properties.getProperty(CONFIG_TYPE);
299         if (type != null) {
300             if (type.equalsIgnoreCase("asyncLogger")) {
301                 loggerBuilder = builder.newAsyncLogger(name, level);
302             } else {
303                 throw new ConfigurationException("Unknown Logger type " + type + " for Logger " + name);
304             }
305         } else {
306             loggerBuilder = builder.newLogger(name, level);
307         }
308         String appenderRefs = properties.getProperty("appenderRefs");
309         if (appenderRefs != null) {
310             properties.remove("appenderRefs");
311             String[] refNames = appenderRefs.split(",");
312             for (String appenderRef : refNames) {
313                 appenderRef = appenderRef.trim();
314                 Properties refProps = PropertiesUtil.extractSubset(properties, "appenderRef." + appenderRef);
315                 loggerBuilder.add(createAppenderRef(builder, appenderRef, refProps));
316             }
317         }
318         String filters = properties.getProperty("filters");
319         if (filters != null) {
320             properties.remove("filters");
321             String[] filterNames = filters.split(",");
322             for (String filterName : filterNames) {
323                 filterName = filterName.trim();
324                 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
325                 loggerBuilder.add(createFilter(builder, filterName, filterProps));
326             }
327         }
328         String additivity = properties.getProperty("additivity");
329         if (!Strings.isEmpty(additivity)) {
330             loggerBuilder.addAttribute("additivity", additivity);
331         }
332         return loggerBuilder;
333     }
334 
335     private RootLoggerComponentBuilder createRootLogger(ConfigurationBuilder<PropertiesConfiguration> builder,
336             Properties properties) {
337         String level = properties.getProperty("level");
338         if (level != null) {
339             properties.remove("level");
340         }
341         RootLoggerComponentBuilder loggerBuilder;
342         String type = properties.getProperty(CONFIG_TYPE);
343         if (type != null) {
344             if (type.equalsIgnoreCase("asyncRoot")) {
345                 loggerBuilder = builder.newAsyncRootLogger(level);
346             } else {
347                 throw new ConfigurationException("Unknown Logger type for root logger" + type);
348             }
349         } else {
350             loggerBuilder = builder.newRootLogger(level);
351         }
352         String appenderRefs = properties.getProperty("appenderRefs");
353         if (appenderRefs != null) {
354             properties.remove("appenderRefs");
355             String[] refNames = appenderRefs.split(",");
356             for (String appenderRef : refNames) {
357                 appenderRef = appenderRef.trim();
358                 Properties refProps = PropertiesUtil.extractSubset(properties, "appenderRef." + appenderRef);
359                 loggerBuilder.add(createAppenderRef(builder, appenderRef, refProps));
360             }
361         }
362         String filters = properties.getProperty("filters");
363         if (filters != null) {
364             properties.remove("filters");
365             String[] filterNames = filters.split(",");
366             for (String filterName : filterNames) {
367                 filterName = filterName.trim();
368                 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
369                 loggerBuilder.add(createFilter(builder, filterName, filterProps));
370             }
371         }
372         return loggerBuilder;
373     }
374 
375     private LayoutComponentBuilder createLayout(ConfigurationBuilder<PropertiesConfiguration> builder,
376             String appenderName, Properties properties) {
377         String type = properties.getProperty(CONFIG_TYPE);
378         if (Strings.isEmpty(type)) {
379             throw new ConfigurationException("No type attribute provided for Layout on Appender " + appenderName);
380         }
381         properties.remove(CONFIG_TYPE);
382         LayoutComponentBuilder layoutBuilder = builder.newLayout(type);
383         processRemainingProperties(layoutBuilder, appenderName, properties);
384         return layoutBuilder;
385     }
386 
387     private <B extends ComponentBuilder<B>> ComponentBuilder<B> createComponent(ComponentBuilder<?> parent, String key,
388             Properties properties) {
389         String name = properties.getProperty(CONFIG_NAME);
390         if (name != null) {
391             properties.remove(CONFIG_NAME);
392         }
393         String type = properties.getProperty(CONFIG_TYPE);
394         if (Strings.isEmpty(type)) {
395             throw new ConfigurationException("No type attribute provided for component " + key);
396         }
397         properties.remove(CONFIG_TYPE);
398         ComponentBuilder<B> componentBuilder = parent.getBuilder().newComponent(name, type);
399         processRemainingProperties(componentBuilder, name, properties);
400         return componentBuilder;
401     }
402 
403     private void processRemainingProperties(ComponentBuilder<?> builder, String name, Properties properties) {
404         while (properties.size() > 0) {
405             String propertyName = properties.stringPropertyNames().iterator().next();
406 
407             int index = propertyName.indexOf('.');
408             if (index > 0) {
409                 String prefix = propertyName.substring(0, index);
410                 Properties componentProperties = PropertiesUtil.extractSubset(properties, prefix);
411                 builder.addComponent(createComponent(builder, prefix, componentProperties));
412             } else {
413                 builder.addAttribute(propertyName, properties.getProperty(propertyName));
414                 properties.remove(propertyName);
415             }
416         }
417     }
418 }