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