/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.core.util; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.util.Enumeration; import java.util.Map; import java.util.Properties; import java.util.TreeMap; import org.teiid.runtime.client.Messages; import org.teiid.runtime.client.TeiidClientException; /** * */ public class PropertiesUtils { /** * Performs a correct deep clone of the properties object by capturing * all properties in the default(s) and placing them directly into the * new Properties object. If the input is an instance of * <code>UnmodifiableProperties</code>, this method returns an * <code>UnmodifiableProperties</code> instance around a new (flattened) * copy of the underlying Properties object. */ public static Properties clone( Properties props ) { return clone(props, null, false); } /** * Performs a correct deep clone of the properties object by capturing * all properties in the default(s) and placing them directly into the * new Properties object. If the input is an instance of * <code>UnmodifiableProperties</code>, this method returns an * <code>UnmodifiableProperties</code> instance around a new (flattened) * copy of the underlying Properties object. */ public static Properties clone( Properties props, Properties defaults, boolean deepClone ) { Properties result = null; if ( defaults != null ) { if ( deepClone ) { defaults = clone(defaults); } result = new Properties(defaults); } else { result = new Properties(); } putAll(result, props); return result; } /** * <p>This method is intended to replace the use of the <code>putAll</code> * method of <code>Properties</code> inherited from <code>java.util.Hashtable</code>. * The problem with that method is that, since it is inherited from * <code>Hashtable</code>, <i>default</i> properties are lost. * </p> * <p>For example, the following code * <pre><code> * Properties a; * Properties b; * //initialize ... * a.putAll(b); * </code></pre> * will fail <i>if</i> <code>b</code> had been constructed with a default * <code>Properties</code> object. Those defaults would be lost and * not added to <code>a</code>.</p> * * <p>The above code could be correctly performed with this method, * like this: * <pre><code> * Properties a; * Properties b; * //initialize ... * PropertiesUtils.putAll(a,b); * </code></pre> * In the above example, <code>a</code> is modified - properties are added to * it (note that if <code>a</code> has defaults they will remain unaffected.) * The properties from <code>b</code>, <i>including defaults</i>, will be * added to <code>a</code> using its <code>setProperty</code> method - * these new properties will overwrite any pre-existing ones of the same * name. * </p> * * @param addToThis This Properties object is modified; the properties * of the other parameter are added to this. The added property values * will replace any current property values of the same names. * @param withThese The properties (including defaults) of this * object are added to the "addToThis" parameter. */ public static void putAll(Properties addToThis, Properties withThese) { if ( withThese != null && addToThis != null ) { Enumeration enumeration = withThese.propertyNames(); while ( enumeration.hasMoreElements() ) { String propName = (String) enumeration.nextElement(); Object propValue = withThese.get(propName); if ( propValue == null ) { //defaults can only be retrieved as strings propValue = withThese.getProperty(propName); } if ( propValue != null ) { addToThis.put(propName, propValue); } } } } public static boolean getBooleanProperty(Properties props, String propName, boolean defaultValue) { String stringVal = props.getProperty(propName); if (stringVal == null) { return defaultValue; } stringVal = stringVal.trim(); if (stringVal.length() == 0) { return defaultValue; } try { return Boolean.valueOf(stringVal); } catch (NumberFormatException e) { String msg = Messages.getString(Messages.InvalidPropertyException.message, propName, stringVal, Float.class.getSimpleName()); throw new RuntimeException(new TeiidClientException(e, msg)); } } public static int getIntProperty(Properties props, String propName, int defaultValue) { String stringVal = props.getProperty(propName); if(stringVal == null) { return defaultValue; } stringVal = stringVal.trim(); if (stringVal.length() == 0) { return defaultValue; } try { return Integer.parseInt(stringVal); } catch(NumberFormatException e) { String msg = Messages.getString(Messages.InvalidPropertyException.message, propName, stringVal, Integer.class.getSimpleName()); throw new RuntimeException(new TeiidClientException(e, msg)); } } /** A table of hex digits */ private static final char[] hexDigit = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; /** * Convert a nibble to a hex character * @param nibble the nibble to convert. */ public static char toHex(int nibble) { return hexDigit[(nibble & 0xF)]; } public static String toHex(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (byte b : bytes) { sb.append(toHex(b >>> 4)); sb.append(toHex(b)); } return sb.toString(); } public static void toHex(StringBuilder sb, InputStream is) throws IOException { int i = 0; while ((i = is.read()) != -1) { byte b = (byte)i; sb.append(toHex(b >>> 4)); sb.append(toHex(b)); } } public static void setBeanProperties(Object bean, Properties props, String prefix) { setBeanProperties(bean, props, prefix, false); } public static void setBeanProperties(Object bean, Properties props, String prefix, boolean caseSensitive) { // Move all prop names to lower case so we can use reflection to get // method names and look them up in the connection props. Map<?, ?> map = props; if (!caseSensitive) { map = caseInsensitiveProps(props); } final Method[] methods = bean.getClass().getMethods(); for (int i = 0; i < methods.length; i++) { final Method method = methods[i]; final String methodName = method.getName(); // If setter ... if (! methodName.startsWith("set") || method.getParameterTypes().length != 1 ) { //$NON-NLS-1$ continue; } // Get the property name String propertyName = methodName.substring(3); // remove the "set" if (prefix != null) { if (caseSensitive) { propertyName = prefix + "." + Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1, propertyName.length()); //$NON-NLS-1$ } else { propertyName = prefix + "." + propertyName; //$NON-NLS-1$ } } Object propertyValue = map.get(propertyName); if (propertyValue != null || map.containsKey(propertyName)) { setProperty(bean, propertyValue, method, propertyName); } } } public static void setBeanProperty(Object bean, String name, Object value) { final Method[] methods = bean.getClass().getMethods(); for (int i = 0; i < methods.length; i++) { final Method method = methods[i]; final String methodName = method.getName(); // If setter ... if (! methodName.startsWith("set") || method.getParameterTypes().length != 1 || !StringUtil.endsWithIgnoreCase(methodName, name)) { //$NON-NLS-1$ continue; } // Get the property name final String propertyName = methodName.substring(3); // remove the "set" setProperty(bean, value, method, propertyName); } } private static Class<?> setProperty(Object bean, Object value, final Method method, final String propertyName) { final Class<?> argType = method.getParameterTypes()[0]; try { Object[] params = new Object[] {value}; if (value != null && !argType.isAssignableFrom(value.getClass())) { params = new Object[] {StringUtil.valueOf(value.toString(), argType)}; } method.invoke(bean, params); } catch (Throwable e) { String msg = Messages.getString(Messages.InvalidPropertyException.message, propertyName, value, argType); throw new RuntimeException(new TeiidClientException(e, msg)); } return argType; } private static TreeMap<String, String> caseInsensitiveProps(final Properties connectionProps) { final TreeMap<String, String> caseInsensitive = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER); final Enumeration<?> itr = connectionProps.propertyNames(); while ( itr.hasMoreElements() ) { final String name = (String) itr.nextElement(); String propValue = connectionProps.getProperty(name); if (propValue != null || connectionProps.containsKey(name)) { caseInsensitive.put(name, propValue); } } return caseInsensitive; } }