1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.util;
18
19 import java.io.InterruptedIOException;
20 import java.util.Locale;
21 import java.util.Properties;
22
23 import org.apache.logging.log4j.Level;
24 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.status.StatusLogger;
26 import org.apache.logging.log4j.util.PropertiesUtil;
27 import org.apache.logging.log4j.util.Strings;
28
29
30
31
32 public final class OptionConverter {
33
34 private static final Logger LOGGER = StatusLogger.getLogger();
35
36 private static final String DELIM_START = "${";
37 private static final char DELIM_STOP = '}';
38 private static final int DELIM_START_LEN = 2;
39 private static final int DELIM_STOP_LEN = 1;
40 private static final int ONE_K = 1024;
41
42
43
44
45 private OptionConverter() {
46 }
47
48 public static String[] concatenateArrays(final String[] l, final String[] r) {
49 final int len = l.length + r.length;
50 final String[] a = new String[len];
51
52 System.arraycopy(l, 0, a, 0, l.length);
53 System.arraycopy(r, 0, a, l.length, r.length);
54
55 return a;
56 }
57
58 public static String convertSpecialChars(final String s) {
59 char c;
60 final int len = s.length();
61 final StringBuilder sbuf = new StringBuilder(len);
62
63 int i = 0;
64 while (i < len) {
65 c = s.charAt(i++);
66 if (c == '\\') {
67 c = s.charAt(i++);
68 switch (c) {
69 case 'n':
70 c = '\n';
71 break;
72 case 'r':
73 c = '\r';
74 break;
75 case 't':
76 c = '\t';
77 break;
78 case 'f':
79 c = '\f';
80 break;
81 case 'b':
82 c = '\b';
83 break;
84 case '"':
85 c = '\"';
86 break;
87 case '\'':
88 c = '\'';
89 break;
90 case '\\':
91 c = '\\';
92 break;
93 default:
94
95 }
96 }
97 sbuf.append(c);
98 }
99 return sbuf.toString();
100 }
101
102 public static Object instantiateByKey(final Properties props, final String key, final Class<?> superClass,
103 final Object defaultValue) {
104
105
106 final String className = findAndSubst(key, props);
107 if (className == null) {
108 LOGGER.error("Could not find value for key {}", key);
109 return defaultValue;
110 }
111
112 return OptionConverter.instantiateByClassName(className.trim(), superClass,
113 defaultValue);
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127 public static boolean toBoolean(final String value, final boolean defaultValue) {
128 if (value == null) {
129 return defaultValue;
130 }
131 final String trimmedVal = value.trim();
132 if ("true".equalsIgnoreCase(trimmedVal)) {
133 return true;
134 }
135 if ("false".equalsIgnoreCase(trimmedVal)) {
136 return false;
137 }
138 return defaultValue;
139 }
140
141
142
143
144
145
146
147 public static int toInt(final String value, final int defaultValue) {
148 if (value != null) {
149 final String s = value.trim();
150 try {
151 return Integer.parseInt(s);
152 } catch (final NumberFormatException e) {
153 LOGGER.error("[{}] is not in proper int form.", s, e);
154 }
155 }
156 return defaultValue;
157 }
158
159 public static Level toLevel(String value, Level defaultValue) {
160 if(value == null) {
161 return defaultValue;
162 }
163
164 value = value.trim();
165
166 int hashIndex = value.indexOf('#');
167 if (hashIndex == -1) {
168 if("NULL".equalsIgnoreCase(value)) {
169 return null;
170 } else {
171
172 return Level.toLevel(value, defaultValue);
173 }
174 }
175
176 Level result = defaultValue;
177
178 String clazz = value.substring(hashIndex+1);
179 String levelName = value.substring(0, hashIndex);
180
181
182 if("NULL".equalsIgnoreCase(levelName)) {
183 return null;
184 }
185
186 LOGGER.debug("toLevel" + ":class=[" + clazz + "]"
187 + ":pri=[" + levelName + "]");
188
189 try {
190 Class customLevel = Loader.loadClass(clazz);
191
192
193
194 Class[] paramTypes = new Class[] { String.class, Level.class
195 };
196 java.lang.reflect.Method toLevelMethod =
197 customLevel.getMethod("toLevel", paramTypes);
198
199
200 Object[] params = new Object[] {levelName, defaultValue};
201 Object o = toLevelMethod.invoke(null, params);
202
203 result = (Level) o;
204 } catch(ClassNotFoundException e) {
205 LOGGER.warn("custom level class [" + clazz + "] not found.");
206 } catch(NoSuchMethodException e) {
207 LOGGER.warn("custom level class [" + clazz + "]"
208 + " does not have a class function toLevel(String, Level)", e);
209 } catch(java.lang.reflect.InvocationTargetException e) {
210 if (e.getTargetException() instanceof InterruptedException
211 || e.getTargetException() instanceof InterruptedIOException) {
212 Thread.currentThread().interrupt();
213 }
214 LOGGER.warn("custom level class [" + clazz + "]" + " could not be instantiated", e);
215 } catch(ClassCastException e) {
216 LOGGER.warn("class [" + clazz + "] is not a subclass of org.apache.log4j.Level", e);
217 } catch(IllegalAccessException e) {
218 LOGGER.warn("class ["+clazz+ "] cannot be instantiated due to access restrictions", e);
219 } catch(RuntimeException e) {
220 LOGGER.warn("class ["+clazz+"], level [" + levelName + "] conversion failed.", e);
221 }
222 return result;
223 }
224
225
226
227
228
229
230
231 public static long toFileSize(final String value, final long defaultValue) {
232 if (value == null) {
233 return defaultValue;
234 }
235
236 String str = value.trim().toUpperCase(Locale.ENGLISH);
237 long multiplier = 1;
238 int index;
239
240 if ((index = str.indexOf("KB")) != -1) {
241 multiplier = ONE_K;
242 str = str.substring(0, index);
243 } else if ((index = str.indexOf("MB")) != -1) {
244 multiplier = ONE_K * ONE_K;
245 str = str.substring(0, index);
246 } else if ((index = str.indexOf("GB")) != -1) {
247 multiplier = ONE_K * ONE_K * ONE_K;
248 str = str.substring(0, index);
249 }
250 try {
251 return Long.parseLong(str) * multiplier;
252 } catch (final NumberFormatException e) {
253 LOGGER.error("[{}] is not in proper int form.", str);
254 LOGGER.error("[{}] not in expected format.", value, e);
255 }
256 return defaultValue;
257 }
258
259
260
261
262
263
264
265
266
267 public static String findAndSubst(final String key, final Properties props) {
268 final String value = props.getProperty(key);
269 if (value == null) {
270 return null;
271 }
272
273 try {
274 return substVars(value, props);
275 } catch (final IllegalArgumentException e) {
276 LOGGER.error("Bad option value [{}].", value, e);
277 return value;
278 }
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292 public static Object instantiateByClassName(final String className, final Class<?> superClass,
293 final Object defaultValue) {
294 if (className != null) {
295 try {
296 final Class<?> classObj = Loader.loadClass(className);
297 if (!superClass.isAssignableFrom(classObj)) {
298 LOGGER.error("A \"{}\" object is not assignable to a \"{}\" variable.", className,
299 superClass.getName());
300 LOGGER.error("The class \"{}\" was loaded by [{}] whereas object of type [{}] was loaded by [{}].",
301 superClass.getName(), superClass.getClassLoader(), classObj.getName());
302 return defaultValue;
303 }
304 return classObj.newInstance();
305 } catch (final Exception e) {
306 LOGGER.error("Could not instantiate class [{}].", className, e);
307 }
308 }
309 return defaultValue;
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349 public static String substVars(final String val, final Properties props) throws
350 IllegalArgumentException {
351
352 final StringBuilder sbuf = new StringBuilder();
353
354 int i = 0;
355 int j;
356 int k;
357
358 while (true) {
359 j = val.indexOf(DELIM_START, i);
360 if (j == -1) {
361
362 if (i == 0) {
363 return val;
364 }
365
366 sbuf.append(val.substring(i, val.length()));
367 return sbuf.toString();
368 }
369 sbuf.append(val.substring(i, j));
370 k = val.indexOf(DELIM_STOP, j);
371 if (k == -1) {
372 throw new IllegalArgumentException(Strings.dquote(val)
373 + " has no closing brace. Opening brace at position " + j
374 + '.');
375 }
376 j += DELIM_START_LEN;
377 final String key = val.substring(j, k);
378
379 String replacement = PropertiesUtil.getProperties().getStringProperty(key, null);
380
381 if (replacement == null && props != null) {
382 replacement = props.getProperty(key);
383 }
384
385 if (replacement != null) {
386
387
388
389
390
391 final String recursiveReplacement = substVars(replacement, props);
392 sbuf.append(recursiveReplacement);
393 }
394 i = k + DELIM_STOP_LEN;
395 }
396 }
397 }