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