MapStringUtils.java |
/* * $Id: MapStringUtils.java,v 1.3 2012/03/15 21:07:39 agoubard Exp $ * * See the COPYRIGHT file for redistribution and use restrictions. */ package org.xins.common.collections; import java.io.InputStream; import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import org.xins.common.MandatoryArgumentChecker; import org.xins.common.text.TextUtils; import org.xins.common.text.URLEncoding; /** * Utility functions for dealing with <code>Map<String, String></code> objects. * * @version $Revision: 1.3 $ $Date: 2012/03/15 21:07:39 $ * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a> * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a> * * @since XINS 3.0.0 */ public final class MapStringUtils { /** * Constructs a new <code>MapStringUtils</code> object. This * constructor is marked as <code>private</code>, since no objects of this * class should be constructed. */ private MapStringUtils() { // empty } /** * Gets the property with the specified name and converts it to a * <code>boolean</code>. * * @param properties * the set of properties to read from, cannot be <code>null</code>. * * @param propertyName * the name of the property to read, cannot be <code>null</code>. * * @param fallbackDefault * the fallback default value, returned if the value of the property is * either <code>null</code> or <code>""</code> (an empty string). * * @return * the value of the property. * * @throws IllegalArgumentException * if <code>properties == null || propertyName == null</code>. * * @throws InvalidPropertyValueException * if the value of the property is neither <code>null</code> nor * <code>""</code> (an empty string), nor <code>"true"</code> nor * <code>"false"</code>. */ public static boolean getBooleanProperty(Map<String, String> properties, String propertyName, boolean fallbackDefault) throws IllegalArgumentException, InvalidPropertyValueException { // Check preconditions MandatoryArgumentChecker.check("properties", properties, "propertyName", propertyName); // Query the Map<String, String> String value = properties.get(propertyName); // Fallback to the default, if necessary if (TextUtils.isEmpty(value)) { return fallbackDefault; } // Parse the string if ("true".equals(value)) { return true; } else if ("false".equals(value)) { return false; } else { throw new InvalidPropertyValueException(propertyName, value); } } /** * Gets the property with the specified name and converts it to an * <code>int</code>. * * @param properties * the set of properties to read from, cannot be <code>null</code>. * * @param propertyName * the name of the property to read, cannot be <code>null</code>. * * @return * the value of the property, as an <code>int</code>. * * @throws IllegalArgumentException * if <code>properties == null || propertyName == null</code>. * * @throws MissingRequiredPropertyException * if the specified property is not set, or if it is set to an empty * string. * * @throws InvalidPropertyValueException * if the conversion to an <code>int</code> failed. */ public static int getIntProperty(Map<String, String> properties, String propertyName) throws IllegalArgumentException, MissingRequiredPropertyException, InvalidPropertyValueException { // Check preconditions MandatoryArgumentChecker.check("properties", properties, "propertyName", propertyName); // Query the Map<String, String> String value = properties.get(propertyName); // Make sure the value is set if (value == null || value.length() == 0) { throw new MissingRequiredPropertyException(propertyName); } // Parse the string try { return Integer.parseInt(value); } catch (NumberFormatException exception) { throw new InvalidPropertyValueException(propertyName, value); } } /** * Retrieves the specified property and throws a * <code>MissingRequiredPropertyException</code> if it is not set. * * @param properties * the set of properties to retrieve a specific proeprty from, cannot be * <code>null</code>. * * @param name * the name of the property, cannot be <code>null</code>. * * @return * the value of the property, guaranteed not to be <code>null</code> and * guaranteed to contain at least one character. * * @throws IllegalArgumentException * if <code>properties == null || name == null</code>. * * @throws MissingRequiredPropertyException * if the value of the property is either <code>null</code> or an empty * string. */ public static String getRequiredProperty(Map<String, String> properties, String name) throws IllegalArgumentException, MissingRequiredPropertyException { // Check preconditions MandatoryArgumentChecker.check("properties", properties, "name", name); // Retrieve the value String value = properties.get(name); // The property is required if (value == null || value.length() < 1) { throw new MissingRequiredPropertyException(name); } return value; } /** * Retrieves a property with the specified name, falling back to a default * value if the property is not set. * * @param properties * the set of properties to retrieve a property from, * cannot be <code>null</code>. * * @param key * the property key, * cannot be <code>null</code>. * * @param fallbackValue * the fallback default value, returned in case the property is not set * in <code>properties</code>, cannot be <code>null</code>. * * @return * the value of the property or the fallback value. * * @throws IllegalArgumentException * if <code>properties == null || key == null || fallbackValue == null</code>. */ public String getWithDefault(Map<String, String> properties, String key, String fallbackValue) throws IllegalArgumentException { // Check preconditions MandatoryArgumentChecker.check("properties", properties, "key", key, "fallbackValue", fallbackValue); // Get value String value = properties.get(key); if (value != null) { return value; // Fallback if necessary } else { return fallbackValue; } } /** * Constructs a <code>Map<String, String></code> from the specified input * stream. * * <p>The parsing done is similar to the parsing done by the * {@link Properties#load(InputStream)} method. Empty values will be * ignored. * * @param in * the input stream to read from, cannot be <code>null</code>. * * @return * a {@link Map} instance that contains all the properties * defined in the specified input stream. * * @throws IllegalArgumentException * if <code>in == null</code>. * * @throws IOException * if there was an I/O error while reading from the stream. */ public static Map<String, String> createMapString(InputStream in) throws IllegalArgumentException, IOException { // Check preconditions MandatoryArgumentChecker.check("in", in); // Parse the input stream using java.util.Properties Properties properties = new Properties(); properties.load(in); // Convert from java.util.Properties to Map<String, String> Map<String, String> r = new HashMap<String, String>(); Enumeration names = properties.propertyNames(); while (names.hasMoreElements()) { String key = (String) names.nextElement(); String value = properties.getProperty(key); if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) { r.put(key, value); } } return r; } /** * Returns the String representation of the specified <code>Map<String, String></code>. * For each entry, both the key and the value are encoded using the URL * encoding (see {@link URLEncoding}). * The key and value are separated by a literal equals sign * (<code>'='</code>). The entries are separated using an ampersand * (<code>'&'</code>). * * <p>If the value for an entry is either <code>null</code> or an empty * string (<code>""</code>), then nothing is added to the String for that * entry. * * @param properties * the {@link Map} to serialize, cannot be <code>null</code>. * * @return * the String representation of the specified <code>Map<String, String></code>. */ public static String toString(Map<String, String> properties) { return toString(properties, null, null, null, -1); } /** * Serializes the specified <code>MapMap<String, String></code> to a * <code>String</code>. For each entry, both the key and the * value are encoded using the URL encoding (see {@link URLEncoding}). * The key and value are separated by a literal equals sign * (<code>'='</code>). The entries are separated using * an ampersand (<code>'&'</code>). * * <p>If the value for an entry is either <code>null</code> or an empty * string (<code>""</code>), then nothing is added to the String for that * entry. * * @param properties * the {@link Map} to serialize, can be <code>null</code>. * * @param valueIfEmpty * the string to append to the buffer in case * <code>properties == null || properties.isEmpty()</code>. * * @return * the String representation of the Map<String, String> or the valueIfEmpty, never <code>null</code>. * If all parameters are <code>null</code> then an empty String is returned. */ public static String toString(Map<String, String> properties, String valueIfEmpty) { return toString(properties, valueIfEmpty, null, null, -1); } /** * Returns the <code>String</code> representation for the specified * <code>Map<String, String></code>. * * @param properties * the {@link Map} to construct a String for, or <code>null</code>. * * @param valueIfEmpty * the value to return if the specified set of properties is either * <code>null</code> or empty, can be <code>null</code>. * * @param prefixIfNotEmpty * the prefix to add to the value if the <code>Map<String, String></code> * is not empty, can be <code>null</code>. * * @param suffix * the suffix to add to the value, can be <code>null</code>. The suffix * will be added even if the Map<String, String> is empty. * * @return * the String representation of the Map<String, String> with the different artifacts, never <code>null</code>. * If all parameters are <code>null</code> then an empty String is returned. */ public static String toString(Map<String, String> properties, String valueIfEmpty, String prefixIfNotEmpty, String suffix) { return toString(properties, valueIfEmpty, prefixIfNotEmpty, suffix, -1); } /** * Returns the <code>String</code> representation for the specified * <code>Map<String, String></code>. * * @param properties * the {@link Map} to construct a String for, or <code>null</code>. * * @param valueIfEmpty * the value to return if the specified set of properties is either * <code>null</code> or empty, can be <code>null</code>. * * @param prefixIfNotEmpty * the prefix to add to the value if the <code>Map<String, String></code> * is not empty, can be <code>null</code>. * * @param suffix * the suffix to add to the value, can be <code>null</code>. The suffix * will be added even if the Map<String, String>is empty. * * @param maxValueLength * the maximum of characters to set for the value, if the value is longer * than this limit '...' will be added after the limit. * If the value is -1, no limit will be set. * * @return * the String representation of the Map<String, String> with the different artifacts, never <code>null</code>. * If all parameters are <code>null</code> then an empty String is returned. */ public static String toString(Map<String, String> properties, String valueIfEmpty, String prefixIfNotEmpty, String suffix, int maxValueLength) { // If the property set if null, return the fallback if (properties == null || properties.isEmpty()) { if (suffix != null) { return suffix; } else { return valueIfEmpty; } } StringBuffer buffer = new StringBuffer(299); boolean first = true; for (Entry<String, String> property : properties.entrySet()) { // Get the name and value String name = property.getKey(); String value = property.getValue(); // If the value is null or an empty string, then output nothing if (value == null || value.length() == 0) { continue; } // Append an ampersand, except for the first entry if (!first) { buffer.append('&'); } else { first = false; if (prefixIfNotEmpty != null) { buffer.append(prefixIfNotEmpty); } } // Append the key and the value, separated by an equals sign buffer.append(URLEncoding.encode(name)); buffer.append('='); String encodedValue; if (maxValueLength == -1 || value.length() <= maxValueLength) { encodedValue = URLEncoding.encode(value); } else { encodedValue = URLEncoding.encode(value.substring(0, maxValueLength)) + "..."; } buffer.append(encodedValue); } if (suffix != null) { buffer.append('&'); buffer.append(suffix); } return buffer.toString(); } /** * Converts the specified <code>Properties</code> object to a new * <code>Map<String, String></code> object. * * @param properties * the {@link Properties} object, cannot be <code>null</code>. * * @return * a new {@link Map} object, never <code>null</code>. * * @throws IllegalArgumentException * if <code>properties == null</code>. */ public static Map<String, String> fromProperties(Properties properties) throws IllegalArgumentException { // Check preconditions MandatoryArgumentChecker.check("properties", properties); Map<String, String> prop = new HashMap<String, String>(); for (Entry<Object, Object> property : properties.entrySet()) { String name = (String) property.getKey(); String value = (String) property.getValue(); prop.put(name, value); } return prop; } /** * Converts the specified <code>Map<String, String></code> object to a new * <code>Properties</code> object. * * @param properties * the {@link Map} object, cannot be <code>null</code>. * * @return * a new {@link Properties} object, never <code>null</code>. * * @throws IllegalArgumentException * if <code>properties == null</code>. */ public static Properties toProperties(Map<String, String> properties) throws IllegalArgumentException { // Check preconditions MandatoryArgumentChecker.check("properties", properties); Properties prop = new Properties(); for (Entry<String, String> property : properties.entrySet()) { String name = property.getKey(); String value = property.getValue(); prop.setProperty(name, value); } return prop; } }