I have reimplemented the subset code with a decorator, the pros : - the resulting code is much cleaner - it fixes some old quicks - it fixes Bug 27427 - no property is copied => more memory efficient - the subset is fully synchronized with its parent configuration
the cons: I should be at home at this hour ;)
I had to change a test for HierarchicalConfiguration, I hope it doesn't break the initial intent.
Emmanuel Bourg
/* * Copyright 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.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
/**
* A subset of another configuration. The new Configuration object contains
* every key from the parent Configuration that starts with prefix. The prefix
* is removed from the keys in the subset.
*
* @author Emmanuel Bourg
* @version $Revision$, $Date$
*/
public class SubsetConfiguration implements Configuration {
protected Configuration parent;
protected String prefix;
protected String delimiter;
/**
* Create a subset of the specified configuration
*
* @param parent The parent configuration
* @param prefix The prefix used to select the properties.
*/
public SubsetConfiguration(Configuration parent, String prefix) {
this.parent = parent;
this.prefix = prefix;
}
/**
* Create a subset of the specified configuration
*
* @param parent The parent configuration
* @param prefix The prefix used to select the properties.
* @param delimiter The prefix delimiter
*/
public SubsetConfiguration(Configuration parent, String prefix, String delimiter) {
this.parent = parent;
this.prefix = prefix;
this.delimiter = delimiter;
}
/**
* Return the key in the parent configuration associated to the specified
* key in this subset.
*
* @param key The key in the subset.
*/
protected String getParentKey(String key) {
return delimiter == null ? prefix + key : prefix + delimiter + key;
}
/**
* Return the parent configuation for this subset.
*/
public Configuration getParent() {
return parent;
}
/**
* Return the prefix used to select the properties in the parent configuration.
*/
public String getPrefix() {
return prefix;
}
/**
* Set the prefix used to select the properties in the parent configuration.
*/
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public Configuration subset(String prefix) {
return parent.subset(getParentKey(prefix));
}
public boolean isEmpty() {
return !getKeys().hasNext();
}
public boolean containsKey(String key) {
return parent.containsKey(getParentKey(key));
}
public void addProperty(String key, Object value) {
parent.addProperty(getParentKey(key), value);
}
public void setProperty(String key, Object value) {
parent.setProperty(getParentKey(key), value);
}
public void clearProperty(String key) {
parent.clearProperty(getParentKey(key));
}
public Object getProperty(String key) {
return parent.getProperty(getParentKey(key));
}
public Iterator getKeys(String prefix) {
return parent.getKeys(getParentKey(prefix));
}
public Iterator getKeys() {
return parent.getKeys(prefix);
}
public Properties getProperties(String key) {
return parent.getProperties(getParentKey(key));
}
public boolean getBoolean(String key) {
return parent.getBoolean(getParentKey(key));
}
public boolean getBoolean(String key, boolean defaultValue) {
return parent.getBoolean(getParentKey(key), defaultValue);
}
public Boolean getBoolean(String key, Boolean defaultValue) {
return parent.getBoolean(getParentKey(key), defaultValue);
}
public byte getByte(String key) {
return parent.getByte(getParentKey(key));
}
public byte getByte(String key, byte defaultValue) {
return parent.getByte(getParentKey(key), defaultValue);
}
public Byte getByte(String key, Byte defaultValue) {
return parent.getByte(getParentKey(key), defaultValue);
}
public double getDouble(String key) {
return parent.getDouble(getParentKey(key));
}
public double getDouble(String key, double defaultValue) {
return parent.getDouble(getParentKey(key), defaultValue);
}
public Double getDouble(String key, Double defaultValue) {
return parent.getDouble(getParentKey(key), defaultValue);
}
public float getFloat(String key) {
return parent.getFloat(getParentKey(key));
}
public float getFloat(String key, float defaultValue) {
return parent.getFloat(getParentKey(key), defaultValue);
}
public Float getFloat(String key, Float defaultValue) {
return parent.getFloat(getParentKey(key), defaultValue);
}
public int getInt(String key) {
return parent.getInt(getParentKey(key));
}
public int getInt(String key, int defaultValue) {
return parent.getInt(getParentKey(key), defaultValue);
}
public Integer getInteger(String key, Integer defaultValue) {
return parent.getInteger(getParentKey(key), defaultValue);
}
public long getLong(String key) {
return parent.getLong(getParentKey(key));
}
public long getLong(String key, long defaultValue) {
return parent.getLong(getParentKey(key), defaultValue);
}
public Long getLong(String key, Long defaultValue) {
return parent.getLong(getParentKey(key), defaultValue);
}
public short getShort(String key) {
return parent.getShort(getParentKey(key));
}
public short getShort(String key, short defaultValue) {
return parent.getShort(getParentKey(key), defaultValue);
}
public Short getShort(String key, Short defaultValue) {
return parent.getShort(getParentKey(key), defaultValue);
}
public BigDecimal getBigDecimal(String key) {
return parent.getBigDecimal(getParentKey(key));
}
public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) {
return parent.getBigDecimal(getParentKey(key), defaultValue);
}
public BigInteger getBigInteger(String key) {
return parent.getBigInteger(getParentKey(key));
}
public BigInteger getBigInteger(String key, BigInteger defaultValue) {
return parent.getBigInteger(getParentKey(key), defaultValue);
}
public String getString(String key) {
return parent.getString(getParentKey(key));
}
public String getString(String key, String defaultValue) {
return parent.getString(getParentKey(key), defaultValue);
}
public String[] getStringArray(String key) {
return parent.getStringArray(getParentKey(key));
}
public List getList(String key) {
return parent.getList(getParentKey(key));
}
public List getList(String key, List defaultValue) {
return parent.getList(getParentKey(key), defaultValue);
}
public Locale getLocale(String key) {
return parent.getLocale(getParentKey(key));
}
public Locale getLocale(String key, Locale defaultValue) {
return parent.getLocale(getParentKey(key), defaultValue);
}
}
/* * 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 junit.framework.TestCase; /** * Test case for the [EMAIL PROTECTED] SubsetConfiguration} class. * * @author Emmanuel Bourg * @version $Revision$, $Date$ */ public class TestSubsetConfiguration extends TestCase { public void testGetProperty() { BaseConfiguration conf = new BaseConfiguration(); conf.setProperty("test.key1", "value1"); conf.setProperty("testing.key2", "value1"); Configuration subset = new SubsetConfiguration(conf, "test", "."); assertFalse("the subset is empty", subset.isEmpty()); assertTrue("'key1' not found in the subset", subset.containsKey("key1")); assertFalse("'ng.key2' found in the subset", subset.containsKey("ng.key2")); } public void testSetProperty() { BaseConfiguration conf = new BaseConfiguration(); Configuration subset = new SubsetConfiguration(conf, "test", "."); // set a property in the subset and check the parent subset.setProperty("key1", "value1"); assertEquals("key1 in the subset configuration", "value1", subset.getProperty("key1")); assertEquals("test.key1 in the parent configuration", "value1", conf.getProperty("test.key1")); // set a property in the parent and check in the subset conf.setProperty("test.key2", "value2"); assertEquals("test.key2 in the parent configuration", "value2", conf.getProperty("test.key2")); assertEquals("key2 in the subset configuration", "value2", subset.getProperty("key2")); } }
Index: src/java/org/apache/commons/configuration/AbstractConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/configuration/src/java/org/apache/commons/configuration/AbstractConfiguration.java,v
retrieving revision 1.6
diff -u -r1.6 AbstractConfiguration.java
--- src/java/org/apache/commons/configuration/AbstractConfiguration.java 27 Feb
2004 17:41:35 -0000 1.6
+++ src/java/org/apache/commons/configuration/AbstractConfiguration.java 4 Mar
2004 20:01:57 -0000
@@ -16,15 +16,16 @@
* limitations under the License.
*/
+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.Locale;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.StringTokenizer;
-import java.math.BigDecimal;
-import java.math.BigInteger;
import org.apache.commons.lang.BooleanUtils;
@@ -270,63 +271,7 @@
*/
public Configuration subset(String prefix)
{
- BaseConfiguration c = new BaseConfiguration();
- Iterator keys = this.getKeys();
- boolean validSubset = false;
-
- while (keys.hasNext())
- {
- Object key = keys.next();
-
- if (key instanceof String && ((String) key).startsWith(prefix))
- {
- if (!validSubset)
- {
- validSubset = true;
- }
-
- String newKey = null;
-
- /*
- * Check to make sure that c.subset(prefix) doesn't blow up when
- * there is only a single property with the key prefix. This is
- * not a useful subset but it is a valid subset.
- */
- if (((String) key).length() == prefix.length())
- {
- newKey = prefix;
- }
- else
- {
- newKey = ((String) key).substring(prefix.length() + 1);
- }
-
- /*
- * use addPropertyDirect() - this will plug the data as is into
- * the Map, but will also do the right thing re key accounting
- *
- * QUESTION: getProperty or getPropertyDirect
- */
- Object value = getProperty((String) key);
- if (value instanceof String)
- {
- c.addPropertyDirect(newKey, interpolate((String) value));
- }
- else
- {
- c.addProperty(newKey, value);
- }
- }
- }
-
- if (validSubset)
- {
- return c;
- }
- else
- {
- return null;
- }
+ return new SubsetConfiguration(this, prefix, ".");
}
/**
Index: src/java/org/apache/commons/configuration/CompositeConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/configuration/src/java/org/apache/commons/configuration/CompositeConfiguration.java,v
retrieving revision 1.7
diff -u -r1.7 CompositeConfiguration.java
--- src/java/org/apache/commons/configuration/CompositeConfiguration.java 27 Feb
2004 17:41:35 -0000 1.7
+++ src/java/org/apache/commons/configuration/CompositeConfiguration.java 4 Mar
2004 20:01:57 -0000
@@ -247,28 +247,7 @@
}
return false;
}
- /**
- * Create a CompositeConfiguration object that is a subset
- * of this one. Cycles over all the config objects, and calls
- * their subset method and then just adds that.
- *
- * @param prefix
- */
- public Configuration subset(String prefix)
- {
- CompositeConfiguration subsetCompositeConfiguration =
- new CompositeConfiguration();
- for (ListIterator i = configList.listIterator(); i.hasNext();)
- {
- Configuration config = (Configuration) i.next();
- Configuration subset = config.subset(prefix);
- if (subset != null)
- {
- subsetCompositeConfiguration.addConfiguration(subset);
- }
- }
- return subsetCompositeConfiguration;
- }
+
/**
* Get a List of strings associated with the given configuration key.
*
Index: src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/configuration/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java,v
retrieving revision 1.3
diff -u -r1.3 HierarchicalConfiguration.java
--- src/java/org/apache/commons/configuration/HierarchicalConfiguration.java 27 Feb
2004 17:41:35 -0000 1.3
+++ src/java/org/apache/commons/configuration/HierarchicalConfiguration.java 4 Mar
2004 20:01:58 -0000
@@ -333,49 +333,6 @@
}
/**
- * Creates a new <code>Configuration</code> object containing all keys
- * that start with the specified prefix. This implementation will return
- * a <code>HierarchicalConfiguration</code> object so that the structure
- * of the keys will be saved.
- * @param prefix the prefix of the keys for the subset
- * @return a new configuration object representing the selected subset
- */
- public Configuration subset(String prefix)
- {
- Collection nodes = fetchNodeList(prefix);
- if (nodes.isEmpty())
- {
- return null;
- } /* if */
-
- HierarchicalConfiguration result = new HierarchicalConfiguration();
- CloneVisitor visitor = new CloneVisitor();
-
- for (Iterator it = nodes.iterator(); it.hasNext();)
- {
- Node nd = (Node) it.next();
- nd.visit(visitor, null);
-
- Container children = visitor.getClone().getChildren();
- if (children.size() > 0)
- {
- for (int i = 0; i < children.size(); i++)
- {
- result.getRoot().addChild((Node) children.get(i));
- } /* for */
- } /* if */
- else
- {
- // In this case we cannot shorten the key because only
- // values are found without further child nodes.
- result.getRoot().addChild(visitor.getClone());
- } /* else */
- } /* for */
-
- return (result.isEmpty()) ? null : result;
- }
-
- /**
* Returns the maximum defined index for the given key. This is
* useful if there are multiple values for this key. They can then be
* addressed separately by specifying indices from 0 to the return value
Index: src/java/org/apache/commons/configuration/JNDIConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/configuration/src/java/org/apache/commons/configuration/JNDIConfiguration.java,v
retrieving revision 1.7
diff -u -r1.7 JNDIConfiguration.java
--- src/java/org/apache/commons/configuration/JNDIConfiguration.java 27 Feb 2004
17:41:35 -0000 1.7
+++ src/java/org/apache/commons/configuration/JNDIConfiguration.java 4 Mar 2004
20:01:58 -0000
@@ -285,65 +285,6 @@
return false;
}
}
- /**
- * Create an ExtendedProperties object that is a subset
- * of this one. Take into account duplicate keys
- * by using the setProperty() in ExtendedProperties.
- *
- * @param prefix
- */
- public Configuration subset(String prefix)
- {
- BaseConfiguration c = new BaseConfiguration();
- Iterator keys = this.getKeys();
- boolean validSubset = false;
- while (keys.hasNext())
- {
- Object key = keys.next();
- if (key instanceof String && ((String) key).startsWith(prefix))
- {
- if (!validSubset)
- {
- validSubset = true;
- }
- String newKey = null;
- /*
- * Check to make sure that c.subset(prefix) doesn't blow up when
- * there is only a single property with the key prefix. This is
- * not a useful subset but it is a valid subset.
- */
- if (((String) key).length() == prefix.length())
- {
- newKey = prefix;
- }
- else
- {
- newKey = ((String) key).substring(prefix.length() + 1);
- }
- /*
- * use addPropertyDirect() - this will plug the data as is into
- * the Map, but will also do the right thing re key accounting
- */
- Object value = getValueFromJNDI(key.toString());
- if (value instanceof String)
- {
- c.addPropertyDirect(newKey, interpolate((String) value));
- }
- else
- {
- c.addPropertyDirect(newKey, value);
- }
- }
- }
- if (validSubset)
- {
- return (Configuration) c;
- }
- else
- {
- return null;
- }
- }
/**
* Get a boolean associated with the given configuration key.
Index: src/test/org/apache/commons/configuration/NonStringTestHolder.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/configuration/src/test/org/apache/commons/configuration/NonStringTestHolder.java,v
retrieving revision 1.4
diff -u -r1.4 NonStringTestHolder.java
--- src/test/org/apache/commons/configuration/NonStringTestHolder.java 27 Feb 2004
17:41:34 -0000 1.4
+++ src/test/org/apache/commons/configuration/NonStringTestHolder.java 4 Mar 2004
20:01:58 -0000
@@ -130,39 +130,29 @@
public void testListMissing() throws Exception
{
-
- Assert.assertEquals(
- 0,
- configuration.getList("missing.list").size());
+ Assert.assertEquals(0, configuration.getList("missing.list").size());
}
public void testSubset() throws Exception
{
- String KEY_VALUE = "test.short";
- Configuration subset = configuration.subset(KEY_VALUE);
- boolean foundKeyValue = false;
- for (Iterator i = subset.getKeys(); i.hasNext();)
- {
- String key = (String) i.next();
- if (!key.equals(KEY_VALUE))
- {
+ Configuration subset = configuration.subset("test");
- Assert.assertTrue(
- "Key is:" + key,
- !key.startsWith("test.short"));
- }
- else {
- foundKeyValue=true;
- }
+ // search the "short" key in the subset using the key iterator
+ boolean foundKeyValue = false;
+ Iterator it = subset.getKeys();
+ while (it.hasNext() && !foundKeyValue)
+ {
+ String key = (String) it.next();
+ foundKeyValue = "short".equals(key);
}
- Assert.assertTrue("Make sure test.short did show up. It is
valid.",foundKeyValue);
+ Assert.assertTrue("Make sure test.short did show up. It is valid.",
!foundKeyValue && configuration.containsKey("test.short"));
}
public void testIsEmpty() throws Exception
{
Assert.assertTrue("Configuration should not be
empty",!configuration.isEmpty());
-
}
+
/**
* @return
*/
Index: src/test/org/apache/commons/configuration/TestCompositeConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/configuration/src/test/org/apache/commons/configuration/TestCompositeConfiguration.java,v
retrieving revision 1.5
diff -u -r1.5 TestCompositeConfiguration.java
--- src/test/org/apache/commons/configuration/TestCompositeConfiguration.java 27 Feb
2004 17:41:34 -0000 1.5
+++ src/test/org/apache/commons/configuration/TestCompositeConfiguration.java 4 Mar
2004 20:01:58 -0000
@@ -210,7 +210,7 @@
}
/**
- * Tests retrieving subsets of configuraitions
+ * Tests retrieving subsets of configurations
*/
public void testGettingSubset() throws Exception
{
@@ -218,14 +218,14 @@
cc.addConfiguration(dom4jConf);
Configuration subset = null;
- subset = cc.subset("test.short");
+ subset = cc.subset("test");
assertNotNull(subset);
- assertTrue("Shouldn't be empty", !subset.isEmpty());
- assertEquals("Make sure the initial loaded configs subset overrides" + "any
later add configs subset", "1", subset.getString("test.short"));
+ assertFalse("Shouldn't be empty", subset.isEmpty());
+ assertEquals("Make sure the initial loaded configs subset overrides any later
add configs subset", "1", subset.getString("short"));
cc.setProperty("test.short", "43");
- subset = cc.subset("test.short");
- assertEquals("Make sure the initial loaded configs subset overrides" + "any
later add configs subset", "43", subset.getString("test.short"));
+ subset = cc.subset("test");
+ assertEquals("Make sure the initial loaded configs subset overrides any later
add configs subset", "43", subset.getString("short"));
}
/**
Index: src/test/org/apache/commons/configuration/TestHierarchicalConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/configuration/src/test/org/apache/commons/configuration/TestHierarchicalConfiguration.java,v
retrieving revision 1.3
diff -u -r1.3 TestHierarchicalConfiguration.java
--- src/test/org/apache/commons/configuration/TestHierarchicalConfiguration.java
27 Feb 2004 17:41:34 -0000 1.3
+++ src/test/org/apache/commons/configuration/TestHierarchicalConfiguration.java
4 Mar 2004 20:01:59 -0000
@@ -235,12 +235,12 @@
key.append("name");
assertEquals(fields[0][i], conf.getProperty(key.toString()));
} /* for */
-
- assertNull(config.subset("tables.table(2)"));
-
- conf = config.subset("tables.table.fields.field.name");
+
+ assertTrue("subset is not empty", config.subset("tables.table(2)").isEmpty());
+
+ conf = config.subset("tables.table.fields.field");
prop = conf.getProperty("name");
- assertTrue(prop instanceof Collection);
+ assertTrue("prop is not a collection", prop instanceof Collection);
assertEquals(10, ((Collection) prop).size());
}
}
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
