package edu.stanford.nlp.util; import java.io.IOException; import java.io.PrintStream; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.Type; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.Map.Entry; public class PropertiesUtils { private PropertiesUtils() {} /** * Returns true iff the given Properties contains a property with the given * key (name), and its value is not "false" or "no" or "off". * * @param props Properties object * @param key The key to test * @return true iff the given Properties contains a property with the given * key (name), and its value is not "false" or "no" or "off". */ public static boolean hasProperty(Properties props, String key) { String value = props.getProperty(key); if (value == null) { return false; } value = value.toLowerCase(); return ! (value.equals("false") || value.equals("no") || value.equals("off")); } // Convert from properties to string and from string to properties public static String asString(Properties props) { try { StringWriter sw = new StringWriter(); props.store(sw, null); return sw.toString(); } catch (IOException ex) { throw new RuntimeException(ex); } } public static Properties fromString(String str) { try { StringReader sr = new StringReader(str); Properties props = new Properties(); props.load(sr); return props; } catch (IOException ex) { throw new RuntimeException(ex); } } // printing ------------------------------------------------------------------- public static void printProperties(String message, Properties properties, PrintStream stream) { if (message != null) { stream.println(message); } if (properties.isEmpty()) { stream.println(" [empty]"); } else { List<Map.Entry<String, String>> entries = getSortedEntries(properties); for (Map.Entry<String, String> entry : entries) { if ( ! "".equals(entry.getKey())) { stream.format(" %-30s = %s%n", entry.getKey(), entry.getValue()); } } } stream.println(); } public static void printProperties(String message, Properties properties) { printProperties(message, properties, System.out); } /** * Tired of Properties not behaving like {@code Map<String,String>}s? This method will solve that problem for you. */ public static Map<String, String> asMap(Properties properties) { Map<String, String> map = Generics.newHashMap(); for (Entry<Object, Object> entry : properties.entrySet()) { map.put((String)entry.getKey(), (String)entry.getValue()); } return map; } public static List<Map.Entry<String, String>> getSortedEntries(Properties properties) { return Maps.sortedEntries(asMap(properties)); } /** * Checks to make sure that all properties specified in <code>properties</code> * are known to the program by checking that each simply overrides * a default value. * * @param properties Current properties * @param defaults Default properties which lists all known keys */ @SuppressWarnings("unchecked") public static void checkProperties(Properties properties, Properties defaults) { Set<String> names = Generics.newHashSet(); for (Enumeration<String> e = (Enumeration<String>) properties.propertyNames(); e.hasMoreElements(); ) { names.add(e.nextElement()); } for (Enumeration<String> e = (Enumeration<String>) defaults.propertyNames(); e.hasMoreElements(); ) { names.remove(e.nextElement()); } if (!names.isEmpty()) { if (names.size() == 1) { throw new IllegalArgumentException("Unknown property: " + names.iterator().next()); } else { throw new IllegalArgumentException("Unknown properties: " + names); } } } /** * Get the value of a property and automatically cast it to a specific type. * This differs from the original Properties.getProperty() method in that you * need to specify the desired type (e.g. Double.class) and the default value * is an object of that type, i.e. a double 0.0 instead of the String "0.0". */ @SuppressWarnings("unchecked") public static <E> E get(Properties props, String key, E defaultValue, Type type) { String value = props.getProperty(key); if (value == null) { return defaultValue; } else { return (E) MetaClass.cast(value, type); } } /** * Load an integer property. If the key is not present, returns defaultValue. */ public static String getString(Properties props, String key, String defaultValue) { String value = props.getProperty(key); if (value != null) { return value; } else { return defaultValue; } } /** * Load an integer property. If the key is not present, returns 0. */ public static int getInt(Properties props, String key) { return getInt(props, key, 0); } /** * Load an integer property. If the key is not present, returns defaultValue. */ public static int getInt(Properties props, String key, int defaultValue) { String value = props.getProperty(key); if (value != null) { return Integer.parseInt(value); } else { return defaultValue; } } /** * Load an integer property as a long. * If the key is not present, returns defaultValue. */ public static long getLong(Properties props, String key, long defaultValue) { String value = props.getProperty(key); if (value != null) { return Long.parseLong(value); } else { return defaultValue; } } /** * Load a double property. If the key is not present, returns 0.0. */ public static double getDouble(Properties props, String key) { return getDouble(props, key, 0.0); } /** * Load a double property. If the key is not present, returns defaultValue. */ public static double getDouble(Properties props, String key, double defaultValue) { String value = props.getProperty(key); if (value != null) { return Double.parseDouble(value); } else { return defaultValue; } } /** * Load a boolean property. If the key is not present, returns false. */ public static boolean getBool(Properties props, String key) { return getBool(props, key, false); } /** * Load a boolean property. If the key is not present, returns defaultValue. */ public static boolean getBool(Properties props, String key, boolean defaultValue) { String value = props.getProperty(key); if (value != null) { return Boolean.parseBoolean(value); } else { return defaultValue; } } /** * Loads a comma-separated list of integers from Properties. The list cannot include any whitespace. */ public static int[] getIntArray(Properties props, String key) { Integer[] result = MetaClass.cast(props.getProperty(key), Integer [].class); return ArrayUtils.toPrimitive(result); } /** * Loads a comma-separated list of doubles from Properties. The list cannot include any whitespace. */ public static double[] getDoubleArray(Properties props, String key) { Double[] result = MetaClass.cast(props.getProperty(key), Double [].class); return ArrayUtils.toPrimitive(result); } /** * Loads a comma-separated list of strings from Properties. Commas may be quoted if needed, e.g.: * property1 = value1,value2,"a quoted value",'another quoted value' * * getStringArray(props, "property1") should return the same thing as * new String[] { "value1", "value2", "a quoted value", "another quoted value" }; */ public static String[] getStringArray(Properties props, String key) { String[] results = MetaClass.cast(props.getProperty(key), String [].class); if (results == null) { results = new String[]{}; } return results; } public static String[] getStringArray(Properties props, String key, String[] defaults) { String[] results = MetaClass.cast(props.getProperty(key), String [].class); if (results == null) { results = defaults; } return results; } public static class Property { public String name; public String defaultValue; public String description; public Property(String name, String defaultValue, String description) { this.name = name; this.defaultValue = defaultValue; this.description = description; } } public static String getSignature(String name, Properties properties, Property[] supportedProperties) { String prefix = (name != null && !name.isEmpty())? name + ".":""; // keep track of all relevant properties for this annotator here! StringBuilder sb = new StringBuilder(); for (Property p:supportedProperties) { String pname = prefix + p.name; String pvalue = properties.getProperty(pname, p.defaultValue); sb.append(pname).append(":").append(pvalue); } return sb.toString(); } }