Author: oheger Date: Sat May 26 11:49:26 2007 New Revision: 541925 URL: http://svn.apache.org/viewvc?view=rev&rev=541925 Log: CONFIGURATION-215: Added a getSource() method to CombinedConfiguration
Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/CombinedConfiguration.java jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestCombinedConfiguration.java Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/CombinedConfiguration.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/CombinedConfiguration.java?view=diff&rev=541925&r1=541924&r2=541925 ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/CombinedConfiguration.java (original) +++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/CombinedConfiguration.java Sat May 26 11:49:26 2007 @@ -512,6 +512,59 @@ } /** + * Returns the configuration source, in which the specified key is defined. + * This method will determine the configuration node that is identified by + * the given key. The following constellations are possible: + * <ul> + * <li>If no node object is found for this key, <b>null</b> is returned.</li> + * <li>If the key maps to multiple nodes belonging to different + * configuration sources, a <code>IllegalArgumentException</code> is + * thrown (in this case no unique source can be determined).</li> + * <li>If exactly one node is found for the key, the (child) configuration + * object, to which the node belongs is determined and returned.</li> + * <li>For keys that have been added directly to this combined + * configuration and that do not belong to the namespaces defined by + * existing child configurations this configuration will be returned.</li> + * </ul> + * + * @param key the key of a configuration property + * @return the configuration, to which this property belongs or <b>null</b> + * if the key cannot be resolved + * @throws IllegalArgumentException if the key maps to multiple properties + * and the source cannot be determined, or if the key is <b>null</b> + * @since 1.5 + */ + public Configuration getSource(String key) + { + if (key == null) + { + throw new IllegalArgumentException("Key must not be null!"); + } + + List nodes = fetchNodeList(key); + if (nodes.isEmpty()) + { + return null; + } + + Iterator it = nodes.iterator(); + Configuration source = findSourceConfiguration((ConfigurationNode) it + .next()); + while (it.hasNext()) + { + Configuration src = findSourceConfiguration((ConfigurationNode) it + .next()); + if (src != source) + { + throw new IllegalArgumentException("The key " + key + + " is defined by multiple sources!"); + } + } + + return source; + } + + /** * Creates the root node of this combined configuration. * * @return the combined root node @@ -538,6 +591,37 @@ } /** + * Determines the configuration that owns the specified node. + * + * @param node the node + * @return the owning configuration + */ + private Configuration findSourceConfiguration(ConfigurationNode node) + { + ConfigurationNode root = null; + ConfigurationNode current = node; + + // find the root node in this hierarchy + while (current != null) + { + root = current; + current = current.getParentNode(); + } + + // Check with the root nodes of the child configurations + for (Iterator it = configurations.iterator(); it.hasNext();) + { + ConfigData cd = (ConfigData) it.next(); + if (root == cd.getRootNode()) + { + return cd.getConfiguration(); + } + } + + return this; + } + + /** * An internal helper class for storing information about contained * configurations. */ @@ -555,6 +639,9 @@ /** Stores the at string.*/ private String at; + /** Stores the root node for this child configuration.*/ + private ConfigurationNode rootNode; + /** * Creates a new instance of <code>ConfigData</code> and initializes * it. @@ -602,6 +689,17 @@ } /** + * Returns the root node for this child configuration. + * + * @return the root node of this child configuration + * @since 1.5 + */ + public ConfigurationNode getRootNode() + { + return rootNode; + } + + /** * Returns the transformed root node of the stored configuration. The * term "transformed" means that an eventually defined at path * has been applied. @@ -630,6 +728,7 @@ .convertToHierarchical(getConfiguration()); atParent.appendChildren(hc.getRootNode()); atParent.appendAttributes(hc.getRootNode()); + rootNode = hc.getRootNode(); return result; } Modified: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestCombinedConfiguration.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestCombinedConfiguration.java?view=diff&rev=541925&r1=541924&r2=541925 ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestCombinedConfiguration.java (original) +++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestCombinedConfiguration.java Sat May 26 11:49:26 2007 @@ -45,6 +45,12 @@ /** Constant for a test key. */ static final String TEST_KEY = "test.value"; + /** Constant for the name of the first child configuration.*/ + static final String CHILD1 = TEST_NAME + "1"; + + /** Constant for the name of the second child configuration.*/ + static final String CHILD2 = TEST_NAME + "2"; + /** The configuration to be tested. */ CombinedConfiguration config; @@ -441,6 +447,115 @@ assertTrue("XML file cannot be removed", testXmlFile.delete()); assertTrue("Props file cannot be removed", testPropsFile.delete()); + } + + /** + * Prepares a test of the getSource() method. + */ + private void setUpSourceTest() + { + HierarchicalConfiguration c1 = new HierarchicalConfiguration(); + PropertiesConfiguration c2 = new PropertiesConfiguration(); + c1.addProperty(TEST_KEY, TEST_NAME); + c2.addProperty("another.key", "test"); + config.addConfiguration(c1, CHILD1); + config.addConfiguration(c2, CHILD2); + } + + /** + * Tests the gestSource() method when the source property is defined in a + * hierarchical configuration. + */ + public void testGetSourceHierarchical() + { + setUpSourceTest(); + assertEquals("Wrong source configuration", config + .getConfiguration(CHILD1), config.getSource(TEST_KEY)); + } + + /** + * Tests whether the source configuration can be detected for non + * hierarchical configurations. + */ + public void testGetSourceNonHierarchical() + { + setUpSourceTest(); + assertEquals("Wrong source configuration", config + .getConfiguration(CHILD2), config.getSource("another.key")); + } + + /** + * Tests the getSource() method when the passed in key is not contained. + * Result should be null in this case. + */ + public void testGetSourceUnknown() + { + setUpSourceTest(); + assertNull("Wrong result for unknown key", config + .getSource("an.unknown.key")); + } + + /** + * Tests the getSource() method when a null key is passed in. This should + * cause an exception. + */ + public void testGetSourceNull() + { + try + { + config.getSource(null); + fail("Could resolve source for null key!"); + } + catch (IllegalArgumentException iex) + { + // ok + } + } + + /** + * Tests the getSource() method when the passed in key belongs to the + * combined configuration itself. + */ + public void testGetSourceCombined() + { + setUpSourceTest(); + final String key = "yet.another.key"; + config.addProperty(key, Boolean.TRUE); + assertEquals("Wrong source for key", config, config.getSource(key)); + } + + /** + * Tests the getSource() method when the passed in key refers to multiple + * values, which are all defined in the same source configuration. + */ + public void testGetSourceMulti() + { + setUpSourceTest(); + final String key = "list.key"; + config.getConfiguration(CHILD1).addProperty(key, "1,2,3"); + assertEquals("Wrong source for multi-value property", config + .getConfiguration(CHILD1), config.getSource(key)); + } + + /** + * Tests the getSource() method when the passed in key refers to multiple + * values defined by different sources. This should cause an exception. + */ + public void testGetSourceMultiSources() + { + setUpSourceTest(); + final String key = "list.key"; + config.getConfiguration(CHILD1).addProperty(key, "1,2,3"); + config.getConfiguration(CHILD2).addProperty(key, "a,b,c"); + try + { + config.getSource(key); + fail("Multiple sources not detected!"); + } + catch (IllegalArgumentException iex) + { + //ok + } } /** --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]