001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.util;
015
016import java.lang.reflect.Constructor;
017import java.lang.reflect.InvocationTargetException;
018import java.util.Properties;
019
020import ch.qos.logback.core.Context;
021import ch.qos.logback.core.spi.ContextAware;
022import ch.qos.logback.core.spi.PropertyContainer;
023import ch.qos.logback.core.spi.ScanException;
024import ch.qos.logback.core.subst.NodeToStringTransformer;
025
026/**
027 * @author Ceki Gulcu
028 */
029public class OptionHelper {
030
031    public static Object instantiateByClassName(String className, Class<?> superClass, Context context)
032            throws IncompatibleClassException, DynamicClassLoadingException {
033        ClassLoader classLoader = Loader.getClassLoaderOfObject(context);
034        return instantiateByClassName(className, superClass, classLoader);
035    }
036
037    public static Object instantiateByClassNameAndParameter(String className, Class<?> superClass, Context context,
038            Class<?> type, Object param) throws IncompatibleClassException, DynamicClassLoadingException {
039        ClassLoader classLoader = Loader.getClassLoaderOfObject(context);
040        return instantiateByClassNameAndParameter(className, superClass, classLoader, type, param);
041    }
042
043    public static Object instantiateByClassName(String className, Class<?> superClass, ClassLoader classLoader)
044            throws IncompatibleClassException, DynamicClassLoadingException {
045        return instantiateByClassNameAndParameter(className, superClass, classLoader, null, null);
046    }
047
048
049    public static Object instantiateClassWithSuperclassRestriction(Class<?> classObj, Class<?> superClass)
050            throws IncompatibleClassException, DynamicClassLoadingException {
051        if (!superClass.isAssignableFrom(classObj)) {
052            throw new IncompatibleClassException(superClass, classObj);
053        }
054
055        try {
056            return classObj.getConstructor().newInstance();
057        } catch (NoSuchMethodException|InstantiationException|IllegalAccessException|InvocationTargetException e) {
058            throw new DynamicClassLoadingException("Failed to instantiate type " + classObj.getName(), e);
059        }
060    }
061
062    public static Object instantiateByClassNameAndParameter(String className, Class<?> superClass,
063            ClassLoader classLoader, Class<?> type, Object parameter)
064            throws IncompatibleClassException, DynamicClassLoadingException {
065
066        if (className == null) {
067            throw new NullPointerException();
068        }
069        try {
070            Class<?> classObj = null;
071            classObj = classLoader.loadClass(className);
072            if (!superClass.isAssignableFrom(classObj)) {
073                throw new IncompatibleClassException(superClass, classObj);
074            }
075            if (type == null) {
076                return classObj.getConstructor().newInstance();
077            } else {
078                Constructor<?> constructor = classObj.getConstructor(type);
079                return constructor.newInstance(parameter);
080            }
081        } catch (IncompatibleClassException ice) {
082            throw ice;
083        } catch (Throwable t) {
084            throw new DynamicClassLoadingException("Failed to instantiate type " + className, t);
085        }
086    }
087
088    /**
089     * Find the value corresponding to <code>key</code> in <code>props</code>. Then
090     * perform variable substitution on the found value.
091     */
092    // public static String findAndSubst(String key, Properties props) {
093    // String value = props.getProperty(key);
094    //
095    // if (value == null) {
096    // return null;
097    // }
098    //
099    // try {
100    // return substVars(value, props);
101    // } catch (IllegalArgumentException e) {
102    // return value;
103    // }
104    // }
105    final static String DELIM_START = "${";
106    final static char DELIM_STOP = '}';
107    final static String DELIM_DEFAULT = ":-";
108
109    final static int DELIM_START_LEN = 2;
110    final static int DELIM_STOP_LEN = 1;
111    final static int DELIM_DEFAULT_LEN = 2;
112
113    final static String _IS_UNDEFINED = "_IS_UNDEFINED";
114
115    /**
116     * @see #substVars(String, PropertyContainer, PropertyContainer)
117     */
118    public static String substVars(String val, PropertyContainer pc1) throws ScanException {
119        return substVars(val, pc1, null);
120    }
121
122    /**
123     * See http://logback.qos.ch/manual/configuration.html#variableSubstitution
124     */
125    public static String substVars(String input, PropertyContainer pc0, PropertyContainer pc1) throws ScanException {
126        // may throw IllegalArgumentException or ScanException
127        return NodeToStringTransformer.substituteVariable(input, pc0, pc1);
128
129    }
130
131    /**
132     * Try to lookup the property in the following order:
133     * <ol>
134     * <li>pc1 (the local property container, usually the {@link ch.qos.logback.core.model.processor.ModelInterpretationContext ModelInterpretationContext})</li>
135     * <li>pc2 (usually the {@link Context context})</li>
136     * <li>System properties</li>
137     * <li>Environment variables</li>
138     * </ol>
139     *
140     * @param key the property key
141     * @param pc1 the first property container to search
142     * @param pc2 the second property container to search
143     * @return the property value or null if not found
144     */
145    public static String propertyLookup(String key, PropertyContainer pc1, PropertyContainer pc2) {
146        String value = null;
147        // first try the props passed as parameter
148        value = pc1.getProperty(key);
149
150        // then try the pc2
151        if (value == null && pc2 != null) {
152            value = pc2.getProperty(key);
153        }
154        // then try in System properties
155        if (value == null) {
156            value = getSystemProperty(key, null);
157        }
158        if (value == null) {
159            value = getEnv(key);
160        }
161        return value;
162    }
163
164    /**
165     * Very similar to <code>System.getProperty</code> except that the
166     * {@link SecurityException} is absorbed.
167     *
168     * @param key The key to search for.
169     * @param def The default value to return.
170     * @return the string value of the system property, or the default value if
171     *         there is no property with that key.
172     */
173    public static String getSystemProperty(String key, String def) {
174        try {
175            return System.getProperty(key, def);
176        } catch (SecurityException e) {
177            return def;
178        }
179    }
180
181    /**
182     * Lookup a key from the environment.
183     *
184     * @param key
185     * @return value corresponding to key from the OS environment
186     */
187    public static String getEnv(String key) {
188        try {
189            return System.getenv(key);
190        } catch (SecurityException e) {
191            return null;
192        }
193    }
194
195    /**
196     * Very similar to <code>System.getProperty</code> except that the
197     * {@link SecurityException} is absorbed.
198     *
199     * @param key The key to search for.
200     * @return the string value of the system property.
201     */
202    public static String getSystemProperty(String key) {
203        try {
204            return System.getProperty(key);
205        } catch (SecurityException e) {
206            return null;
207        }
208    }
209
210    public static void setSystemProperties(ContextAware contextAware, Properties props) {
211        for (Object o : props.keySet()) {
212            String key = (String) o;
213            String value = props.getProperty(key);
214            setSystemProperty(contextAware, key, value);
215        }
216    }
217
218    public static void setSystemProperty(ContextAware contextAware, String key, String value) {
219        try {
220            System.setProperty(key, value);
221        } catch (SecurityException e) {
222            contextAware.addError("Failed to set system property [" + key + "]", e);
223        }
224    }
225
226    /**
227     * Very similar to {@link System#getProperties()} except that the
228     * {@link SecurityException} is absorbed.
229     *
230     * @return the system properties
231     */
232    public static Properties getSystemProperties() {
233        try {
234            return System.getProperties();
235        } catch (SecurityException e) {
236            return new Properties();
237        }
238    }
239
240    /**
241     * Return a String[] of size two. The first item containing the key part and the
242     * second item containing a default value specified by the user. The second item
243     * will be null if no default value is specified.
244     *
245     * @param key
246     * @return
247     */
248    static public String[] extractDefaultReplacement(String key) {
249        String[] result = new String[2];
250        if (key == null)
251            return result;
252
253        result[0] = key;
254        int d = key.indexOf(DELIM_DEFAULT);
255        if (d != -1) {
256            result[0] = key.substring(0, d);
257            result[1] = key.substring(d + DELIM_DEFAULT_LEN);
258        }
259        return result;
260    }
261
262    /**
263     * If <code>value</code> is "true", then <code>true</code> is returned. If
264     * <code>value</code> is "false", then <code>true</code> is returned. Otherwise,
265     * <code>default</code> is returned.
266     * <p>
267     * Case of value is unimportant.
268     */
269    public static boolean toBoolean(String value, boolean dEfault) {
270        if (value == null) {
271            return dEfault;
272        }
273
274        String trimmedVal = value.trim();
275
276        if ("true".equalsIgnoreCase(trimmedVal)) {
277            return true;
278        }
279
280        if ("false".equalsIgnoreCase(trimmedVal)) {
281            return false;
282        }
283
284        return dEfault;
285    }
286
287    /**
288     * @deprecated
289     * @since 1.3
290     */
291    public static boolean isEmpty(String str) {
292        return isNullOrEmptyOrAllSpaces(str);
293    }
294
295    /**
296     * Returns true if input str is null or empty.
297     * 
298     * @param str
299     * @return
300     */
301    public static boolean isNullOrEmpty(String str) {
302        return ((str == null) || str.trim().length() == 0);
303    }
304
305    /**
306     * isNullOrEmpty xisNullOrEmptyOrAllSpaces
307     * @param str
308     * @return
309     * @since  1.5.0
310     */
311    public static boolean isNullOrEmptyOrAllSpaces(String str) {
312        return ((str == null) || str.trim().length() == 0);
313    }
314
315
316    final public static boolean isNullOrEmpty(Object[] array) {
317        if(array == null || array.length == 0)
318                return true;
319        else
320                return false;
321    }
322
323    final public static boolean isNotEmtpy(Object[] array) {
324        return !isNullOrEmpty(array);
325    }
326}