View Javadoc

1   /**
2    * Logback: the generic, reliable, fast and flexible logging framework.
3    * 
4    * Copyright (C) 1999-2006, QOS.ch
5    * 
6    * This library is free software, you can redistribute it and/or modify it under
7    * the terms of the GNU Lesser General Public License as published by the Free
8    * Software Foundation.
9    */
10  package ch.qos.logback.core.util;
11  
12  
13  import java.util.Properties;
14  
15  import ch.qos.logback.core.Context;
16  import ch.qos.logback.core.CoreConstants;
17  import ch.qos.logback.core.spi.PropertyContainer;
18  
19  /**
20   * @author Ceki Gulcu
21   */
22  public class OptionHelper {
23  
24    public static Object instantiateByClassName(String className,
25        Class superClass, Context context) throws IncompatibleClassException, DynamicClassLoadingException {
26      ClassLoader classLoader = context.getClass().getClassLoader();
27      return instantiateByClassName(className, superClass, classLoader);
28    }
29    
30    @SuppressWarnings("unchecked")
31    public static Object instantiateByClassName(String className,
32        Class superClass, ClassLoader classLoader)
33        throws IncompatibleClassException, DynamicClassLoadingException {
34  
35      if (className == null) {
36        throw new NullPointerException();
37      }
38  
39      try {
40        Class classObj = null;
41        classObj = classLoader.loadClass(className);
42        if (!superClass.isAssignableFrom(classObj)) {
43          throw new IncompatibleClassException(superClass, classObj);
44        }
45        return classObj.newInstance();
46      } catch (IncompatibleClassException ice) {
47        throw ice;
48      } catch (Throwable t) {
49        throw new DynamicClassLoadingException("Failed to instantiate type "
50            + className, t);
51      }
52    }
53  
54    /**
55     * Find the value corresponding to <code>key</code> in <code>props</code>.
56     * Then perform variable substitution on the found value.
57     * 
58     */
59    // public static String findAndSubst(String key, Properties props) {
60    // String value = props.getProperty(key);
61    //
62    // if (value == null) {
63    // return null;
64    // }
65    //
66    // try {
67    // return substVars(value, props);
68    // } catch (IllegalArgumentException e) {
69    // return value;
70    // }
71    // }
72    final static String DELIM_START = "${";
73    final static char DELIM_STOP = '}';
74    final static int DELIM_START_LEN = 2;
75    final static int DELIM_STOP_LEN = 1;
76    final static String _IS_UNDEFINED = "_IS_UNDEFINED";
77    
78    /**
79     * Perform variable substitution in string <code>val</code> from the values
80     * of keys found in context property map, and if that fails, then in the
81     * system properties.
82     * 
83     * <p>
84     * The variable substitution delimeters are <b>${</b> and <b>}</b>.
85     * 
86     * <p>
87     * For example, if the context property map contains a property "key1" set as
88     * "value1", then the call
89     * 
90     * <pre>
91     * String s = OptionConverter.substituteVars(&quot;Value of key is ${key1}.&quot;, context);</pre>
92     * will set the variable <code>s</code> to "Value of key is value1.".
93     * 
94     * <p>
95     * If no value could be found for the specified key in the context map, then 
96     * the system properties are searched, if that fails, then substitution defaults 
97     * to appending "_IS_UNDEFINED" to the key name.
98     * 
99     * <p>
100    * For example, if not the context not the system properties contains no value for the key
101    * "inexistentKey", then the call
102    * 
103    * <pre>
104    * String s = OptionConverter.subsVars(
105    *     &quot;Value of inexistentKey is [${inexistentKey}]&quot;, context);</pre>
106    * will set <code>s</code> to "Value of inexistentKey is [inexistentKey_IS_UNDEFINED]".
107    * 
108    * <p>
109    * Nevertheless, it is possible to specify a default substitution value using
110    * the ":-" operator. For example, the call
111    * 
112    * <pre>
113    * String s = OptionConverter.subsVars(&quot;Value of key is [${key2:-val2}]&quot;, context);</pre>
114    * will set <code>s</code> to "Value of key is [val2]" even if the "key2"
115    * property is not set.
116    * 
117    * <p>
118    * An {@link java.lang.IllegalArgumentException} is thrown if <code>val</code>
119    * contains a start delimeter "${" which is not balanced by a stop delimeter
120    * "}".
121    * </p>
122 
123    * 
124    * @param val
125    *          The string on which variable substitution is performed.
126    * @throws IllegalArgumentException
127    *           if <code>val</code> is malformed.
128    */
129   public static String substVars(String val, PropertyContainer pc) {
130 
131     StringBuffer sbuf = new StringBuffer();
132 
133     int i = 0;
134     int j;
135     int k;
136 
137     while (true) {
138       j = val.indexOf(DELIM_START, i);
139 
140       if (j == -1) {
141         // no more variables
142         if (i == 0) { // this is a simple string
143 
144           return val;
145         } else { // add the tail string which contails no variables and return
146           // the result.
147           sbuf.append(val.substring(i, val.length()));
148 
149           return sbuf.toString();
150         }
151       } else {
152         sbuf.append(val.substring(i, j));
153         k = val.indexOf(DELIM_STOP, j);
154 
155         if (k == -1) {
156           throw new IllegalArgumentException('"' + val
157               + "\" has no closing brace. Opening brace at position " + j + '.');
158         } else {
159           j += DELIM_START_LEN;
160 
161           String rawKey = val.substring(j, k);
162 
163           // Massage the key to extract a default replacement if there is one
164           String[] extracted = extractDefaultReplacement(rawKey);
165           String key = extracted[0];
166           String defaultReplacement = extracted[1]; // can be null
167 
168           String replacement = null;
169 
170           // first try the props passed as parameter
171           replacement = pc.getProperty(key);
172 
173           // then try in System properties
174           if (replacement == null) {
175             replacement = getSystemProperty(key, null);
176           }
177 
178           // if replacement is still null, use the defaultReplacement which
179           // can be null as well
180           if (replacement == null) {
181             replacement = defaultReplacement;
182           }
183 
184           if (replacement != null) {
185             // Do variable substitution on the replacement string
186             // such that we can solve "Hello ${x2}" as "Hello p1"
187             // where the properties are
188             // x1=p1
189             // x2=${x1}
190             String recursiveReplacement = substVars(replacement, pc);
191             sbuf.append(recursiveReplacement);
192           } else {
193             // if we could not find a replacement, then signal the error
194             sbuf.append(key+"_IS_UNDEFINED");
195           }
196 
197           i = k + DELIM_STOP_LEN;
198         }
199       }
200     }
201   }
202 
203   /**
204    * Very similar to <code>System.getProperty</code> except that the
205    * {@link SecurityException} is absorbed.
206    * 
207    * @param key
208    *          The key to search for.
209    * @param def
210    *          The default value to return.
211    * @return the string value of the system property, or the default value if
212    *         there is no property with that key.
213    */
214   public static String getSystemProperty(String key, String def) {
215     try {
216       return System.getProperty(key, def);
217     } catch (SecurityException e) {
218       return def;
219     }
220   }
221 
222   /**
223    * Very similar to <code>System.getProperty</code> except that the
224    * {@link SecurityException} is absorbed.
225    * 
226    * @param key
227    *          The key to search for.
228 
229    * @return the string value of the system property.
230    */
231   public static String getSystemProperty(String key) {
232     try {
233       return System.getProperty(key);
234     } catch (SecurityException e) {
235       return null;
236     }
237   }
238   /**
239    * Very similar to {@link System#getProperties()} except that the
240    * {@link SecurityException} is absorbed.
241    * 
242    * @return the system properties
243    */
244   public static Properties getSystemProperties() {
245     try {
246       return System.getProperties();
247     } catch (SecurityException e) {
248       return new Properties();
249     }
250   }
251   
252   static public String[] extractDefaultReplacement(String key) {
253     String[] result = new String[2];
254     result[0] = key;
255     int d = key.indexOf(":-");
256     if (d != -1) {
257       result[0] = key.substring(0, d);
258       result[1] = key.substring(d + 2);
259     }
260     return result;
261   }
262 
263   /**
264    * If <code>value</code> is "true", then <code>true</code> is returned. If
265    * <code>value</code> is "false", then <code>true</code> is returned.
266    * Otherwise, <code>default</code> is returned.
267    * 
268    * <p>
269    * Case of value is unimportant.
270    */
271   public static boolean toBoolean(String value, boolean dEfault) {
272     if (value == null) {
273       return dEfault;
274     }
275 
276     String trimmedVal = value.trim();
277 
278     if ("true".equalsIgnoreCase(trimmedVal)) {
279       return true;
280     }
281 
282     if ("false".equalsIgnoreCase(trimmedVal)) {
283       return false;
284     }
285 
286     return dEfault;
287   }
288 
289   public static boolean isEmpty(String val) {
290     return ((val == null) || CoreConstants.EMPTY_STRING.equals(val));
291   }
292 
293 }