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 &quot;transformed&quot; 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]

Reply via email to