PropertyReaderUtils.java |
/* * $Id: PropertyReaderUtils.java,v 1.62 2010/10/25 20:36:51 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.Iterator; import java.util.Properties; import org.xins.common.MandatoryArgumentChecker; import org.xins.common.text.FastStringBuffer; import org.xins.common.text.TextUtils; import org.xins.common.text.URLEncoding; /** * Utility functions for dealing with <code>PropertyReader</code> objects. * * @version $Revision: 1.62 $ $Date: 2010/10/25 20:36:51 $ * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a> * * @since XINS 1.0.0 * * @see PropertyReader * @deprecated Use MapStringUtils */ public final class PropertyReaderUtils { /** * An empty and unmodifiable <code>PropertyReader</code> instance. This * field is not <code>null</code>. * * @since XINS 1.1.0 */ public static final PropertyReader EMPTY_PROPERTY_READER = new ProtectedPropertyReader(new Object()); /** * Secret key object used when dealing with * <code>ProtectedPropertyReader</code> instances. */ private static final Object SECRET_KEY = new Object(); /** * Constructs a new <code>PropertyReaderUtils</code> object. This * constructor is marked as <code>private</code>, since no objects of this * class should be constructed. */ private PropertyReaderUtils() { // 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(PropertyReader properties, String propertyName, boolean fallbackDefault) throws IllegalArgumentException, InvalidPropertyValueException { // Check preconditions MandatoryArgumentChecker.check("properties", properties, "propertyName", propertyName); // Query the PropertyReader 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(PropertyReader properties, String propertyName) throws IllegalArgumentException, MissingRequiredPropertyException, InvalidPropertyValueException { // Check preconditions MandatoryArgumentChecker.check("properties", properties, "propertyName", propertyName); // Query the PropertyReader 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(PropertyReader 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>. * * @since XINS 2.1 */ public String getWithDefault(PropertyReader 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>PropertyReader</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 PropertyReader} 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 PropertyReader createPropertyReader(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 PropertyReader ProtectedPropertyReader r = new ProtectedPropertyReader(SECRET_KEY); 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.set(SECRET_KEY, key, value); } } return r; } /** * Serializes the specified <code>PropertyReader</code> to a * <code>FastStringBuffer</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 buffer for that * entry. * * @param properties * the {@link PropertyReader} to serialize, can be <code>null</code>. * * @param buffer * the buffer to write the serialized data to, cannot be * <code>null</code>. * * @param valueIfEmpty * the string to append to the buffer in case * <code>properties == null || properties.size() == 0</code>; if this * argument is <code>null</code>, however, then nothing will be appended * in the mentioned case. * * @throws IllegalArgumentException * if <code>properties == null || buffer == null</code>. * * @deprecated since XINS 2.0, use {@link #toString(PropertyReader, String)} */ public static void serialize(PropertyReader properties, FastStringBuffer buffer, String valueIfEmpty) throws IllegalArgumentException { // Check preconditions MandatoryArgumentChecker.check("buffer", buffer); // Catch special case: No properties available. if (properties == null || properties.size() == 0) { if (valueIfEmpty != null) { buffer.append(valueIfEmpty); } return; } // Loop over all properties Iterator names = properties.getNames(); boolean first = true; while (names.hasNext()) { // Get the name and value String name = (String) names.next(); String value = properties.get(name); // If the value is null or an empty string, then output nothing if (value == null) { continue; } // Append an ampersand, except for the first entry if (!first) { buffer.append('&'); } else { first = false; } // Append the key and the value, separated by an equals sign buffer.append(URLEncoding.encode(name)); buffer.append('='); buffer.append(URLEncoding.encode(value)); } } /** * Returns the String representation of the specified <code>PropertyReader</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 PropertyReader} to serialize, cannot be <code>null</code>. * * @return * the String representation of the specified <code>PropertyReader</code>. * * @since XINS 2.0. */ public static String toString(PropertyReader properties) { return toString(properties, null, null, null, -1); } /** * Serializes the specified <code>PropertyReader</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 PropertyReader} to serialize, can be <code>null</code>. * * @param valueIfEmpty * the string to append to the buffer in case * <code>properties == null || properties.size() == 0</code>. * * @return * the String representation of the PropertyReader or the valueIfEmpty, never <code>null</code>. * If all parameters are <code>null</code> then an empty String is returned. */ public static String toString(PropertyReader properties, String valueIfEmpty) { return toString(properties, valueIfEmpty, null, null, -1); } /** * Returns the <code>String</code> representation for the specified * <code>PropertyReader</code>. * * @param properties * the {@link PropertyReader} 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>PropertyReader</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 PropertyReaderis empty. * * @return * the String representation of the PropertyReader with the different artifacts, never <code>null</code>. * If all parameters are <code>null</code> then an empty String is returned. * * @since XINS 2.0 */ public static String toString(PropertyReader properties, String valueIfEmpty, String prefixIfNotEmpty, String suffix) { return toString(properties, valueIfEmpty, prefixIfNotEmpty, suffix, -1); } /** * Returns the <code>String</code> representation for the specified * <code>PropertyReader</code>. * * @param properties * the {@link PropertyReader} 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>PropertyReader</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 PropertyReaderis 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 PropertyReader with the different artifacts, never <code>null</code>. * If all parameters are <code>null</code> then an empty String is returned. * * @since XINS 2.0 */ public static String toString(PropertyReader properties, String valueIfEmpty, String prefixIfNotEmpty, String suffix, int maxValueLength) { // If the property set if null, return the fallback if (properties == null) { if (suffix != null) { return suffix; } else { return valueIfEmpty; } } Iterator names = properties.getNames(); // If there are no parameters, then return the fallback if (!names.hasNext()) { if (suffix != null) { return suffix; } else { return valueIfEmpty; } } StringBuffer buffer = new StringBuffer(299); boolean first = true; do { // Get the name and value String name = (String) names.next(); String value = properties.get(name); // 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); } while (names.hasNext()); if (suffix != null) { buffer.append('&'); buffer.append(suffix); } return buffer.toString(); } /** * Compares a <code>PropertyReader</code> instance with another object for * equality. * * @param pr * the <code>PropertyReader</code>, can be <code>null</code>. * * @param toCompare * the object to compare the <code>PropertyReader</code> with, * can be <code>null</code>. * * @return * <code>true</code> if the objects are considered to be equal, * <code>false</code> if they are considered different. * * @since XINS 2.1 */ public static final boolean equals(PropertyReader pr, Object toCompare) { // Test for identity equality if (pr == toCompare) { return true; } // If either one is null, then they are not equal (otherwise they would // both be null in which case they are identity equal) if (pr == null || toCompare == null) { return false; } // The 2nd object must implement the PropertyReader interface if (! (toCompare instanceof PropertyReader)) { return false; } // Size must be the same PropertyReader pr2 = (PropertyReader) toCompare; if (pr.size() != pr2.size()) { return false; } // Loop over all key/value pairs Iterator keys = pr.getNames(); while (keys.hasNext()) { String key = (String) keys.next(); String value1 = pr.get(key); String value2 = pr2.get(key); if (value1 == null && value2 != null) { return false; } else if (value1 != null && !value1.equals(value2)) { return false; } } // No differences found return true; } /** * Computes a hash code value for the specified <code>PropertyReader</code> * object. * * @param pr * the <code>PropertyReader</code> instance to compute a hash code value * for, cannot be <code>null</code>. * * @return * the hash code value. * * @throws NullPointerException * if <code>pr == null</code>. * * @since XINS 2.1 */ public static final int hashCode(PropertyReader pr) throws NullPointerException { int hash = 0; // Loop over all key/value pairs Iterator keys = pr.getNames(); while (keys.hasNext()) { String key = (String) keys.next(); String value = pr.get(key); // XOR the hash code value with the key string hash code if (key != null) { hash ^= key.hashCode(); } // XOR the hash code value with the key string hash code if (value != null) { hash ^= value.hashCode(); } } return hash; } }