1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.util;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.nio.charset.Charset;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Properties;
27 import java.util.ResourceBundle;
28 import java.util.ServiceLoader;
29 import java.util.Set;
30 import java.util.TreeSet;
31 import java.util.concurrent.ConcurrentHashMap;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public final class PropertiesUtil {
47
48 private static final String LOG4J_PROPERTIES_FILE_NAME = "log4j2.component.properties";
49 private static final String LOG4J_SYSTEM_PROPERTIES_FILE_NAME = "log4j2.system.properties";
50 private static final String SYSTEM = "system:";
51 private static final PropertiesUtil LOG4J_PROPERTIES = new PropertiesUtil(LOG4J_PROPERTIES_FILE_NAME);
52
53 private final Environment environment;
54
55
56
57
58
59
60 public PropertiesUtil(final Properties props) {
61 this.environment = new Environment(new PropertiesPropertySource(props));
62 }
63
64
65
66
67
68
69
70 public PropertiesUtil(final String propertiesFileName) {
71 this.environment = new Environment(new PropertyFilePropertySource(propertiesFileName));
72 }
73
74
75
76
77
78
79
80
81 static Properties loadClose(final InputStream in, final Object source) {
82 final Properties props = new Properties();
83 if (null != in) {
84 try {
85 props.load(in);
86 } catch (final IOException e) {
87 LowLevelLogUtil.logException("Unable to read " + source, e);
88 } finally {
89 try {
90 in.close();
91 } catch (final IOException e) {
92 LowLevelLogUtil.logException("Unable to close " + source, e);
93 }
94 }
95 }
96 return props;
97 }
98
99
100
101
102
103
104 public static PropertiesUtil getProperties() {
105 return LOG4J_PROPERTIES;
106 }
107
108
109
110
111
112
113
114 public boolean hasProperty(final String name) {
115 return environment.containsKey(name);
116 }
117
118
119
120
121
122
123
124
125
126 public boolean getBooleanProperty(final String name) {
127 return getBooleanProperty(name, false);
128 }
129
130
131
132
133
134
135
136
137 public boolean getBooleanProperty(final String name, final boolean defaultValue) {
138 final String prop = getStringProperty(name);
139 return prop == null ? defaultValue : "true".equalsIgnoreCase(prop);
140 }
141
142
143
144
145
146
147
148
149
150 public boolean getBooleanProperty(final String name, final boolean defaultValueIfAbsent,
151 final boolean defaultValueIfPresent) {
152 final String prop = getStringProperty(name);
153 return prop == null ? defaultValueIfAbsent
154 : prop.isEmpty() ? defaultValueIfPresent : "true".equalsIgnoreCase(prop);
155 }
156
157
158
159
160
161
162
163 public Charset getCharsetProperty(final String name) {
164 return getCharsetProperty(name, Charset.defaultCharset());
165 }
166
167
168
169
170
171
172
173
174
175 public Charset getCharsetProperty(final String name, final Charset defaultValue) {
176 final String charsetName = getStringProperty(name);
177 if (charsetName == null) {
178 return defaultValue;
179 }
180 if (Charset.isSupported(charsetName)) {
181 return Charset.forName(charsetName);
182 }
183 final ResourceBundle bundle = getCharsetsResourceBundle();
184 if (bundle.containsKey(name)) {
185 final String mapped = bundle.getString(name);
186 if (Charset.isSupported(mapped)) {
187 return Charset.forName(mapped);
188 }
189 }
190 LowLevelLogUtil.log("Unable to get Charset '" + charsetName + "' for property '" + name + "', using default "
191 + defaultValue + " and continuing.");
192 return defaultValue;
193 }
194
195
196
197
198
199
200
201
202 public double getDoubleProperty(final String name, final double defaultValue) {
203 final String prop = getStringProperty(name);
204 if (prop != null) {
205 try {
206 return Double.parseDouble(prop);
207 } catch (final Exception ignored) {
208 return defaultValue;
209 }
210 }
211 return defaultValue;
212 }
213
214
215
216
217
218
219
220
221
222 public int getIntegerProperty(final String name, final int defaultValue) {
223 final String prop = getStringProperty(name);
224 if (prop != null) {
225 try {
226 return Integer.parseInt(prop);
227 } catch (final Exception ignored) {
228 return defaultValue;
229 }
230 }
231 return defaultValue;
232 }
233
234
235
236
237
238
239
240
241 public long getLongProperty(final String name, final long defaultValue) {
242 final String prop = getStringProperty(name);
243 if (prop != null) {
244 try {
245 return Long.parseLong(prop);
246 } catch (final Exception ignored) {
247 return defaultValue;
248 }
249 }
250 return defaultValue;
251 }
252
253
254
255
256
257
258
259 public String getStringProperty(final String name) {
260 return environment.get(name);
261 }
262
263
264
265
266
267
268
269
270 public String getStringProperty(final String name, final String defaultValue) {
271 final String prop = getStringProperty(name);
272 return (prop == null) ? defaultValue : prop;
273 }
274
275
276
277
278
279
280 public static Properties getSystemProperties() {
281 try {
282 return new Properties(System.getProperties());
283 } catch (final SecurityException ex) {
284 LowLevelLogUtil.logException("Unable to access system properties.", ex);
285
286 return new Properties();
287 }
288 }
289
290
291
292
293
294
295 public void reload() {
296 environment.reload();
297 }
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312 private static class Environment {
313
314 private final Set<PropertySource> sources = new TreeSet<>(new PropertySource.Comparator());
315 private final Map<CharSequence, String> literal = new ConcurrentHashMap<>();
316 private final Map<CharSequence, String> normalized = new ConcurrentHashMap<>();
317 private final Map<List<CharSequence>, String> tokenized = new ConcurrentHashMap<>();
318
319 private Environment(final PropertySource propertySource) {
320 PropertyFilePropertySource sysProps = new PropertyFilePropertySource(LOG4J_SYSTEM_PROPERTIES_FILE_NAME);
321 try {
322 sysProps.forEach(new BiConsumer<String, String>() {
323 @Override
324 public void accept(String key, String value) {
325 if (System.getProperty(key) == null) {
326 System.setProperty(key, value);
327 }
328 }
329 });
330 } catch (SecurityException ex) {
331
332 }
333 sources.add(propertySource);
334 for (final ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
335 try {
336 for (final PropertySource source : ServiceLoader.load(PropertySource.class, classLoader)) {
337 sources.add(source);
338 }
339 } catch (final Throwable ex) {
340
341
342
343 }
344 }
345
346 reload();
347 }
348
349 private synchronized void reload() {
350 literal.clear();
351 normalized.clear();
352 tokenized.clear();
353 for (final PropertySource source : sources) {
354 source.forEach(new BiConsumer<String, String>() {
355 @Override
356 public void accept(final String key, final String value) {
357 if (key != null && value != null) {
358 literal.put(key, value);
359 final List<CharSequence> tokens = PropertySource.Util.tokenize(key);
360 if (tokens.isEmpty()) {
361 normalized.put(source.getNormalForm(Collections.singleton(key)), value);
362 } else {
363 normalized.put(source.getNormalForm(tokens), value);
364 tokenized.put(tokens, value);
365 }
366 }
367 }
368 });
369 }
370 }
371
372 private static boolean hasSystemProperty(final String key) {
373 try {
374 return System.getProperties().containsKey(key);
375 } catch (final SecurityException ignored) {
376 return false;
377 }
378 }
379
380 private String get(final String key) {
381 if (normalized.containsKey(key)) {
382 return normalized.get(key);
383 }
384 if (literal.containsKey(key)) {
385 return literal.get(key);
386 }
387 if (hasSystemProperty(key)) {
388 return System.getProperty(key);
389 }
390 return tokenized.get(PropertySource.Util.tokenize(key));
391 }
392
393 private boolean containsKey(final String key) {
394 return normalized.containsKey(key) ||
395 literal.containsKey(key) ||
396 hasSystemProperty(key) ||
397 tokenized.containsKey(PropertySource.Util.tokenize(key));
398 }
399 }
400
401
402
403
404
405
406
407
408
409 public static Properties extractSubset(final Properties properties, final String prefix) {
410 final Properties subset = new Properties();
411
412 if (prefix == null || prefix.length() == 0) {
413 return subset;
414 }
415
416 final String prefixToMatch = prefix.charAt(prefix.length() - 1) != '.' ? prefix + '.' : prefix;
417
418 final List<String> keys = new ArrayList<>();
419
420 for (final String key : properties.stringPropertyNames()) {
421 if (key.startsWith(prefixToMatch)) {
422 subset.setProperty(key.substring(prefixToMatch.length()), properties.getProperty(key));
423 keys.add(key);
424 }
425 }
426 for (final String key : keys) {
427 properties.remove(key);
428 }
429
430 return subset;
431 }
432
433 static ResourceBundle getCharsetsResourceBundle() {
434 return ResourceBundle.getBundle("Log4j-charsets");
435 }
436
437
438
439
440
441
442
443
444
445 public static Map<String, Properties> partitionOnCommonPrefixes(final Properties properties) {
446 final Map<String, Properties> parts = new ConcurrentHashMap<>();
447 for (final String key : properties.stringPropertyNames()) {
448 final String prefix = key.substring(0, key.indexOf('.'));
449 if (!parts.containsKey(prefix)) {
450 parts.put(prefix, new Properties());
451 }
452 parts.get(prefix).setProperty(key.substring(key.indexOf('.') + 1), properties.getProperty(key));
453 }
454 return parts;
455 }
456
457
458
459
460
461
462 public boolean isOsWindows() {
463 return getStringProperty("os.name", "").startsWith("Windows");
464 }
465
466 }