Hi guys,
Thanks again for inspecting this problem with me and hashing out my various
options. I have taken the liberty of making some modifications to 2 classes
in Commons Configuration (attached) in order to get it to do what I wanted.
Is it possible to contribute this to Commons Configuration? I've tried to
do a good job in this code change by providing the test case. I plan to use
commons configuration for as long as I can think and would hate to have to
make this change for every new version I get.
The summary of these changes is that I added a Boolean flag to tell the
interpolation algorithm whether to substitute using the entire multi-valued
property or just the first value. I.e., an if statement determining whether
getString or getPoroperty are used. I added a test case for this in what I
think is the appropriate place.
My exact changes are as follows:
TestBaseConfiguration.java(592): test case for making sure flag switches
behaviour properly.
public void testMultiValuedPropertyInterpolation() throws Exception
{
config.setProperty("multi", "value1");
config.addProperty("multi", "value2");
config.setProperty("interpolated", "${multi}");
config.setInterpolateAllValues(false);
String expectedValue = "value1";
assertEquals(config.getString("interpolated"),
expectedValue);
config.setInterpolateAllValues(true);
expectedValue = "" + config.getProperty("multi");
assertEquals(config.getString("interpolated"),
expectedValue);
}
Abstractconfiguration.java(59): added flag
/**
* Determines whether all values of a property are used or just
*the first when
* substituting tokens.
*/
private boolean interpolateAllValues = true;
Abstractconfiguration.java(209): the if statement in interpolateHelper() to
use getString or getProperty:
Object value;
if (isInterpolateAllValues())
{
value = getProperty(variable);
}
else
{
value = getString(variable);
}
Abstractconfiguration.java(977): setter and getter for flag:
public void setInterpolateAllValues(boolean b)
{
this.interpolateAllValues = b;
}
public boolean isInterpolateAllValues()
{
return interpolateAllValues;
}
> -----Original Message-----
> From: Emmanuel Bourg [mailto:[EMAIL PROTECTED]
> Sent: Tuesday, August 23, 2005 8:49 AM
> To: Jakarta Commons Users List
> Subject: Re: [configuration] Property Substitution Policy
>
> Hi Moran,
>
> Moran Ben-David wrote:
>
> > I was actually trying to get the substitution to only use the 1st value
> in a
> > multi-valued property. For example, a file like
> >
> > V1 = value1
> > V1 = value2
> > Myprop = ${V1}
> >
> > Would result in a configuration having
> >
> > Myprop = value1
> >
> > This way, when I do config.getString("Myprop") I'd get "value1" and not
> > "[value1, value2]".
>
> I tend to agree on this, the interpolated value should be a scalar, this
> would be consistent with the getString() method called on a multi-valued
> property.
>
> However regarding your use case I agree with Oliver, using a
> CompositeConfiguration is the right solution. You can build it
> programatically, or use the ConfigurationFactory with a configuration
> descriptor.
>
> Emmanuel Bourg
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.configuration;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Properties;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.iterators.FilterIterator;
import org.apache.commons.lang.BooleanUtils;
/**
* Abstract configuration class. Provide basic functionality but does not store
* any data. If you want to write your own Configuration class then you should
* implement only abstract methods from this class.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Konstantin Shaposhnikov </a>
* @author <a href="mailto:[EMAIL PROTECTED]">Oliver Heger </a>
* @author <a href="mailto:[EMAIL PROTECTED]">Henning P. Schmiedehausen </a>
* @version $Id: AbstractConfiguration.java,v 1.29 2004/12/02 22:05:52 ebourg
* Exp $
*/
public abstract class AbstractConfiguration implements Configuration
{
/** start token */
protected static final String START_TOKEN = "${";
/** end token */
protected static final String END_TOKEN = "}";
/** The property delimiter used while parsing (a comma). */
private static char DELIMITER = ',';
/**
* Whether the configuration should throw NoSuchElementExceptions or simply
* return null when a property does not exist. Defaults to return null.
*/
private boolean throwExceptionOnMissing = false;
/**
* Determines whether all values of a property are used or just the first when
* substituting tokens.
*/
private boolean interpolateAllValues = true;
/**
* For configurations extending AbstractConfiguration, allow them to change
* the delimiter from the default comma (",").
*
* @param delimiter The new delimiter
*/
public static void setDelimiter(char delimiter)
{
AbstractConfiguration.DELIMITER = delimiter;
}
/**
* Retrieve the current delimiter. By default this is a comma (",").
*
* @return The delimiter in use
*/
public static char getDelimiter()
{
return AbstractConfiguration.DELIMITER;
}
/**
* If set to false, missing elements return null if possible (for objects).
*
* @param throwExceptionOnMissing The new value for the property
*/
public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing)
{
this.throwExceptionOnMissing = throwExceptionOnMissing;
}
/**
* Returns true if missing values throw Exceptions.
*
* @return true if missing values throw Exceptions
*/
public boolean isThrowExceptionOnMissing()
{
return throwExceptionOnMissing;
}
/**
* [EMAIL PROTECTED]
*/
public void addProperty(String key, Object value)
{
Iterator it = PropertyConverter.toIterator(value, DELIMITER);
while (it.hasNext())
{
addPropertyDirect(key, it.next());
}
}
/**
* Adds a key/value pair to the Configuration. Override this method to
* provide write acces to underlying Configuration store.
*
* @param key key to use for mapping
* @param obj object to store
*/
protected abstract void addPropertyDirect(String key, Object obj);
/**
* interpolate key names to handle ${key} stuff
*
* @param base string to interpolate
*
* @return returns the key name with the ${key} substituted
*/
protected String interpolate(String base)
{
return interpolateHelper(base, null);
}
/**
* Recursive handler for multple levels of interpolation.
*
* When called the first time, priorVariables should be null.
*
* @param base string with the ${key} variables
* @param priorVariables serves two purposes: to allow checking for loops,
* and creating a meaningful exception message should a loop occur. It's
* 0'th element will be set to the value of base from the first call. All
* subsequent interpolated variables are added afterward.
*
* @return the string with the interpolation taken care of
*/
protected String interpolateHelper(String base, List priorVariables)
{
if (base == null)
{
return null;
}
// on the first call initialize priorVariables
// and add base as the first element
if (priorVariables == null)
{
priorVariables = new ArrayList();
priorVariables.add(base);
}
int begin = -1;
int end = -1;
int prec = 0 - END_TOKEN.length();
String variable = null;
StringBuffer result = new StringBuffer();
// FIXME: we should probably allow the escaping of the start token
while (((begin = base.indexOf(START_TOKEN, prec + END_TOKEN.length())) > -1)
&& ((end = base.indexOf(END_TOKEN, begin)) > -1))
{
result.append(base.substring(prec + END_TOKEN.length(), begin));
variable = base.substring(begin + START_TOKEN.length(), end);
// if we've got a loop, create a useful exception message and throw
if (priorVariables.contains(variable))
{
String initialBase = priorVariables.remove(0).toString();
priorVariables.add(variable);
StringBuffer priorVariableSb = new StringBuffer();
// create a nice trace of interpolated variables like so:
// var1->var2->var3
for (Iterator it = priorVariables.iterator(); it.hasNext();)
{
priorVariableSb.append(it.next());
if (it.hasNext())
{
priorVariableSb.append("->");
}
}
throw new IllegalStateException("infinite loop in property interpolation of " + initialBase + ": "
+ priorVariableSb.toString());
}
// otherwise, add this variable to the interpolation list.
else
{
priorVariables.add(variable);
}
Object value;
if (isInterpolateAllValues())
{
value = getProperty(variable);
}
else
{
value = getString(variable);
}
if (value != null)
{
result.append(interpolateHelper(value.toString(), priorVariables));
// pop the interpolated variable off the stack
// this maintains priorVariables correctness for
// properties with multiple interpolations, e.g.
// prop.name=${some.other.prop1}/blahblah/${some.other.prop2}
priorVariables.remove(priorVariables.size() - 1);
}
else
{
//variable not defined - so put it back in the value
result.append(START_TOKEN).append(variable).append(END_TOKEN);
}
prec = end;
}
result.append(base.substring(prec + END_TOKEN.length(), base.length()));
return result.toString();
}
/**
* [EMAIL PROTECTED]
*/
public Configuration subset(String prefix)
{
return new SubsetConfiguration(this, prefix, ".");
}
/**
* [EMAIL PROTECTED]
*/
public abstract boolean isEmpty();
/**
* [EMAIL PROTECTED]
*/
public abstract boolean containsKey(String key);
/**
* [EMAIL PROTECTED]
*/
public void setProperty(String key, Object value)
{
clearProperty(key);
addProperty(key, value);
}
/**
* [EMAIL PROTECTED]
*/
public abstract void clearProperty(String key);
/**
* [EMAIL PROTECTED]
*/
public void clear()
{
Iterator it = getKeys();
while (it.hasNext())
{
String key = (String) it.next();
it.remove();
if (containsKey(key))
{
// workaround for Iterators that do not remove the property on calling remove()
clearProperty(key);
}
}
}
/**
* [EMAIL PROTECTED]
*/
public abstract Iterator getKeys();
/**
* [EMAIL PROTECTED]
*/
public Iterator getKeys(final String prefix)
{
return new FilterIterator(getKeys(), new Predicate()
{
public boolean evaluate(Object obj)
{
String key = (String) obj;
return key.startsWith(prefix + ".") || key.equals(prefix);
}
});
}
/**
* [EMAIL PROTECTED]
*/
public Properties getProperties(String key)
{
return getProperties(key, null);
}
/**
* Get a list of properties associated with the given configuration key.
*
* @param key The configuration key.
* @param defaults Any default values for the returned
* <code>Properties</code> object. Ignored if <code>null</code>.
*
* @return The associated properties if key is found.
*
* @throws ConversionException is thrown if the key maps to an object that
* is not a String/List of Strings.
*
* @throws IllegalArgumentException if one of the tokens is malformed (does
* not contain an equals sign).
*/
public Properties getProperties(String key, Properties defaults)
{
/*
* Grab an array of the tokens for this key.
*/
String[] tokens = getStringArray(key);
/*
* Each token is of the form 'key=value'.
*/
Properties props = defaults == null ? new Properties() : new Properties(defaults);
for (int i = 0; i < tokens.length; i++)
{
String token = tokens[i];
int equalSign = token.indexOf('=');
if (equalSign > 0)
{
String pkey = token.substring(0, equalSign).trim();
String pvalue = token.substring(equalSign + 1).trim();
props.put(pkey, pvalue);
}
else if (tokens.length == 1 && "".equals(token))
{
// Semantically equivalent to an empty Properties
// object.
break;
}
else
{
throw new IllegalArgumentException('\'' + token + "' does not contain an equals sign");
}
}
return props;
}
/**
* [EMAIL PROTECTED]
*/
public boolean getBoolean(String key)
{
Boolean b = getBoolean(key, null);
if (b != null)
{
return b.booleanValue();
}
else
{
throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
}
}
/**
* [EMAIL PROTECTED]
*/
public boolean getBoolean(String key, boolean defaultValue)
{
return getBoolean(key, BooleanUtils.toBooleanObject(defaultValue)).booleanValue();
}
/**
* [EMAIL PROTECTED]
*/
public Boolean getBoolean(String key, Boolean defaultValue)
{
Object value = resolveContainerStore(key);
if (value == null)
{
return defaultValue;
}
else
{
try
{
return PropertyConverter.toBoolean(value);
}
catch (ConversionException e)
{
throw new ConversionException('\'' + key + "' doesn't map to a Boolean object", e);
}
}
}
/**
* [EMAIL PROTECTED]
*/
public byte getByte(String key)
{
Byte b = getByte(key, null);
if (b != null)
{
return b.byteValue();
}
else
{
throw new NoSuchElementException('\'' + key + " doesn't map to an existing object");
}
}
/**
* [EMAIL PROTECTED]
*/
public byte getByte(String key, byte defaultValue)
{
return getByte(key, new Byte(defaultValue)).byteValue();
}
/**
* [EMAIL PROTECTED]
*/
public Byte getByte(String key, Byte defaultValue)
{
Object value = resolveContainerStore(key);
if (value == null)
{
return defaultValue;
}
else
{
try
{
return PropertyConverter.toByte(value);
}
catch (ConversionException e)
{
throw new ConversionException('\'' + key + "' doesn't map to a Byte object", e);
}
}
}
/**
* [EMAIL PROTECTED]
*/
public double getDouble(String key)
{
Double d = getDouble(key, null);
if (d != null)
{
return d.doubleValue();
}
else
{
throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
}
}
/**
* [EMAIL PROTECTED]
*/
public double getDouble(String key, double defaultValue)
{
return getDouble(key, new Double(defaultValue)).doubleValue();
}
/**
* [EMAIL PROTECTED]
*/
public Double getDouble(String key, Double defaultValue)
{
Object value = resolveContainerStore(key);
if (value == null)
{
return defaultValue;
}
else
{
try
{
return PropertyConverter.toDouble(value);
}
catch (ConversionException e)
{
throw new ConversionException('\'' + key + "' doesn't map to a Double object", e);
}
}
}
/**
* [EMAIL PROTECTED]
*/
public float getFloat(String key)
{
Float f = getFloat(key, null);
if (f != null)
{
return f.floatValue();
}
else
{
throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
}
}
/**
* [EMAIL PROTECTED]
*/
public float getFloat(String key, float defaultValue)
{
return getFloat(key, new Float(defaultValue)).floatValue();
}
/**
* [EMAIL PROTECTED]
*/
public Float getFloat(String key, Float defaultValue)
{
Object value = resolveContainerStore(key);
if (value == null)
{
return defaultValue;
}
else
{
try
{
return PropertyConverter.toFloat(value);
}
catch (ConversionException e)
{
throw new ConversionException('\'' + key + "' doesn't map to a Float object", e);
}
}
}
/**
* [EMAIL PROTECTED]
*/
public int getInt(String key)
{
Integer i = getInteger(key, null);
if (i != null)
{
return i.intValue();
}
else
{
throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
}
}
/**
* [EMAIL PROTECTED]
*/
public int getInt(String key, int defaultValue)
{
Integer i = getInteger(key, null);
if (i == null)
{
return defaultValue;
}
return i.intValue();
}
/**
* [EMAIL PROTECTED]
*/
public Integer getInteger(String key, Integer defaultValue)
{
Object value = resolveContainerStore(key);
if (value == null)
{
return defaultValue;
}
else
{
try
{
return PropertyConverter.toInteger(value);
}
catch (ConversionException e)
{
throw new ConversionException('\'' + key + "' doesn't map to an Integer object", e);
}
}
}
/**
* [EMAIL PROTECTED]
*/
public long getLong(String key)
{
Long l = getLong(key, null);
if (l != null)
{
return l.longValue();
}
else
{
throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
}
}
/**
* [EMAIL PROTECTED]
*/
public long getLong(String key, long defaultValue)
{
return getLong(key, new Long(defaultValue)).longValue();
}
/**
* [EMAIL PROTECTED]
*/
public Long getLong(String key, Long defaultValue)
{
Object value = resolveContainerStore(key);
if (value == null)
{
return defaultValue;
}
else
{
try
{
return PropertyConverter.toLong(value);
}
catch (ConversionException e)
{
throw new ConversionException('\'' + key + "' doesn't map to a Long object", e);
}
}
}
/**
* [EMAIL PROTECTED]
*/
public short getShort(String key)
{
Short s = getShort(key, null);
if (s != null)
{
return s.shortValue();
}
else
{
throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
}
}
/**
* [EMAIL PROTECTED]
*/
public short getShort(String key, short defaultValue)
{
return getShort(key, new Short(defaultValue)).shortValue();
}
/**
* [EMAIL PROTECTED]
*/
public Short getShort(String key, Short defaultValue)
{
Object value = resolveContainerStore(key);
if (value == null)
{
return defaultValue;
}
else
{
try
{
return PropertyConverter.toShort(value);
}
catch (ConversionException e)
{
throw new ConversionException('\'' + key + "' doesn't map to a Short object", e);
}
}
}
/**
* [EMAIL PROTECTED]
*/
public BigDecimal getBigDecimal(String key)
{
BigDecimal number = getBigDecimal(key, null);
if (number != null)
{
return number;
}
else if (isThrowExceptionOnMissing())
{
throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
}
else
{
return null;
}
}
/**
* [EMAIL PROTECTED]
*/
public BigDecimal getBigDecimal(String key, BigDecimal defaultValue)
{
Object value = resolveContainerStore(key);
if (value == null)
{
return defaultValue;
}
else
{
try
{
return PropertyConverter.toBigDecimal(value);
}
catch (ConversionException e)
{
throw new ConversionException('\'' + key + "' doesn't map to a BigDecimal object", e);
}
}
}
/**
* [EMAIL PROTECTED]
*/
public BigInteger getBigInteger(String key)
{
BigInteger number = getBigInteger(key, null);
if (number != null)
{
return number;
}
else if (isThrowExceptionOnMissing())
{
throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
}
else
{
return null;
}
}
/**
* [EMAIL PROTECTED]
*/
public BigInteger getBigInteger(String key, BigInteger defaultValue)
{
Object value = resolveContainerStore(key);
if (value == null)
{
return defaultValue;
}
else
{
try
{
return PropertyConverter.toBigInteger(value);
}
catch (ConversionException e)
{
throw new ConversionException('\'' + key + "' doesn't map to a BigDecimal object", e);
}
}
}
/**
* [EMAIL PROTECTED]
*/
public String getString(String key)
{
String s = getString(key, null);
if (s != null)
{
return s;
}
else if (isThrowExceptionOnMissing())
{
throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
}
else
{
return null;
}
}
/**
* [EMAIL PROTECTED]
*/
public String getString(String key, String defaultValue)
{
Object value = resolveContainerStore(key);
if (value instanceof String)
{
return interpolate((String) value);
}
else if (value == null)
{
return interpolate(defaultValue);
}
else
{
throw new ConversionException('\'' + key + "' doesn't map to a String object");
}
}
/**
* [EMAIL PROTECTED]
*/
public String[] getStringArray(String key)
{
Object value = getProperty(key);
String[] array;
if (value instanceof String)
{
array = new String[1];
array[0] = interpolate((String) value);
}
else if (value instanceof List)
{
List list = (List) value;
array = new String[list.size()];
for (int i = 0; i < array.length; i++)
{
array[i] = interpolate((String) list.get(i));
}
}
else if (value == null)
{
array = new String[0];
}
else
{
throw new ConversionException('\'' + key + "' doesn't map to a String/List object");
}
return array;
}
/**
* [EMAIL PROTECTED]
*/
public List getList(String key)
{
return getList(key, new ArrayList());
}
/**
* [EMAIL PROTECTED]
*/
public List getList(String key, List defaultValue)
{
Object value = getProperty(key);
List list = null;
if (value instanceof String)
{
list = new ArrayList(1);
list.add(value);
}
else if (value instanceof List)
{
list = (List) value;
}
else if (value == null)
{
list = defaultValue;
}
else
{
throw new ConversionException('\'' + key + "' doesn't map to a List object: " + value + ", a "
+ value.getClass().getName());
}
return list;
}
/**
* Returns an object from the store described by the key. If the value is a
* List object, replace it with the first object in the list.
*
* @param key The property key.
*
* @return value Value, transparently resolving a possible List dependency.
*/
protected Object resolveContainerStore(String key)
{
Object value = getProperty(key);
if (value != null)
{
if (value instanceof List)
{
List list = (List) value;
value = list.isEmpty() ? null : list.get(0);
}
else if (value instanceof Object[])
{
Object[] array = (Object[]) value;
value = array.length == 0 ? null : array[0];
}
else if (value instanceof boolean[])
{
boolean[] array = (boolean[]) value;
value = array.length == 0 ? null : new Boolean(array[0]);
}
else if (value instanceof byte[])
{
byte[] array = (byte[]) value;
value = array.length == 0 ? null : new Byte(array[0]);
}
else if (value instanceof short[])
{
short[] array = (short[]) value;
value = array.length == 0 ? null : new Short(array[0]);
}
else if (value instanceof int[])
{
int[] array = (int[]) value;
value = array.length == 0 ? null : new Integer(array[0]);
}
else if (value instanceof long[])
{
long[] array = (long[]) value;
value = array.length == 0 ? null : new Long(array[0]);
}
else if (value instanceof float[])
{
float[] array = (float[]) value;
value = array.length == 0 ? null : new Float(array[0]);
}
else if (value instanceof double[])
{
double[] array = (double[]) value;
value = array.length == 0 ? null : new Double(array[0]);
}
}
return value;
}
public void setInterpolateAllValues(boolean b)
{
this.interpolateAllValues = b;
}
public boolean isInterpolateAllValues()
{
return interpolateAllValues;
}
}
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.configuration;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.StringTokenizer;
import junit.framework.TestCase;
import junitx.framework.ObjectAssert;
/**
* Tests some basic functions of the BaseConfiguration class. Missing keys will
* throw Exceptions
*
* @version $Id: TestBaseConfiguration.java 158491 2005-03-21 17:58:56Z ebourg $
*/
public class TestBaseConfiguration extends TestCase
{
protected BaseConfiguration config = null;
protected static Class missingElementException = NoSuchElementException.class;
protected static Class incompatibleElementException = ConversionException.class;
protected void setUp() throws Exception
{
config = new BaseConfiguration();
config.setThrowExceptionOnMissing(true);
}
public void testThrowExceptionOnMissing()
{
assertTrue("Throw Exception Property is not set!", config.isThrowExceptionOnMissing());
}
public void testGetProperty()
{
/* should be empty and return null */
assertEquals("This returns null", config.getProperty("foo"), null);
/* add a real value, and get it two different ways */
config.setProperty("number", "1");
assertEquals("This returns '1'", config.getProperty("number"), "1");
assertEquals("This returns '1'", config.getString("number"), "1");
}
public void testGetByte()
{
config.setProperty("number", "1");
byte oneB = 1;
byte twoB = 2;
assertEquals("This returns 1(byte)", oneB, config.getByte("number"));
assertEquals("This returns 1(byte)", oneB, config.getByte("number", twoB));
assertEquals("This returns 2(default byte)", twoB, config.getByte("numberNotInConfig", twoB));
assertEquals("This returns 1(Byte)", new Byte(oneB), config.getByte("number", new Byte("2")));
// missing key without default value
Throwable t = null;
try
{
config.getByte("numberNotInConfig");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for missing keys", t);
ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
// existing key with an incompatible value
config.setProperty("test.empty", "");
t = null;
try
{
config.getByte("test.empty");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for incompatible values", t);
ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
}
public void testGetShort()
{
config.setProperty("numberS", "1");
short oneS = 1;
short twoS = 2;
assertEquals("This returns 1(short)", oneS, config.getShort("numberS"));
assertEquals("This returns 1(short)", oneS, config.getShort("numberS", twoS));
assertEquals("This returns 2(default short)", twoS, config.getShort("numberNotInConfig", twoS));
assertEquals("This returns 1(Short)", new Short(oneS), config.getShort("numberS", new Short("2")));
// missing key without default value
Throwable t = null;
try
{
config.getShort("numberNotInConfig");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for missing keys", t);
ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
// existing key with an incompatible value
config.setProperty("test.empty", "");
t = null;
try
{
config.getShort("test.empty");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for incompatible values", t);
ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
}
public void testGetLong()
{
config.setProperty("numberL", "1");
long oneL = 1;
long twoL = 2;
assertEquals("This returns 1(long)", oneL, config.getLong("numberL"));
assertEquals("This returns 1(long)", oneL, config.getLong("numberL", twoL));
assertEquals("This returns 2(default long)", twoL, config.getLong("numberNotInConfig", twoL));
assertEquals("This returns 1(Long)", new Long(oneL), config.getLong("numberL", new Long("2")));
// missing key without default value
Throwable t = null;
try
{
config.getLong("numberNotInConfig");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for missing keys", t);
ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
// existing key with an incompatible value
config.setProperty("test.empty", "");
t = null;
try
{
config.getLong("test.empty");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for incompatible values", t);
ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
}
public void testGetFloat()
{
config.setProperty("numberF", "1.0");
float oneF = 1;
float twoF = 2;
assertEquals("This returns 1(float)", oneF, config.getFloat("numberF"), 0);
assertEquals("This returns 1(float)", oneF, config.getFloat("numberF", twoF), 0);
assertEquals("This returns 2(default float)", twoF, config.getFloat("numberNotInConfig", twoF), 0);
assertEquals("This returns 1(Float)", new Float(oneF), config.getFloat("numberF", new Float("2")));
// missing key without default value
Throwable t = null;
try
{
config.getFloat("numberNotInConfig");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for missing keys", t);
ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
// existing key with an incompatible value
config.setProperty("test.empty", "");
t = null;
try
{
config.getFloat("test.empty");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for incompatible values", t);
ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
}
public void testGetDouble()
{
config.setProperty("numberD", "1.0");
double oneD = 1;
double twoD = 2;
assertEquals("This returns 1(double)", oneD, config.getDouble("numberD"), 0);
assertEquals("This returns 1(double)", oneD, config.getDouble("numberD", twoD), 0);
assertEquals("This returns 2(default double)", twoD, config.getDouble("numberNotInConfig", twoD), 0);
assertEquals("This returns 1(Double)", new Double(oneD), config.getDouble("numberD", new Double("2")));
// missing key without default value
Throwable t = null;
try
{
config.getDouble("numberNotInConfig");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for missing keys", t);
ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
// existing key with an incompatible value
config.setProperty("test.empty", "");
t = null;
try
{
config.getDouble("test.empty");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for incompatible values", t);
ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
}
public void testGetBigDecimal()
{
config.setProperty("numberBigD", "123.456");
BigDecimal number = new BigDecimal("123.456");
BigDecimal defaultValue = new BigDecimal("654.321");
assertEquals("Existing key", number, config.getBigDecimal("numberBigD"));
assertEquals("Existing key with default value", number, config.getBigDecimal("numberBigD", defaultValue));
assertEquals("Missing key with default value", defaultValue, config.getBigDecimal("numberNotInConfig", defaultValue));
// missing key without default value
Throwable t = null;
try
{
config.getBigDecimal("numberNotInConfig");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for missing keys", t);
ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
// existing key with an incompatible value
config.setProperty("test.empty", "");
t = null;
try
{
config.getBigDecimal("test.empty");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for incompatible values", t);
ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
}
public void testGetBigInteger()
{
config.setProperty("numberBigI", "1234567890");
BigInteger number = new BigInteger("1234567890");
BigInteger defaultValue = new BigInteger("654321");
assertEquals("Existing key", number, config.getBigInteger("numberBigI"));
assertEquals("Existing key with default value", number, config.getBigInteger("numberBigI", defaultValue));
assertEquals("Missing key with default value", defaultValue, config.getBigInteger("numberNotInConfig", defaultValue));
// missing key without default value
Throwable t = null;
try
{
config.getBigInteger("numberNotInConfig");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for missing keys", t);
ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
// existing key with an incompatible value
config.setProperty("test.empty", "");
t = null;
try
{
config.getBigInteger("test.empty");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for incompatible values", t);
ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
}
public void testGetString()
{
config.setProperty("testString", "The quick brown fox");
String string = new String("The quick brown fox");
String defaultValue = new String("jumps over the lazy dog");
assertEquals("Existing key", string, config.getString("testString"));
assertEquals("Existing key with default value", string, config.getString("testString", defaultValue));
assertEquals("Missing key with default value", defaultValue, config.getString("stringNotInConfig", defaultValue));
// missing key without default value
Throwable t = null;
try
{
config.getString("stringNotInConfig");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for missing keys", t);
ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
}
public void testGetBoolean()
{
config.setProperty("boolA", Boolean.TRUE);
boolean boolT = true, boolF = false;
assertEquals("This returns true", boolT, config.getBoolean("boolA"));
assertEquals("This returns true, not the default", boolT, config.getBoolean("boolA", boolF));
assertEquals("This returns false(default)", boolF, config.getBoolean("boolNotInConfig", boolF));
assertEquals("This returns true(Boolean)", new Boolean(boolT), config.getBoolean("boolA", new Boolean(boolF)));
// missing key without default value
Throwable t = null;
try
{
config.getBoolean("numberNotInConfig");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for missing keys", t);
ObjectAssert.assertInstanceOf("Exception thrown for missing keys", missingElementException, t);
// existing key with an incompatible value
config.setProperty("test.empty", "");
t = null;
try
{
config.getBoolean("test.empty");
}
catch (Throwable T)
{
t = T;
}
assertNotNull("No exception thrown for incompatible values", t);
ObjectAssert.assertInstanceOf("Exception thrown for incompatible values", incompatibleElementException, t);
}
public void testGetList()
{
config.addProperty("number", "1");
config.addProperty("number", "2");
List list = config.getList("number");
assertNotNull("The list is null", list);
assertEquals("List size", 2, list.size());
assertTrue("The number 1 is missing from the list", list.contains("1"));
assertTrue("The number 2 is missing from the list", list.contains("2"));
/*
* now test dan's new fix where we get the first scalar
* when we access a list valued property
*/
try
{
config.getString("number");
}
catch (NoSuchElementException nsse)
{
fail("Should return a string");
}
}
public void testCommaSeparatedString()
{
String prop = "hey, that's a test";
config.setProperty("prop.string", prop);
try
{
config.getList("prop.string");
}
catch (NoSuchElementException nsse)
{
fail("Should return a list");
}
String prop2 = "hey\\, that's a test";
config.clearProperty("prop.string");
config.setProperty("prop.string", prop2);
try
{
config.getString("prop.string");
}
catch (NoSuchElementException nsse)
{
fail("Should return a list");
}
}
public void testAddProperty() throws Exception
{
Collection props = new ArrayList();
props.add("one");
props.add("two,three,four");
props.add(new String[] { "5.1", "5.2", "5.3,5.4", "5.5" });
props.add("six");
config.addProperty("complex.property", props);
Object val = config.getProperty("complex.property");
assertTrue(val instanceof Collection);
Collection col = (Collection) val;
assertEquals(10, col.size());
props = new ArrayList();
props.add("quick");
props.add("brown");
props.add("fox,jumps");
Object[] data = new Object[] {
"The", props, "over,the", "lazy", "dog."
};
config.setProperty("complex.property", data);
val = config.getProperty("complex.property");
assertTrue(val instanceof Collection);
col = (Collection) val;
Iterator it = col.iterator();
StringTokenizer tok = new StringTokenizer("The quick brown fox jumps over the lazy dog.", " ");
while(tok.hasMoreTokens())
{
assertTrue(it.hasNext());
assertEquals(tok.nextToken(), it.next());
}
assertFalse(it.hasNext());
config.setProperty("complex.property", null);
assertFalse(config.containsKey("complex.property"));
}
public void testPropertyAccess()
{
config.clearProperty("prop.properties");
config.setProperty("prop.properties", "");
assertEquals(
"This returns an empty Properties object",
config.getProperties("prop.properties"),
new Properties());
config.clearProperty("prop.properties");
config.setProperty("prop.properties", "foo=bar, baz=moo, seal=clubber");
Properties p = new Properties();
p.setProperty("foo", "bar");
p.setProperty("baz", "moo");
p.setProperty("seal", "clubber");
assertEquals(
"This returns a filled in Properties object",
config.getProperties("prop.properties"),
p);
}
public void testSubset()
{
/*
* test subset : assure we don't reprocess the data elements
* when generating the subset
*/
String prop = "hey, that's a test";
String prop2 = "hey\\, that's a test";
config.setProperty("prop.string", prop2);
config.setProperty("property.string", "hello");
Configuration subEprop = config.subset("prop");
assertEquals(
"Returns the full string",
prop,
subEprop.getString("string"));
try
{
subEprop.getString("string");
}
catch (NoSuchElementException nsse)
{
fail("Should return a string");
}
try
{
subEprop.getList("string");
}
catch (NoSuchElementException nsse)
{
fail("Should return a list");
}
Iterator it = subEprop.getKeys();
it.next();
assertFalse(it.hasNext());
subEprop = config.subset("prop.");
it = subEprop.getKeys();
assertFalse(it.hasNext());
}
public void testInterpolation() throws Exception
{
config.setProperty("applicationRoot", "/home/applicationRoot");
config.setProperty("db", "${applicationRoot}/db/hypersonic");
String unInterpolatedValue = "${applicationRoot2}/db/hypersonic";
config.setProperty("dbFailedInterpolate", unInterpolatedValue);
String dbProp = "/home/applicationRoot/db/hypersonic";
//construct a new config, using config as the defaults config for it.
BaseConfiguration superProp = config;
assertEquals(
"Checking interpolated variable", dbProp,
superProp.getString("db"));
assertEquals(
"lookup fails, leave variable as is",
superProp.getString("dbFailedInterpolate"),
unInterpolatedValue);
superProp.setProperty("arrayInt", "${applicationRoot}/1");
String[] arrayInt = superProp.getStringArray("arrayInt");
assertEquals(
"check first entry was interpolated",
"/home/applicationRoot/1",
arrayInt[0]);
}
public void testMultipleInterpolation() throws Exception
{
config.setProperty("test.base-level", "/base-level");
config.setProperty("test.first-level", "${test.base-level}/first-level");
config.setProperty(
"test.second-level",
"${test.first-level}/second-level");
config.setProperty(
"test.third-level",
"${test.second-level}/third-level");
String expectedValue =
"/base-level/first-level/second-level/third-level";
assertEquals(config.getString("test.third-level"), expectedValue);
}
public void testMultiValuedPropertyInterpolation() throws Exception
{
config.setProperty("multi", "value1");
config.addProperty("multi", "value2");
config.setProperty("interpolated", "${multi}");
config.setInterpolateAllValues(false);
String expectedValue = "value1";
assertEquals(config.getString("interpolated"), expectedValue);
config.setInterpolateAllValues(true);
expectedValue = "" + config.getProperty("multi");
assertEquals(config.getString("interpolated"), expectedValue);
}
public void testInterpolationLoop() throws Exception
{
config.setProperty("test.a", "${test.b}");
config.setProperty("test.b", "${test.a}");
try
{
config.getString("test.a");
}
catch (IllegalStateException e)
{
return;
}
fail("IllegalStateException should have been thrown for looped property references");
}
public void testGetHexadecimalValue()
{
config.setProperty("number", "0xFF");
assertEquals("byte value", (byte) 0xFF, config.getByte("number"));
config.setProperty("number", "0xFFFF");
assertEquals("short value", (short) 0xFFFF, config.getShort("number"));
config.setProperty("number", "0xFFFFFFFF");
assertEquals("int value", 0xFFFFFFFF, config.getInt("number"));
config.setProperty("number", "0xFFFFFFFFFFFFFFFF");
assertEquals("long value", 0xFFFFFFFFFFFFFFFFL, config.getLong("number"));
assertEquals("long value", 0xFFFFFFFFFFFFFFFFL, config.getBigInteger("number").longValue());
}
public void testResolveContainerStore()
{
AbstractConfiguration config = new BaseConfiguration();
// array of objects
config.addPropertyDirect("array", new String[] { "foo", "bar" });
assertEquals("first element of the 'array' property", "foo", config.resolveContainerStore("array"));
// list of objects
List list = new ArrayList();
list.add("foo");
list.add("bar");
config.addPropertyDirect("list", list);
assertEquals("first element of the 'list' property", "foo", config.resolveContainerStore("list"));
// arrays of primitives
config.addPropertyDirect("array.boolean", new boolean[] { true, false });
assertEquals("first element of the 'array.boolean' property", true, config.getBoolean("array.boolean"));
config.addPropertyDirect("array.byte", new byte[] { 1, 2 });
assertEquals("first element of the 'array.byte' property", 1, config.getByte("array.byte"));
config.addPropertyDirect("array.short", new short[] { 1, 2 });
assertEquals("first element of the 'array.short' property", 1, config.getShort("array.short"));
config.addPropertyDirect("array.int", new int[] { 1, 2 });
assertEquals("first element of the 'array.int' property", 1, config.getInt("array.int"));
config.addPropertyDirect("array.long", new long[] { 1, 2 });
assertEquals("first element of the 'array.long' property", 1, config.getLong("array.long"));
config.addPropertyDirect("array.float", new float[] { 1, 2 });
assertEquals("first element of the 'array.float' property", 1, config.getFloat("array.float"), 0);
config.addPropertyDirect("array.double", new double[] { 1, 2 });
assertEquals("first element of the 'array.double' property", 1, config.getDouble("array.double"), 0);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]