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