001 package org.apache.jcs.utils.config;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.util.Properties;
023
024 import org.apache.commons.logging.Log;
025 import org.apache.commons.logging.LogFactory;
026
027 /**
028 * This class is based on the log4j class org.apache.log4j.helpers.OptionConverter that was made by
029 * Ceki Gülcü Simon Kitching; Avy Sharell (sharell@online.fr) Anders Kristensen Matthieu
030 * Verbert (mve@zurich.ibm.com) A convenience class to convert property values to specific types.
031 */
032 public class OptionConverter
033 {
034 /** The logger */
035 private final static Log log = LogFactory.getLog( OptionConverter.class );
036
037 /** System property delimter */
038 static String DELIM_START = "${";
039
040 /** System property delimter */
041 static char DELIM_STOP = '}';
042
043 /** System property delimter start length */
044 static int DELIM_START_LEN = 2;
045
046 /** System property delimter end length */
047 static int DELIM_STOP_LEN = 1;
048
049 /** working buffer */
050 static StringBuffer sbuf = new StringBuffer();
051
052 /** No instances please. */
053 private OptionConverter()
054 {
055 super();
056 }
057
058 /**
059 * Combines two arrays.
060 * @param l
061 * @param r
062 * @return String[]
063 */
064 public static String[] concatanateArrays( String[] l, String[] r )
065 {
066 int len = l.length + r.length;
067 String[] a = new String[len];
068
069 System.arraycopy( l, 0, a, 0, l.length );
070 System.arraycopy( r, 0, a, l.length, r.length );
071
072 return a;
073 }
074
075 /**
076 * Escapes special characters.
077 * <p>
078 * @param s
079 * @return String
080 */
081 public static String convertSpecialChars( String s )
082 {
083 char c;
084 int len = s.length();
085 StringBuffer sbuf = new StringBuffer( len );
086
087 int i = 0;
088 while ( i < len )
089 {
090 c = s.charAt( i++ );
091 if ( c == '\\' )
092 {
093 c = s.charAt( i++ );
094 if ( c == 'n' )
095 {
096 c = '\n';
097 }
098 else if ( c == 'r' )
099 {
100 c = '\r';
101 }
102 else if ( c == 't' )
103 {
104 c = '\t';
105 }
106 else if ( c == 'f' )
107 {
108 c = '\f';
109 }
110 else if ( c == '\b' )
111 {
112 c = '\b';
113 }
114 else if ( c == '\"' )
115 {
116 c = '\"';
117 }
118 else if ( c == '\'' )
119 {
120 c = '\'';
121 }
122 else if ( c == '\\' )
123 {
124 c = '\\';
125 }
126 }
127 sbuf.append( c );
128 }
129 return sbuf.toString();
130 }
131
132 /**
133 * Very similar to <code>System.getProperty</code> except that the {@link SecurityException} is
134 * hidden.
135 * @param key The key to search for.
136 * @param def The default value to return.
137 * @return the string value of the system property, or the default value if there is no property
138 * with that key.
139 * @since 1.1
140 */
141
142 public static String getSystemProperty( String key, String def )
143 {
144 try
145 {
146 return System.getProperty( key, def );
147 }
148 catch ( Throwable e )
149 {
150 // MS-Java throws com.ms.security.SecurityExceptionEx
151 log.debug( "Was not allowed to read system property \"" + key + "\"." );
152 return def;
153 }
154 }
155
156 /**
157 * Creates an object for the className value of the key.
158 * <p>
159 * @param props
160 * @param key
161 * @param defaultValue
162 * @return Object that was created
163 */
164 public static <T> T instantiateByKey( Properties props, String key, T defaultValue )
165 {
166
167 // Get the value of the property in string form
168 String className = findAndSubst( key, props );
169 if ( className == null )
170 {
171 if ( log.isTraceEnabled() )
172 {
173 log.info( "Could not find value for key " + key );
174 }
175 return defaultValue;
176 }
177 // Trim className to avoid trailing spaces that cause problems.
178 return OptionConverter.instantiateByClassName( className.trim(), defaultValue );
179 }
180
181 /**
182 * If <code>value</code> is "true", then <code>true</code> is returned. If <code>value</code> is
183 * "false", then <code>true</code> is returned. Otherwise, <code>default</code> is returned.
184 * <p>
185 * Case of value is unimportant.
186 * @param value
187 * @param dEfault
188 * @return Object
189 */
190
191 public static boolean toBoolean( String value, boolean dEfault )
192 {
193 if ( value == null )
194 {
195 return dEfault;
196 }
197 String trimmedVal = value.trim();
198 if ( "true".equalsIgnoreCase( trimmedVal ) )
199 {
200 return true;
201 }
202 if ( "false".equalsIgnoreCase( trimmedVal ) )
203 {
204 return false;
205 }
206 return dEfault;
207 }
208
209 /**
210 * Converts to int.
211 * <p>
212 * @param value
213 * @param dEfault
214 * @return int
215 */
216 public static int toInt( String value, int dEfault )
217 {
218 if ( value != null )
219 {
220 String s = value.trim();
221 try
222 {
223 return Integer.valueOf( s ).intValue();
224 }
225 catch ( NumberFormatException e )
226 {
227 log.error( "[" + s + "] is not in proper int form." );
228 e.printStackTrace();
229 }
230 }
231 return dEfault;
232 }
233
234 /**
235 * @param value
236 * @param dEfault
237 * @return long
238 */
239 public static long toFileSize( String value, long dEfault )
240 {
241 if ( value == null )
242 {
243 return dEfault;
244 }
245
246 String s = value.trim().toUpperCase();
247 long multiplier = 1;
248 int index;
249
250 if ( ( index = s.indexOf( "KB" ) ) != -1 )
251 {
252 multiplier = 1024;
253 s = s.substring( 0, index );
254 }
255 else if ( ( index = s.indexOf( "MB" ) ) != -1 )
256 {
257 multiplier = 1024 * 1024;
258 s = s.substring( 0, index );
259 }
260 else if ( ( index = s.indexOf( "GB" ) ) != -1 )
261 {
262 multiplier = 1024 * 1024 * 1024;
263 s = s.substring( 0, index );
264 }
265 if ( s != null )
266 {
267 try
268 {
269 return Long.valueOf( s ).longValue() * multiplier;
270 }
271 catch ( NumberFormatException e )
272 {
273 log.error( "[" + s + "] is not in proper int form" );
274 log.error( "[" + value + "] not in expected format", e );
275 }
276 }
277 return dEfault;
278 }
279
280 /**
281 * Find the value corresponding to <code>key</code> in <code>props</code>. Then perform variable
282 * substitution on the found value.
283 * <p>
284 * @param key
285 * @param props
286 * @return substituted string
287 */
288
289 public static String findAndSubst( String key, Properties props )
290 {
291 String value = props.getProperty( key );
292 if ( value == null )
293 {
294 return null;
295 }
296
297 try
298 {
299 return substVars( value, props );
300 }
301 catch ( IllegalArgumentException e )
302 {
303 log.error( "Bad option value [" + value + "]", e );
304 return value;
305 }
306 }
307
308 /**
309 * Instantiate an object given a class name. Check that the <code>className</code> is a subclass
310 * of <code>superClass</code>. If that test fails or the object could not be instantiated, then
311 * <code>defaultValue</code> is returned.
312 * <p>
313 * @param className The fully qualified class name of the object to instantiate.
314 * @param defaultValue The object to return in case of non-fulfillment
315 * @return instantiated object
316 */
317
318 public static <T> T instantiateByClassName( String className, T defaultValue )
319 {
320 if ( className != null )
321 {
322 try
323 {
324 Class<?> classObj = Class.forName( className );
325 Object o = classObj.newInstance();
326
327 try
328 {
329 @SuppressWarnings("unchecked") // CCE catched
330 T t = (T) o;
331 return t;
332 }
333 catch (ClassCastException e)
334 {
335 log.error( "A \"" + className + "\" object is not assignable to the generic variable." );
336 return defaultValue;
337 }
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 values of keys found in the
349 * system properties.
350 * <p>
351 * The variable substitution delimeters are <b>${ </b> and <b>} </b>.
352 * <p>
353 * For example, if the System properties contains "key=value", then the call
354 *
355 * <pre>
356 * String s = OptionConverter.substituteVars( "Value of key is ${key}." );
357 * </pre>
358 *
359 * will set the variable <code>s</code> to "Value of key is value.".
360 * <p>
361 * If no value could be found for the specified key, then the <code>props</code> parameter is
362 * searched, if the value could not be found there, then substitution defaults to the empty
363 * string.
364 * <p>
365 * For example, if system propeties contains no value for the key "inexistentKey", then the call
366 *
367 * <pre>
368 * String s = OptionConverter.subsVars( "Value of inexistentKey is [${inexistentKey}]" );
369 * </pre>
370 *
371 * will set <code>s</code> to "Value of inexistentKey is []"
372 * <p>
373 * An {@link java.lang.IllegalArgumentException}is thrown if <code>val</code> contains a start
374 * delimeter "${" which is not balanced by a stop delimeter "}".
375 * </p>
376 * <p>
377 * <b>Author </b> Avy Sharell </a>
378 * </p>
379 * @param val The string on which variable substitution is performed.
380 * @param props
381 * @return String
382 * @throws IllegalArgumentException if <code>val</code> is malformed.
383 */
384
385 public static String substVars( String val, Properties props )
386 throws IllegalArgumentException
387 {
388 sbuf.setLength( 0 );
389
390 int i = 0;
391 int j;
392 int k;
393
394 while ( true )
395 {
396 j = val.indexOf( DELIM_START, i );
397 if ( j == -1 )
398 {
399 if ( i == 0 )
400 {
401 return val;
402 }
403 sbuf.append( val.substring( i, val.length() ) );
404 return sbuf.toString();
405 }
406 sbuf.append( val.substring( i, j ) );
407 k = val.indexOf( DELIM_STOP, j );
408 if ( k == -1 )
409 {
410 throw new IllegalArgumentException( '"' + val + "\" has no closing brace. Opening brace at position "
411 + j + '.' );
412 }
413 j += DELIM_START_LEN;
414 String key = val.substring( j, k );
415 // first try in System properties
416 String replacement = getSystemProperty( key, null );
417 // then try props parameter
418 if ( replacement == null && props != null )
419 {
420 replacement = props.getProperty( key );
421 }
422
423 if ( replacement != null )
424 {
425 sbuf.append( replacement );
426 }
427 i = k + DELIM_STOP_LEN;
428 }
429 }
430 }