package ca.hermeneuti.trombone.util; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.Map.Entry; /** * This class encapsulates flexible parameters that map keys to values, except * that values can be retrieved as various data types (String, int, long, boolean) and * arrays of an array of Strings. * @author Stéfan Sinclair * @deprecated */ public class FlexibleParameters implements Cloneable, Serializable { private static final long serialVersionUID = -2698890359540759874L; /* obsolete code private Map<String, List<Object>> objectEntries = new HashMap<String, List<Object>>(); public synchronized void addObjectParameters(String key, List<Object> values) { if (key == null) { throw new NullPointerException("illegal key"); } if (values == null) { throw new NullPointerException("illegal values"); } if (values.size() < 1) { throw new IllegalArgumentException("illegal values"); } if (this.objectEntries.put(key, values) != null) { throw new IllegalArgumentException("key "+key+" already mapped"); } } public synchronized List<Object> getObjectParameters(String key) { if (key == null) { throw new NullPointerException("illegal key"); } final List<Object> values = this.objectEntries.get(key); if (values == null) { throw new IllegalArgumentException("key "+key+" is not mapped"); } return values; } */ /** * An internal {@link Map} to facilitate looking up of properties. */ private final Map<String, List<String>> entries = new HashMap<String, List<String>>(); /** * Constructs a new instance of the {@link FlexibleParameters} class. */ public FlexibleParameters() { } /** * Constructs a new instance of the {@link FlexibleParameters} class and * parses the array of {@link String}s adhering to the {@code key=value} pattern. * * @param parameters the array of {@link String}s to add */ public FlexibleParameters(String[] parameters) { if (parameters == null) { throw new NullPointerException("illegal parameters"); } addParameters(parameters); } /** * Adds a parameter with a double value. Previously added values are not * discarded. * * @param key the key of the parameter * @param value the value of the parameter */ public synchronized void addParameter(String key, double value) { addParameterWithObject(key, value); } /** * Adds a parameter with an int value. Previously added values are not * discarded. * * @param key the key of the parameter * @param value the value of the parameter */ public synchronized void addParameter(String key, int value) { if (key == null) { throw new NullPointerException("illegal key"); } addParameterWithObject(key, value); } /** * Adds an array of int values for a parameter. Previously added values are * not discarded. * * @param key the key of the parameter * @param values the array of int values to add */ public synchronized void addParameter(String key, int[] values) { for (int v : values) { addParameter(key, v); } } /** * Adds a parameter with a long value. Previously added values are not * discarded. * * @param key the key of the parameter * @param value the value of the parameter */ public synchronized void addParameter(String key, long value) { if (key == null) { throw new NullPointerException("illegal key"); } addParameterWithObject(key, value); } /** * Adds a parameter with a String value. Previously added values are not * discarded. * * @param key the key of the parameter * @param value the value of the parameter */ public synchronized void addParameter(String key, String value) { if (key == null) { throw new NullPointerException("illegal key"); } if (value == null) { throw new NullPointerException("illegal value"); } addParameterWithObject(key, value); } /** * Adds an array of String values for a parameter. Previously added values * are not discarded. * * @param key the key of the parameter * @param values the array of {@link String}s as a value */ public synchronized void addParameter(String key, String[] values) { addParameterWithObjects(key, values); } /** * Adds parameters from an array of {@link String}s adhering to the {@code * key=value} pattern. Previously added values are not discarded. * * @param parameters an array of {@link String}s adhering to the {@code key=value} pattern */ public synchronized void addParameters(String[] parameters) { if (parameters == null) { throw new NullPointerException("illegal parameters"); } for (String parameter : parameters) { final String[] parts = parameter.split("=", 2); if (parts.length != 2) { throw new IllegalArgumentException(parameter+" is not a parameter"); } addParameter(parts[0], parts[1]); } } public synchronized void addProperties(Properties properties) { if (properties == null) { throw new NullPointerException("illegal Properties"); } for (Entry<Object, Object> entry : properties.entrySet()) { addParameter((String) entry.getKey(), (String) entry.getValue()); } } public synchronized void addProperties(FlexibleParameters properties) { if (properties == null) { throw new NullPointerException("illegal Properties"); } for (String key : properties.getKeys()) { this.entries.put(key, properties.entries.get(key)); } } /** * Add a single object to the map. Previously existing values are not discarded. * * @param key the key for the map * @param value object to add */ private synchronized void addParameterWithObject(String key, Object value) { if (key == null) { throw new NullPointerException("illegal key"); } if (value == null) { throw new NullPointerException("illegal value"); } if (this.entries.containsKey(key) == false) { this.entries.put(key, new ArrayList<String>()); } this.entries.get(key).add(String.valueOf(value)); } /** * Add an array of objects to the map. Previously existing values are not * discarded. * * @param key the key for the map * @param values the array of objects */ private synchronized void addParameterWithObjects(String key, Object[] values) { if (key == null) { throw new NullPointerException("illegal key"); } if (values == null) { throw new NullPointerException("illegal values"); } if (this.entries.containsKey(key) == false) { this.entries.put(key, new ArrayList<String>()); } final List<String> vals = this.entries.get(key); for (Object val : values) { vals.add(String.valueOf(val)); } } @Override public synchronized FlexibleParameters clone() { try { return (FlexibleParameters) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } public synchronized FlexibleParameters deepClone() { final FlexibleParameters clone = new FlexibleParameters(); for (Entry<String, List<String>> entry : this.entries.entrySet()) { final List<String> entryValueClone = new ArrayList<String>(); for (String s : entry.getValue()) { entryValueClone.add(new String(s)); } clone.entries.put(entry.getKey(), entryValueClone); } return clone; } /** * Determines if a parameter is defined with the specified key. * * @param key the key of the parameter * @return whether or not a parameter is defined with the specified key. */ public synchronized boolean containsKey(String key) { if (key == null) { throw new NullPointerException("illegal key"); } int counter = -1; while (true) { final String lookupKey = key + (counter < 0 ? "" : String.valueOf(counter)); if (this.entries.containsKey(lookupKey)) { return true; } else if (counter > 1) { break; } counter++; } return false; } public synchronized Set<String> getKeys() { return this.entries.keySet(); } /** * Returns a {@link Properties} view of all the properties. If a * key does not exist, a value of null is returned; if a key has multiple * values, only the last one is used. * @return a {@link Properties} view */ public synchronized Properties getAsProperties() { return getAsProperties(this.entries.keySet()); } /** * Returns a {@link Properties} view that includes the specified keys. If a * key does not exist, a value of null is returned; if a key has multiple * values, only the last one is used. * @param keys a list of keys for which to retrieve values * @return a {@link Properties} view */ public synchronized Properties getAsProperties(String... keys) { if (keys == null) { throw new NullPointerException("illegal keys"); } return getAsProperties(Arrays.asList(keys)); } /** * Returns a {@link Properties} view that includes the specified keys. If a * key does not exist, a value of null is returned; if a key has multiple * values, only the last one is used. * @param keys a list of keys for which to retrieve values * @return a {@link Properties} view */ public synchronized Properties getAsProperties(Collection<String> keys) { if (keys == null) { throw new NullPointerException("illegal keys"); } final Properties properties = new Properties(); for (String key : keys) { properties.put(key, getParameterValue(key)); } return properties; } /** * Returns a {@link String} view that can be used as a URL query. Each value * is URL encoded (in UTF-8) and a name can have multiple values: * <code>type=one&type=two</code * @return a {@link String} view */ public synchronized String getAsQueryString() throws UnsupportedEncodingException { final StringBuilder query = new StringBuilder(); for (Map.Entry<String, List<String>> entry : this.entries.entrySet()) { for (String value : entry.getValue()) { if (query.length()>0) query.append("&"); query.append(entry.getKey()).append("=").append(URLEncoder.encode(value, "UTF-8")); } } return query.toString(); } /** * Gets the parameter value as an float for the specified key. If the key is * not defined, then a value of 0 is returned. * * @param key the key for the parameter value * @return the parameter value as a float */ public synchronized float getParameterFloatValue(String key) { if (key == null) { throw new NullPointerException("illegal key"); } final String value = getParameterValue(key); return value == null || value.isEmpty() ? 0f : Float.parseFloat(value); } /** * Gets the parameter value as an float for the specified key, or return the * specified default value if the key does not exist. * * @param key the key for the parameter value * @return the parameter value as a float */ public synchronized float getParameterFloatValue(String key, float defaultValue) { if (key == null) { throw new NullPointerException("illegal key"); } final String value = getParameterValue(key); return value == null || value.isEmpty() ? defaultValue : Float.parseFloat(value); } /** * Gets the parameter value as an int for the specified key. If the key is * not defined, then a value of 0 is returned. * * @param key the key for the parameter value * @return the parameter value as an int */ public synchronized int getParameterIntValue(String key) { if (key == null) { throw new NullPointerException("illegal key"); } final String value = getParameterValue(key); return value == null || value.isEmpty() ? 0 : Integer.parseInt(value); } /** * Gets the parameter value as an int for the specified key, or return the * specified default value if the key does not exist. * * @param key the key for the parameter value * @param defaultValue the default value to use if the parameter is not set * @return the parameter value as an int */ public synchronized int getParameterIntValue(String key, int defaultValue) { if (key == null) { throw new NullPointerException("illegal key"); } final String value = getParameterValue(key); return value == null || value.length() == 0 ? defaultValue : Integer.parseInt(value); } /** * Gets the parameter value as an arrat of int values. If the key does not * exist, an empty array of ints is returned * * @param key the key for the parameter value * @return the parameter value as an int */ public synchronized int[] getParameterIntValues(String key) { if (key == null) { throw new NullPointerException("illegal key"); } final String[] values = getParameterValues(key); final int[] ints = new int[values.length]; for (int i = 0, size = values.length; i < size; i++) { ints[i] = values[i].isEmpty() ? 0 : Integer.valueOf(values[i]); } return ints; } /** * Gets the parameter value as a long for the specified key. If the key is * not defined, then a value of 0 is returned. * @param key the key for the parameter value * @return the parameter value as a long */ public synchronized long getParameterLongValue(String key) { final String value = getParameterValue(key); return value == null || value.isEmpty() ? 0l : Long.valueOf(value); } /** * Gets the parameter value as a long for the specified key, or return the * specified default value if the key does not exist. * * @param key the key for the parameter value * @param defaultValue the default value to use if the parameter is not set * @return the parameter value as a long */ public synchronized long getParameterLongValue(String key, long defaultValue) { if (key == null) { throw new NullPointerException("illegal key"); } final String value = getParameterValue(key); return value == null ? defaultValue : Long.valueOf(value); } /** * Gets the parameter value for the specified key. If the key is not defined, * then null is returned. * * @param key the key for the parameter value * @return the parameter value as a {@link String} */ public synchronized String getParameterValue(String key) { final String[] values = getParameterValues(key); // TODO: would it be more symmetrical to return "", more like the other methods? return values.length == 0 ? null : values[0]; } /** * Gets the parameter value for the specified key, or return the specified * default value if the key does not exist. * * @param key the key for the parameter value * @param defaultValue the default value to use if the parameter is not set * @return the parameter value as a {@link String} */ public synchronized String getParameterValue(String key, String defaultValue) { if (key == null) { throw new NullPointerException("illegal key"); } if (defaultValue == null) { throw new NullPointerException("illegal default value"); } final String value = getParameterValue(key); return value == null ? defaultValue : value; } /** * Gets an array of {@link String}s for the specified key. If the key is not * defined, then an empty array of Strings is returned. * * @param key the key for the parameter * @return an array of {@link String}s for the specified key */ public synchronized String[] getParameterValues(String key) { if (key == null) { throw new NullPointerException("illegal key"); } final List<String> values = this.entries.get(key); return values == null ? new String[0] : (String[]) values.toArray(new String[] {}); } /** * Gets a boolean value for the key (based on the first value for that key). * This will return false if the key is not defined, if the value is empty * or if the value is "false" or 0. * @param key the key for the parameter * @return a boolean for the specified key */ public synchronized boolean getParameterBooleanValue(String key) { if (key == null) { throw new NullPointerException("illegal key"); } final String val = getParameterValue(key); if (val==null || val.equals("false") || val.equals("0") || val.isEmpty()) { return false; } return true; } /** * Sets the specified parameter while removing any existing values that * might exist. * * @param key the key of the parameter * @param value the value of the parameter */ public synchronized void setParameter(String key, double value) { setParameterWithObject(key, value); } /** * Sets the specified parameter while removing any existing values that * might exist. * * @param key the key of the parameter * @param value the value of the parameter */ public synchronized void setParameter(String key, int value) { setParameterWithObject(key, value); } /** * Sets the specified parameter while removing any existing values that might exist. * @param key the key of the parameter * @param values the value of the parameter */ public synchronized void setParameter(String key, int[] values) { if (key == null) { throw new NullPointerException("illegal key"); } if (values == null) { throw new NullPointerException("illegal values"); } this.entries.remove(key); addParameter(key, values); } /** * Sets the specified parameter while removing any existing values that * might exist. * * @param key the key of the parameter * @param value the value of the parameter */ public synchronized void setParameter(String key, long value) { setParameterWithObject(key, value); } /** * Sets the specified parameter while removing any existing values that * might exist. * * @param key the key of the parameter * @param value the value of the parameter */ public synchronized void setParameter(String key, String value) { if (key == null) { throw new NullPointerException("illegal key"); } if (value == null) { throw new NullPointerException("illegal value"); } setParameterWithObject(key, value); } /** * Sets the specified parameter while removing any existing values that might exist. * @param key the key of the parameter * @param values the value of the parameter */ public synchronized void setParameter(String key, String[] values) { this.entries.remove(key); addParameter(key, values); } /** * Set the parameter, removing any previously existing values. * @param key * @param value */ private synchronized void setParameterWithObject(String key, Object value) { if (key == null) { throw new NullPointerException("illegal key"); } if (value == null) { throw new NullPointerException("illegal value"); } this.entries.remove(key); addParameterWithObject(key, value); } /* public void removeParameter(String key) { this.entries.remove(key); } */ @Override public synchronized String toString() { return this.entries.toString(); } public synchronized void removeParameter(String key) { if (key == null) { throw new NullPointerException("illegal key"); } this.entries.remove(key); } public synchronized int getKeyCount() { return this.entries.size(); } public synchronized int size() { int count = 0; for (List<String> values : this.entries.values()) { // yes, this could be optimized by maintining count in every instance method here above count += values.size(); } return count; } }