1 package org.apache.jcs.config;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.Properties;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 /***
28 * This class is based on the log4j class
29 * org.apache.log4j.helpers.OptionConverter that was made by Ceki
30 * Gülcü Simon Kitching; Avy Sharell (sharell@online.fr) Anders
31 * Kristensen Matthieu Verbert (mve@zurich.ibm.com) A convenience class to
32 * convert property values to specific types.
33 *
34 */
35 public class OptionConverter
36 {
37 private final static Log log = LogFactory.getLog( OptionConverter.class );
38
39 static String DELIM_START = "${";
40
41 static char DELIM_STOP = '}';
42
43 static int DELIM_START_LEN = 2;
44
45 static int DELIM_STOP_LEN = 1;
46
47 static StringBuffer sbuf = new StringBuffer();
48
49 /*** No instances please. */
50 private OptionConverter()
51 {
52 super();
53 }
54
55 /***
56 * Combines two arrays.
57 *
58 * @param l
59 * @param r
60 * @return String[]
61 */
62 public static String[] concatanateArrays( String[] l, String[] r )
63 {
64 int len = l.length + r.length;
65 String[] a = new String[len];
66
67 System.arraycopy( l, 0, a, 0, l.length );
68 System.arraycopy( r, 0, a, l.length, r.length );
69
70 return a;
71 }
72
73 /***
74 * Escapes special cahracters/
75 *
76 * @param s
77 * @return String
78 */
79 public static String convertSpecialChars( String s )
80 {
81 char c;
82 int len = s.length();
83 StringBuffer sbuf = new StringBuffer( len );
84
85 int i = 0;
86 while ( i < len )
87 {
88 c = s.charAt( i++ );
89 if ( c == '//' )
90 {
91 c = s.charAt( i++ );
92 if ( c == 'n' )
93 {
94 c = '\n';
95 }
96 else if ( c == 'r' )
97 {
98 c = '\r';
99 }
100 else if ( c == 't' )
101 {
102 c = '\t';
103 }
104 else if ( c == 'f' )
105 {
106 c = '\f';
107 }
108 else if ( c == '\b' )
109 {
110 c = '\b';
111 }
112 else if ( c == '\"' )
113 {
114 c = '\"';
115 }
116 else if ( c == '\'' )
117 {
118 c = '\'';
119 }
120 else if ( c == '//' )
121 {
122 c = '//';
123 }
124 }
125 sbuf.append( c );
126 }
127 return sbuf.toString();
128 }
129
130 /***
131 * Very similar to <code>System.getProperty</code> except that the {@link
132 * SecurityException} is hidden.
133 *
134 * @param key
135 * The key to search for.
136 * @param def
137 * The default value to return.
138 * @return the string value of the system property, or the default value if
139 * there is no property with that key.
140 * @since 1.1
141 */
142
143 public static String getSystemProperty( String key, String def )
144 {
145 try
146 {
147 return System.getProperty( key, def );
148 }
149 catch ( Throwable e )
150 {
151
152 log.debug( "Was not allowed to read system property \"" + key + "\"." );
153 return def;
154 }
155 }
156
157 /***
158 * Creates an object for the className value of the key.
159 *
160 * @param props
161 * @param key
162 * @param superClass
163 * @param defaultValue
164 * @return Object that was created
165 */
166 public static Object instantiateByKey( Properties props, String key, Class superClass, Object defaultValue )
167 {
168
169
170 String className = findAndSubst( key, props );
171 if ( className == null )
172 {
173 if ( log.isTraceEnabled() )
174 {
175 log.info( "Could not find value for key " + key );
176 }
177 return defaultValue;
178 }
179
180 return OptionConverter.instantiateByClassName( className.trim(), superClass, defaultValue );
181 }
182
183 /***
184 * If <code>value</code> is "true", then <code>true</code> is returned.
185 * If <code>value</code> is "false", then <code>true</code> is returned.
186 * Otherwise, <code>default</code> is returned.
187 * <p>
188 *
189 * Case of value is unimportant.
190 * @param value
191 * @param dEfault
192 * @return Object
193 */
194
195 public static boolean toBoolean( String value, boolean dEfault )
196 {
197 if ( value == null )
198 {
199 return dEfault;
200 }
201 String trimmedVal = value.trim();
202 if ( "true".equalsIgnoreCase( trimmedVal ) )
203 {
204 return true;
205 }
206 if ( "false".equalsIgnoreCase( trimmedVal ) )
207 {
208 return false;
209 }
210 return dEfault;
211 }
212
213 /*** Description of the Method
214 * @param value
215 * @param dEfault
216 * @return
217 */
218 public static int toInt( String value, int dEfault )
219 {
220 if ( value != null )
221 {
222 String s = value.trim();
223 try
224 {
225 return Integer.valueOf( s ).intValue();
226 }
227 catch ( NumberFormatException e )
228 {
229 log.error( "[" + s + "] is not in proper int form." );
230 e.printStackTrace();
231 }
232 }
233 return dEfault;
234 }
235
236 /***
237 * @param value
238 * @param dEfault
239 * @return
240 */
241 public static long toFileSize( String value, long dEfault )
242 {
243 if ( value == null )
244 {
245 return dEfault;
246 }
247
248 String s = value.trim().toUpperCase();
249 long multiplier = 1;
250 int index;
251
252 if ( ( index = s.indexOf( "KB" ) ) != -1 )
253 {
254 multiplier = 1024;
255 s = s.substring( 0, index );
256 }
257 else if ( ( index = s.indexOf( "MB" ) ) != -1 )
258 {
259 multiplier = 1024 * 1024;
260 s = s.substring( 0, index );
261 }
262 else if ( ( index = s.indexOf( "GB" ) ) != -1 )
263 {
264 multiplier = 1024 * 1024 * 1024;
265 s = s.substring( 0, index );
266 }
267 if ( s != null )
268 {
269 try
270 {
271 return Long.valueOf( s ).longValue() * multiplier;
272 }
273 catch ( NumberFormatException e )
274 {
275 log.error( "[" + s + "] is not in proper int form" );
276 log.error( "[" + value + "] not in expected format", e );
277 }
278 }
279 return dEfault;
280 }
281
282 /***
283 * Find the value corresponding to <code>key</code> in <code>props</code>.
284 * Then perform variable substitution on the found value.
285 * @param key
286 * @param props
287 * @return
288 */
289
290 public static String findAndSubst( String key, Properties props )
291 {
292 String value = props.getProperty( key );
293 if ( value == null )
294 {
295 return null;
296 }
297
298 try
299 {
300 return substVars( value, props );
301 }
302 catch ( IllegalArgumentException e )
303 {
304 log.error( "Bad option value [" + value + "]", e );
305 return value;
306 }
307 }
308
309 /***
310 * Instantiate an object given a class name. Check that the
311 * <code>className</code> is a subclass of <code>superClass</code>. If
312 * that test fails or the object could not be instantiated, then
313 * <code>defaultValue</code> is returned.
314 *
315 * @param className
316 * The fully qualified class name of the object to instantiate.
317 * @param superClass
318 * The class to which the new object should belong.
319 * @param defaultValue
320 * The object to return in case of non-fulfillment
321 * @return
322 */
323
324 public static Object instantiateByClassName( String className, Class superClass, Object defaultValue )
325 {
326 if ( className != null )
327 {
328 try
329 {
330 Class classObj = Class.forName( className );
331 if ( !superClass.isAssignableFrom( classObj ) )
332 {
333 log.error( "A \"" + className + "\" object is not assignable to a \"" + superClass.getName()
334 + "\" variable." );
335 return defaultValue;
336 }
337 return classObj.newInstance();
338 }
339 catch ( Exception e )
340 {
341 log.error( "Could not instantiate class [" + className + "]", e );
342 }
343 }
344 return defaultValue;
345 }
346
347 /***
348 * Perform variable substitution in string <code>val</code> from the
349 * values of keys found in the system propeties.
350 * <p>
351 *
352 * The variable substitution delimeters are <b>${ </b> and <b>} </b>.
353 * <p>
354 *
355 * For example, if the System properties contains "key=value", then the call
356 *
357 * <pre>
358 * String s = OptionConverter.substituteVars( "Value of key is ${key}." );
359 * </pre>
360 *
361 * will set the variable <code>s</code> to "Value of key is value.".
362 * <p>
363 *
364 * If no value could be found for the specified key, then the
365 * <code>props</code> parameter is searched, if the value could not be
366 * found there, then substitution defaults to the empty string.
367 * <p>
368 *
369 * For example, if system propeties contains no value for the key
370 * "inexistentKey", then the call
371 *
372 * <pre>
373 * String s = OptionConverter.subsVars( "Value of inexistentKey is [${inexistentKey}]" );
374 * </pre>
375 *
376 * will set <code>s</code> to "Value of inexistentKey is []"
377 * <p>
378 *
379 * An {@link java.lang.IllegalArgumentException}is thrown if
380 * <code>val</code> contains a start delimeter "${" which is not balanced
381 * by a stop delimeter "}".
382 * </p>
383 * <p>
384 *
385 * <b>Author </b> Avy Sharell </a>
386 * </p>
387 *
388 * @param val
389 * The string on which variable substitution is performed.
390 * @param props
391 * @return String
392 * @throws IllegalArgumentException
393 * if <code>val</code> is malformed.
394 */
395
396 public static String substVars( String val, Properties props )
397 throws IllegalArgumentException
398 {
399 sbuf.setLength( 0 );
400
401 int i = 0;
402 int j;
403 int k;
404
405 while ( true )
406 {
407 j = val.indexOf( DELIM_START, i );
408 if ( j == -1 )
409 {
410 if ( i == 0 )
411 {
412 return val;
413 }
414 sbuf.append( val.substring( i, val.length() ) );
415 return sbuf.toString();
416 }
417 sbuf.append( val.substring( i, j ) );
418 k = val.indexOf( DELIM_STOP, j );
419 if ( k == -1 )
420 {
421 throw new IllegalArgumentException( '"' + val + "\" has no closing brace. Opening brace at position "
422 + j + '.' );
423 }
424 j += DELIM_START_LEN;
425 String key = val.substring( j, k );
426
427 String replacement = getSystemProperty( key, null );
428
429 if ( replacement == null && props != null )
430 {
431 replacement = props.getProperty( key );
432 }
433
434 if ( replacement != null )
435 {
436 sbuf.append( replacement );
437 }
438 i = k + DELIM_STOP_LEN;
439 }
440 }
441
442 }
443