You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2014/03/17 22:12:13 UTC
svn commit: r1578582 - in
/commons/proper/configuration/branches/immutableNodes/src:
main/java/org/apache/commons/configuration/
test/java/org/apache/commons/configuration/
Author: oheger
Date: Mon Mar 17 21:12:13 2014
New Revision: 1578582
URL: http://svn.apache.org/r1578582
Log:
Implemented configurationAt() in BaseHierarchicalConfiguration.
The method now either creates a BaseHierarchicalConfiguration initialized with
the selected root node or a SubnodeConfiguration with a corresponding
NodeSelector. Adapted test classes.
Modified:
commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java
commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/SubnodeConfiguration.java
commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java
commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestSubnodeConfiguration.java
Modified: commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java?rev=1578582&r1=1578581&r2=1578582&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java Mon Mar 17 21:12:13 2014
@@ -28,13 +28,16 @@ import java.util.WeakHashMap;
import org.apache.commons.configuration.event.ConfigurationEvent;
import org.apache.commons.configuration.event.ConfigurationListener;
+import org.apache.commons.configuration.ex.ConfigurationRuntimeException;
import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
import org.apache.commons.configuration.tree.ConfigurationNode;
import org.apache.commons.configuration.tree.ConfigurationNodeVisitorAdapter;
import org.apache.commons.configuration.tree.ImmutableNode;
import org.apache.commons.configuration.tree.InMemoryNodeModel;
import org.apache.commons.configuration.tree.NodeModel;
+import org.apache.commons.configuration.tree.NodeSelector;
import org.apache.commons.configuration.tree.QueryResult;
+import org.apache.commons.configuration.tree.TrackedNodeModel;
/**
* <p>
@@ -221,73 +224,90 @@ public class BaseHierarchicalConfigurati
}
/**
- * <p>
- * Returns a hierarchical subnode configuration object that wraps the
- * configuration node specified by the given key. This method provides an
- * easy means of accessing sub trees of a hierarchical configuration. In the
- * returned configuration the sub tree can directly be accessed, it becomes
- * the root node of this configuration. Because of this the passed in key
- * must select exactly one configuration node; otherwise an
- * {@code IllegalArgumentException} will be thrown.
- * </p>
- * <p>
- * The difference between this method and the
- * {@link #subset(String)} method is that
- * {@code subset()} supports arbitrary subsets of configuration nodes
- * while {@code configurationAt()} only returns a single sub tree.
- * Please refer to the documentation of the
- * {@code SubnodeConfiguration} class to obtain further information
- * about subnode configurations and when they should be used.
- * </p>
- * <p>
- * With the {@code supportUpdate} flag the behavior of the returned
- * {@code SubnodeConfiguration} regarding updates of its parent
- * configuration can be determined. A subnode configuration operates on the
- * same nodes as its parent, so changes at one configuration are normally
- * directly visible for the other configuration. There are however changes
- * of the parent configuration, which are not recognized by the subnode
- * configuration per default. An example for this is a reload operation (for
- * file-based configurations): Here the complete node set of the parent
- * configuration is replaced, but the subnode configuration still references
- * the old nodes. If such changes should be detected by the subnode
- * configuration, the {@code supportUpdates} flag must be set to
- * <b>true</b>. This causes the subnode configuration to reevaluate the key
- * used for its creation each time it is accessed. This guarantees that the
- * subnode configuration always stays in sync with its key, even if the
- * parent configuration's data significantly changes. If such a change
- * makes the key invalid - because it now no longer points to exactly one
- * node -, the subnode configuration is not reconstructed, but keeps its
- * old data. It is then quasi detached from its parent.
- * </p>
- *
- * @param key the key that selects the sub tree
- * @param supportUpdates a flag whether the returned subnode configuration
- * should be able to handle updates of its parent
- * @return a hierarchical configuration that contains this sub tree
+ * {@inheritDoc} The result of this implementation depends on the
+ * {@code supportUpdates} flag: If it is <b>false</b>, a plain
+ * {@code BaseHierarchicalConfiguration} is returned using the selected node
+ * as root node. This is suitable for read-only access to properties.
+ * Because the configuration returned in this case is not connected to the
+ * parent configuration, updates on properties made by one configuration are
+ * not reflected by the other one. A value of <b>true</b> for this parameter
+ * causes a tracked node to be created, and result is a
+ * {@link SubnodeConfiguration} based on this tracked node. This
+ * configuration is really connected to its parent, so that updated
+ * properties are visible on both.
+ *
* @see SubnodeConfiguration
- * @since 1.5
+ * @throws ConfigurationRuntimeException if the key does not select a single
+ * node
*/
- public SubnodeConfiguration configurationAt(String key,
+ public HierarchicalConfiguration<ImmutableNode> configurationAt(String key,
boolean supportUpdates)
{
- beginWrite(false);
- try
+ BaseHierarchicalConfiguration sub =
+ supportUpdates ? createConnectedSubConfiguration(key)
+ : createIndependentSubConfiguration(key);
+ initSubConfiguration(sub);
+ return sub;
+ }
+
+ /**
+ * Creates a sub configuration from the specified key which is connected to
+ * this configuration. This implementation creates a
+ * {@link SubnodeConfiguration} with a tracked node identified by the passed
+ * in key.
+ *
+ * @param key the key of the sub configuration
+ * @return the new sub configuration
+ */
+ private BaseHierarchicalConfiguration createConnectedSubConfiguration(
+ String key)
+ {
+ InMemoryNodeModel myModel = (InMemoryNodeModel) getModel();
+ NodeSelector selector = new NodeSelector(key);
+ myModel.trackNode(selector, this);
+ return new SubnodeConfiguration(this, new TrackedNodeModel(myModel,
+ selector, true), selector);
+ }
+
+ /**
+ * Creates a sub configuration from the specified key which is independent
+ * on this configuration. This means that the sub configuration operates on
+ * a separate node model (although the nodes are initially shared).
+ *
+ * @param key the key of the sub configuration
+ * @return the new sub configuration
+ */
+ private BaseHierarchicalConfiguration createIndependentSubConfiguration(
+ String key)
+ {
+ List<ImmutableNode> targetNodes = fetchFilteredNodeResults(key);
+ if (targetNodes.size() != 1)
{
-// List<ConfigurationNode> nodes = fetchNodeList(key);
-// if (nodes.size() != 1)
-// {
-// throw new IllegalArgumentException(
-// "Passed in key must select exactly one node: " + key);
-// }
-// return createAndInitializeSubnodeConfiguration(nodes.get(0), key,
-// supportUpdates);
- //TODO implementation
- return null;
+ throw new ConfigurationRuntimeException(
+ "Passed in key must select exactly one node: " + key);
}
- finally
+ return new BaseHierarchicalConfiguration(new InMemoryNodeModel(
+ targetNodes.get(0)));
+ }
+
+ /**
+ * Executes a query on the specified key and filters it for node results.
+ *
+ * @param key the key
+ * @return the filtered list with result nodes
+ */
+ private List<ImmutableNode> fetchFilteredNodeResults(String key)
+ {
+ List<QueryResult<ImmutableNode>> results = fetchNodeList(key);
+ List<ImmutableNode> targetNodes = new LinkedList<ImmutableNode>();
+ for (QueryResult<ImmutableNode> result : results)
{
- endWrite();
+ if (!result.isAttributeResult())
+ {
+ targetNodes.add(result.getNode());
+ }
}
+ return targetNodes;
}
/**
@@ -303,16 +323,11 @@ public class BaseHierarchicalConfigurati
}
/**
- * Returns a hierarchical subnode configuration for the node specified by
- * the given key. This is a short form for {@code configurationAt(key,
+ * {@inheritDoc} This is a short form for {@code configurationAt(key,
* <b>false</b>)}.
- *
- * @param key the key that selects the sub tree
- * @return a hierarchical configuration that contains this sub tree
- * @see SubnodeConfiguration
- * @since 1.3
+ * @throws ConfigurationRuntimeException if the key does not select a single node
*/
- public SubnodeConfiguration configurationAt(String key)
+ public HierarchicalConfiguration<ImmutableNode> configurationAt(String key)
{
return configurationAt(key, false);
}
@@ -321,6 +336,7 @@ public class BaseHierarchicalConfigurati
* {@inheritDoc} This implementation creates a {@code SubnodeConfiguration}
* by delegating to {@code configurationAt()}. Then an immutable wrapper
* is created and returned.
+ * @throws ConfigurationRuntimeException if the key does not select a single node
*/
public ImmutableHierarchicalConfiguration immutableConfigurationAt(
String key)
@@ -330,31 +346,8 @@ public class BaseHierarchicalConfigurati
}
/**
- * Returns a list of sub configurations for all configuration nodes selected
- * by the given key. This method will evaluate the passed in key (using the
- * current {@code ExpressionEngine}) and then create a subnode
- * configuration for each returned node (like
- * {@link #configurationAt(String)}}). This is especially
- * useful when dealing with list-like structures. As an example consider the
- * configuration that contains data about database tables and their fields.
- * If you need access to all fields of a certain table, you can simply do
- *
- * <pre>
- * List fields = config.configurationsAt("tables.table(0).fields.field");
- * for(Iterator it = fields.iterator(); it.hasNext();)
- * {
- * BaseHierarchicalConfiguration sub = (BaseHierarchicalConfiguration) it.next();
- * // now the children and attributes of the field node can be
- * // directly accessed
- * String fieldName = sub.getString("name");
- * String fieldType = sub.getString("type");
- * ...
- * </pre>
- *
- * @param key the key for selecting the desired nodes
- * @return a list with hierarchical configuration objects; each
- * configuration represents one of the nodes selected by the passed in key
- * @since 1.3
+ * {@inheritDoc} This implementation creates sub configurations in the same way as
+ * described for {@link #configurationAt(String)}.
*/
public List<HierarchicalConfiguration<ImmutableNode>> configurationsAt(String key)
{
@@ -505,6 +498,22 @@ public class BaseHierarchicalConfigurati
}
/**
+ * Initializes properties of a sub configuration. A sub configuration
+ * inherits some settings from its parent, e.g. the expression engine or the
+ * synchronizer. The corresponding values are copied by this method.
+ *
+ * @param sub the sub configuration to be initialized
+ */
+ private void initSubConfiguration(BaseHierarchicalConfiguration sub)
+ {
+ sub.setSynchronizer(getSynchronizer());
+ sub.setExpressionEngine(getExpressionEngine());
+ sub.setListDelimiterHandler(getListDelimiterHandler());
+ sub.setThrowExceptionOnMissing(isThrowExceptionOnMissing());
+ sub.getInterpolator().setParentInterpolator(getInterpolator());
+ }
+
+ /**
* Initializes the data related to the management of
* {@code SubnodeConfiguration} instances. This method is called each time a
* new {@code SubnodeConfiguration} was created. A configuration and its
Modified: commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/SubnodeConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/SubnodeConfiguration.java?rev=1578582&r1=1578581&r2=1578582&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/SubnodeConfiguration.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/SubnodeConfiguration.java Mon Mar 17 21:12:13 2014
@@ -149,8 +149,6 @@ public class SubnodeConfiguration extend
this.parent = parent;
rootSelector = selector;
- initFromParent(parent);
- initInterpolator();
}
/**
@@ -215,28 +213,4 @@ public class SubnodeConfiguration extend
//TODO implementation
throw new UnsupportedOperationException("Not yet implemented!");
}
-
- /**
- * Initializes this subnode configuration from the given parent
- * configuration. This method is called by the constructor. It will copy
- * many settings from the parent.
- *
- * @param parentConfig the parent configuration
- */
- private void initFromParent(BaseHierarchicalConfiguration parentConfig)
- {
- setExpressionEngine(parentConfig.getExpressionEngine());
- setListDelimiterHandler(parentConfig.getListDelimiterHandler());
- setThrowExceptionOnMissing(parentConfig.isThrowExceptionOnMissing());
- }
-
- /**
- * Initializes the {@code ConfigurationInterpolator} for this sub configuration.
- * This is a standard {@code ConfigurationInterpolator} which also references
- * the {@code ConfigurationInterpolator} of the parent configuration.
- */
- private void initInterpolator()
- {
- getInterpolator().setParentInterpolator(getParent().getInterpolator());
- }
}
Modified: commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java?rev=1578582&r1=1578581&r2=1578582&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java Mon Mar 17 21:12:13 2014
@@ -26,6 +26,7 @@ import java.util.List;
import org.apache.commons.configuration.convert.DefaultListDelimiterHandler;
import org.apache.commons.configuration.event.ConfigurationListener;
+import org.apache.commons.configuration.ex.ConfigurationRuntimeException;
import org.apache.commons.configuration.tree.DefaultConfigurationKey;
import org.apache.commons.configuration.tree.DefaultExpressionEngine;
import org.apache.commons.configuration.tree.ImmutableNode;
@@ -90,7 +91,13 @@ public class TestHierarchicalConfigurati
subset = config.subset("tables.table.fields.field");
prop = subset.getProperty("name");
assertTrue("prop is not a collection", prop instanceof Collection);
- assertEquals(10, ((Collection<?>) prop).size());
+ int expectedFieldCount = 0;
+ for (int i = 0; i < NodeStructureHelper.tablesLength(); i++)
+ {
+ expectedFieldCount += NodeStructureHelper.fieldsLength(i);
+ }
+ assertEquals("Wrong number of fields", expectedFieldCount,
+ ((Collection<?>) prop).size());
assertEquals(NodeStructureHelper.field(0, 0), subset.getProperty("name(0)"));
@@ -147,13 +154,13 @@ public class TestHierarchicalConfigurati
}
/**
- * Tests the configurationAt() method to obtain a configuration for a sub
- * tree.
+ * Tests whether a configuration obtained via configurationAt() contains the
+ * expected properties.
*/
@Test
- public void testConfigurationAt()
+ public void testConfigurationAtReadAccess()
{
- BaseHierarchicalConfiguration subConfig =
+ HierarchicalConfiguration<ImmutableNode> subConfig =
config.configurationAt("tables.table(1)");
assertEquals("Wrong table name", NodeStructureHelper.table(1),
subConfig.getString("name"));
@@ -165,13 +172,65 @@ public class TestHierarchicalConfigurati
assertEquals("Wrong field at position " + i,
NodeStructureHelper.field(1, i), lstFlds.get(i));
}
+ }
+
+ /**
+ * Tests an update operation on a sub configuration which is independent on
+ * its parent.
+ */
+ @Test
+ public void testConfigurationAtUpdateSubConfigIndependent()
+ {
+ HierarchicalConfiguration<ImmutableNode> subConfig =
+ config.configurationAt("tables.table(1)");
+ subConfig.setProperty("name", "testTable");
+ assertEquals("Value not changed", "testTable",
+ subConfig.getString("name"));
+ assertEquals("Change visible in parent", NodeStructureHelper.table(1),
+ config.getString("tables.table(1).name"));
+ }
+
+ /**
+ * Tests an update operation on a parent configuration if the sub
+ * configuration is independent.
+ */
+ @Test
+ public void testConfigurationAtUpdateParentIndependent()
+ {
+ HierarchicalConfiguration<ImmutableNode> subConfig =
+ config.configurationAt("tables.table(1)");
+ config.setProperty("tables.table(1).fields.field(2).name", "testField");
+ assertEquals("Change visible in sub config",
+ NodeStructureHelper.field(1, 2),
+ subConfig.getString("fields.field(2).name"));
+ }
+ /**
+ * Tests an update operation on a sub configuration which is connected to
+ * its parent.
+ */
+ @Test
+ public void testConfigurationAtUpdateSubConfigConnected()
+ {
+ HierarchicalConfiguration<ImmutableNode> subConfig =
+ config.configurationAt("tables.table(1)", true);
subConfig.setProperty("name", "testTable");
- assertEquals("Change not visible in parent", "testTable", config
- .getString("tables.table(1).name"));
+ assertEquals("Change not visible in parent", "testTable",
+ config.getString("tables.table(1).name"));
+ }
+
+ /**
+ * Tests an update operation on a parent configuration if the sub
+ * configuration is connected.
+ */
+ @Test
+ public void testConfigurationAtUpdateParentConnected()
+ {
+ HierarchicalConfiguration<ImmutableNode> subConfig =
+ config.configurationAt("tables.table(1)", true);
config.setProperty("tables.table(1).fields.field(2).name", "testField");
- assertEquals("Change not visible in sub config", "testField", subConfig
- .getString("fields.field(2).name"));
+ assertEquals("Change visible in sub config", "testField",
+ subConfig.getString("fields.field(2).name"));
}
/**
@@ -211,41 +270,71 @@ public class TestHierarchicalConfigurati
}
/**
- * Tests the configurationAt() method when the passed in key does not exist.
+ * Tests the configurationAt() method if the passed in key does not exist.
*/
- @Test(expected = IllegalArgumentException.class)
+ @Test(expected = ConfigurationRuntimeException.class)
public void testConfigurationAtUnknownSubTree()
{
config.configurationAt("non.existing.key");
}
/**
- * Tests the configurationAt() method when the passed in key selects
+ * Tests configurationAt() for a non existing key if the update flag is set.
+ */
+ @Test(expected = ConfigurationRuntimeException.class)
+ public void testConfigurationAtUnknownSubTreeWithUpdates()
+ {
+ config.configurationAt("non.existing.key", true);
+ }
+
+ /**
+ * Tests the configurationAt() method if the passed in key selects
* multiple nodes. This should cause an exception.
*/
- @Test(expected = IllegalArgumentException.class)
+ @Test(expected = ConfigurationRuntimeException.class)
public void testConfigurationAtMultipleNodes()
{
config.configurationAt("tables.table.name");
}
/**
- * Tests whether a sub configuration obtained by configurationAt() can be
- * cleared.
+ * Tests configurationAt() if the passed in key selects multiple nodes and the
+ * update flag is set.
*/
- @Test
- public void testConfigurationAtClear()
+ @Test(expected = ConfigurationRuntimeException.class)
+ public void testConfigurationAtMultipleNodesWithUpdates()
{
- config.addProperty("test.sub.test", "fail");
- assertEquals("Wrong index (1)", 0, config.getMaxIndex("test"));
- SubnodeConfiguration sub = config.configurationAt("test.sub");
- assertEquals("Wrong value", "fail", sub.getString("test"));
- sub.clear();
- assertNull("Key still found", config.getString("test.sub.test"));
- sub.setProperty("test", "success");
- assertEquals("Property not set", "success",
- config.getString("test.sub.test"));
- assertEquals("Wrong index (2)", 0, config.getMaxIndex("test"));
+ config.configurationAt("tables.table.name", true);
+ }
+
+ /**
+ * Checks configurationAt() if the passed in key selects an attribute.
+ * @param withUpdates the updates flag
+ */
+ private void checkConfigurationAtAttributeNode(boolean withUpdates)
+ {
+ final String key = "tables.table(0)[@type]";
+ config.addProperty(key, "system");
+ config.configurationAt(key, withUpdates);
+ }
+
+ /**
+ * Tests configurationAt() if the passed in key selects an attribute result.
+ */
+ @Test(expected = ConfigurationRuntimeException.class)
+ public void testConfigurationAtAttributeNode()
+ {
+ checkConfigurationAtAttributeNode(false);
+ }
+
+ /**
+ * Tests configurationAt() if the passed in key selects an attribute result and the
+ * updates flag is set.
+ */
+ @Test(expected = ConfigurationRuntimeException.class)
+ public void testConfigurationAtAttributeNodeWithUpdates()
+ {
+ checkConfigurationAtAttributeNode(true);
}
/**
@@ -257,8 +346,9 @@ public class TestHierarchicalConfigurati
{
config.addProperty("test.sub.test", "success");
config.addProperty("test.other", "check");
- SubnodeConfiguration sub = config.configurationAt("test.sub");
- sub.clearAndDetachFromParent();
+ HierarchicalConfiguration<ImmutableNode> sub =
+ config.configurationAt("test.sub", true);
+ sub.clear();
assertTrue("Sub not empty", sub.isEmpty());
assertNull("Key still found", config.getString("test.sub.test"));
sub.setProperty("test", "failure!");
@@ -290,7 +380,7 @@ public class TestHierarchicalConfigurati
@Test
public void testConfigurationsAt()
{
- List<SubnodeConfiguration> lstFlds =
+ List<HierarchicalConfiguration<ImmutableNode>> lstFlds =
config.configurationsAt("tables.table(1).fields.field");
checkSubConfigurations(lstFlds);
}
@@ -426,10 +516,10 @@ public class TestHierarchicalConfigurati
@Test
public void testChildConfigurationsAt()
{
- List<SubnodeConfiguration> children =
+ List<HierarchicalConfiguration<ImmutableNode>> children =
config.childConfigurationsAt("tables.table(0)");
assertEquals("Wrong number of elements", 2, children.size());
- SubnodeConfiguration sub = children.get(0);
+ HierarchicalConfiguration<ImmutableNode> sub = children.get(0);
String newTabName = "otherTabe";
sub.setProperty(null, newTabName);
assertEquals("Table name not changed", newTabName,
Modified: commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestSubnodeConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestSubnodeConfiguration.java?rev=1578582&r1=1578581&r2=1578582&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestSubnodeConfiguration.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestSubnodeConfiguration.java Mon Mar 17 21:12:13 2014
@@ -106,18 +106,17 @@ public class TestSubnodeConfiguration
*/
private void setUpSubnodeConfig()
{
- setUpSubnodeConfig(SELECTOR);
+ setUpSubnodeConfig(SUB_KEY);
}
/**
- * Initializes the test configuration using the specified selector.
+ * Initializes the test configuration using the specified key.
*
- * @param selector the selector
+ * @param key the key
*/
- private void setUpSubnodeConfig(NodeSelector selector)
+ private void setUpSubnodeConfig(String key)
{
- TrackedNodeModel subModel = setUpTrackedModel(selector);
- config = new SubnodeConfiguration(parent, subModel, selector);
+ config = (SubnodeConfiguration) parent.configurationAt(key, true);
}
/**
@@ -314,7 +313,7 @@ public class TestSubnodeConfiguration
public void testSetExpressionEngine()
{
parent.setExpressionEngine(new XPathExpressionEngine());
- setUpSubnodeConfig(new NodeSelector("tables/table[1]"));
+ setUpSubnodeConfig("tables/table[1]");
assertEquals("Wrong field name", NodeStructureHelper.field(0, 1),
config.getString("fields/field[2]/name"));
Set<String> keys = new HashSet<String>();
@@ -328,13 +327,30 @@ public class TestSubnodeConfiguration
}
/**
- * Tests the configurationAt() method.
+ * Tests the configurationAt() method if updates are not supported.
+ */
+ @Test
+ public void testConfiguarationAtNoUpdates()
+ {
+ setUpSubnodeConfig();
+ HierarchicalConfiguration<ImmutableNode> sub2 =
+ config.configurationAt("fields.field(1)");
+ assertEquals("Wrong value of property",
+ NodeStructureHelper.field(0, 1), sub2.getString("name"));
+ parent.setProperty("tables.table(0).fields.field(1).name", "otherName");
+ assertEquals("Change of parent is visible",
+ NodeStructureHelper.field(0, 1), sub2.getString("name"));
+ }
+
+ /**
+ * Tests configurationAt() if updates are supported.
*/
@Test
- public void testConfiguarationAt()
+ public void testConfigurationAtWithUpdateSupport()
{
setUpSubnodeConfig();
- SubnodeConfiguration sub2 = config.configurationAt("fields.field(1)");
+ SubnodeConfiguration sub2 =
+ (SubnodeConfiguration) config.configurationAt("fields.field(1)", true);
assertEquals("Wrong value of property",
NodeStructureHelper.field(0, 1), sub2.getString("name"));
assertEquals("Wrong parent", config.getParent(), sub2.getParent());
@@ -360,28 +376,50 @@ public class TestSubnodeConfiguration
}
/**
- * An additional test for interpolation when the configurationAt() method is
- * involved.
+ * Helper method for testing interpolation facilities between a sub and its
+ * parent configuration.
+ *
+ * @param withUpdates the supports updates flag
*/
- @Test
- public void testInterpolationFromConfigurationAt()
+ private void checkInterpolationFromConfigurationAt(boolean withUpdates)
{
parent.addProperty("base.dir", "/home/foo");
parent.addProperty("test.absolute.dir.dir1", "${base.dir}/path1");
parent.addProperty("test.absolute.dir.dir2", "${base.dir}/path2");
parent.addProperty("test.absolute.dir.dir3", "${base.dir}/path3");
- Configuration sub = parent.configurationAt("test.absolute.dir");
+ Configuration sub =
+ parent.configurationAt("test.absolute.dir", withUpdates);
for (int i = 1; i < 4; i++)
{
assertEquals("Wrong interpolation in parent", "/home/foo/path" + i,
parent.getString("test.absolute.dir.dir" + i));
- assertEquals("Wrong interpolation in subnode",
- "/home/foo/path" + i, sub.getString("dir" + i));
+ assertEquals("Wrong interpolation in sub", "/home/foo/path" + i,
+ sub.getString("dir" + i));
}
}
/**
+ * Tests whether interpolation works for a sub configuration obtained via
+ * configurationAt() if updates are not supported.
+ */
+ @Test
+ public void testInterpolationFromConfigurationAtNoUpdateSupport()
+ {
+ checkInterpolationFromConfigurationAt(false);
+ }
+
+ /**
+ * Tests whether interpolation works for a sub configuration obtained via
+ * configurationAt() if updates are supported.
+ */
+ @Test
+ public void testInterpolationFromConfigurationAtWithUpdateSupport()
+ {
+ checkInterpolationFromConfigurationAt(true);
+ }
+
+ /**
* An additional test for interpolation when the configurationAt() method is
* involved for a local interpolation.
*/
@@ -440,7 +478,9 @@ public class TestSubnodeConfiguration
@Test
public void testUpdateEvents() throws ConfigurationException
{
- config = parent.configurationAt(SUB_KEY, true);
+ BaseHierarchicalConfiguration config =
+ (BaseHierarchicalConfiguration) parent.configurationAt(SUB_KEY,
+ true);
ConfigurationListenerTestImpl l = new ConfigurationListenerTestImpl();
config.addConfigurationListener(l);
updateParent();