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 2012/12/29 21:16:40 UTC

svn commit: r1426821 - in /commons/proper/configuration/trunk/src: main/java/org/apache/commons/configuration/builder/combined/ test/java/org/apache/commons/configuration/builder/combined/ test/resources/

Author: oheger
Date: Sat Dec 29 20:16:40 2012
New Revision: 1426821

URL: http://svn.apache.org/viewvc?rev=1426821&view=rev
Log:
CombinedConfigurationBuilder now creates child builders at a later stage. This makes it possible to enable enhanced interpolation in the definition configuration.

Modified:
    commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/CombinedConfigurationBuilder.java
    commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestCombinedConfigurationBuilder.java
    commons/proper/configuration/trunk/src/test/resources/testInterpolation.properties
    commons/proper/configuration/trunk/src/test/resources/testInterpolationBuilder.xml

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/CombinedConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/CombinedConfigurationBuilder.java?rev=1426821&r1=1426820&r2=1426821&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/CombinedConfigurationBuilder.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/builder/combined/CombinedConfigurationBuilder.java Sat Dec 29 20:16:40 2012
@@ -567,20 +567,33 @@ public class CombinedConfigurationBuilde
     }
 
     /**
+     * <p>
      * Returns the configuration builder with the given name. With this method a
      * builder of a child configuration which was given a name in the
      * configuration definition file can be accessed directly.
+     * </p>
+     * <p>
+     * <strong>Important note:</strong> This method only returns a meaningful
+     * result after the result configuration has been created by calling
+     * {@code getConfiguration()}. If called before, always an exception is
+     * thrown.
+     * </p>
      *
      * @param name the name of the builder in question
      * @return the child configuration builder with this name
-     * @throws ConfigurationException if an error occurs setting up the
-     *         definition configuration or no builder with this name exists
+     * @throws ConfigurationException if information about named builders is not
+     *         yet available or no builder with this name exists
      */
     public synchronized ConfigurationBuilder<? extends Configuration> getNamedBuilder(
             String name) throws ConfigurationException
     {
+        if (sourceData == null)
+        {
+            throw new ConfigurationException("Information about child builders"
+                    + " has not been setup yet! Call getConfiguration() first.");
+        }
         ConfigurationBuilder<? extends Configuration> builder =
-                getSourceData().getNamedBuilder(name);
+                sourceData.getNamedBuilder(name);
         if (builder == null)
         {
             throw new ConfigurationException("Builder cannot be resolved: "
@@ -590,21 +603,33 @@ public class CombinedConfigurationBuilde
     }
 
     /**
+     * <p>
      * Returns a set with the names of all child configuration builders. A tag
      * defining a configuration source in the configuration definition file can
      * have the {@code config-name} attribute. If this attribute is present, the
      * corresponding builder is assigned this name and can be directly accessed
      * through the {@link #getNamedBuilder(String)} method. This method returns
      * a collection with all available builder names.
+     * </p>
+     * <p>
+     * <strong>Important note:</strong> This method only returns a meaningful
+     * result after the result configuration has been created by calling
+     * {@code getConfiguration()}. If called before, always an empty set is
+     * returned.
+     * </p>
      *
-     * @return a collection with the names of all builders
-     * @throws ConfigurationException if an error occurs setting up the
-     *         definition configuration
+     * @return a set with the names of all builders
      */
     public synchronized Set<String> builderNames()
-            throws ConfigurationException
     {
-        return Collections.unmodifiableSet(getSourceData().builderNames());
+        if (sourceData == null)
+        {
+            return Collections.emptySet();
+        }
+        else
+        {
+            return Collections.unmodifiableSet(sourceData.builderNames());
+        }
     }
 
     /**
@@ -749,13 +774,13 @@ public class CombinedConfigurationBuilde
         setUpParentInterpolator(currentConfiguration, config);
 
         ConfigurationSourceData data = getSourceData();
-        createAndAddConfigurations(result, data.getOverrideBuilders(), data);
-        if (!data.getUnionBuilders().isEmpty())
+        data.createAndAddConfigurations(result, data.getOverrideSources());
+        if (!data.getUnionSources().isEmpty())
         {
             CombinedConfiguration addConfig = createAdditionalsConfiguration(result);
             result.addConfiguration(addConfig, ADDITIONAL_NAME);
             initNodeCombinerListNodes(addConfig, config, KEY_ADDITIONAL_LIST);
-            createAndAddConfigurations(addConfig, data.getUnionBuilders(), data);
+            data.createAndAddConfigurations(addConfig, data.getUnionSources());
         }
         currentConfiguration = null;
     }
@@ -1281,40 +1306,6 @@ public class CombinedConfigurationBuilde
     }
 
     /**
-     * Queries the current {@code Configuration} objects from the given builders
-     * and adds them to the specified combined configuration.
-     *
-     * @param cc the resulting combined configuration
-     * @param builders the collection with configuration builders
-     * @param srcData the data object for configuration sources
-     * @throws ConfigurationException if an error occurs
-     */
-    private static void createAndAddConfigurations(CombinedConfiguration cc,
-            Collection<ConfigurationBuilder<? extends Configuration>> builders,
-            ConfigurationSourceData srcData) throws ConfigurationException
-    {
-        for (ConfigurationBuilder<? extends Configuration> builder : builders)
-        {
-            ConfigurationDeclaration decl = srcData.getDeclaration(builder);
-            assert decl != null : "Cannot resolve builder!";
-            try
-            {
-                cc.addConfiguration(
-                        (AbstractConfiguration) builder.getConfiguration(),
-                        decl.getName(), decl.getAt());
-            }
-            catch (ConfigurationException cex)
-            {
-                // ignore exceptions for optional configurations
-                if (!decl.isOptional())
-                {
-                    throw cex;
-                }
-            }
-        }
-    }
-
-    /**
      * Creates the map with the default configuration builder providers.
      *
      * @return the map with default providers
@@ -1342,23 +1333,14 @@ public class CombinedConfigurationBuilde
     private class ConfigurationSourceData
     {
         /** A list with all builders for override configurations. */
-        private final Collection<ConfigurationBuilder<? extends Configuration>> overrideBuilders;
+        private final Collection<SubnodeConfiguration> overrideBuilders;
 
         /** A list with all builders for union configurations. */
-        private final Collection<ConfigurationBuilder<? extends Configuration>> unionBuilders;
-
-        /** A list with all sub builders (override plus union). */
-        private final Collection<ConfigurationBuilder<? extends Configuration>> allBuilders;
+        private final Collection<SubnodeConfiguration> unionBuilders;
 
         /** A map for direct access to a builder by its name. */
         private final Map<String, ConfigurationBuilder<? extends Configuration>> namedBuilders;
 
-        /**
-         * A map for retrieving the bean declarations associated with
-         * configuration builders.
-         */
-        private final Map<ConfigurationBuilder<? extends Configuration>, ConfigurationDeclaration> declarations;
-
         /** A listener for reacting on changes of sub builders. */
         private BuilderListener changeListener;
 
@@ -1368,15 +1350,11 @@ public class CombinedConfigurationBuilde
         public ConfigurationSourceData()
         {
             overrideBuilders =
-                    new LinkedList<ConfigurationBuilder<? extends Configuration>>();
+                    new LinkedList<SubnodeConfiguration>();
             unionBuilders =
-                    new LinkedList<ConfigurationBuilder<? extends Configuration>>();
-            allBuilders =
-                    new LinkedList<ConfigurationBuilder<? extends Configuration>>();
+                    new LinkedList<SubnodeConfiguration>();
             namedBuilders =
                     new HashMap<String, ConfigurationBuilder<? extends Configuration>>();
-            declarations =
-                    new HashMap<ConfigurationBuilder<? extends Configuration>, ConfigurationDeclaration>();
         }
 
         /**
@@ -1388,16 +1366,35 @@ public class CombinedConfigurationBuilde
         public void initFromDefinitionConfiguration(
                 HierarchicalConfiguration config) throws ConfigurationException
         {
-            createBuilders(overrideBuilders,
-                    fetchTopLevelOverrideConfigs(config));
-            createBuilders(overrideBuilders,
-                    config.childConfigurationsAt(KEY_OVERRIDE));
-            createBuilders(unionBuilders,
-                    config.childConfigurationsAt(KEY_UNION));
-
-            allBuilders.addAll(overrideBuilders);
-            allBuilders.addAll(unionBuilders);
-            registerChangeListener();
+            overrideBuilders.addAll(fetchTopLevelOverrideConfigs(config));
+            overrideBuilders.addAll(config.childConfigurationsAt(KEY_OVERRIDE));
+            unionBuilders.addAll(config.childConfigurationsAt(KEY_UNION));
+        }
+
+        /**
+         * Processes the declaration of configuration builder providers, creates
+         * the corresponding builder, obtains configurations, and adds them to
+         * the specified result configuration.
+         *
+         * @param ccResult the result configuration
+         * @param srcDecl the collection with the declarations of configuration
+         *        sources to process
+         * @throws ConfigurationException if an error occurs
+         */
+        public void createAndAddConfigurations(CombinedConfiguration ccResult,
+                Collection<SubnodeConfiguration> srcDecl)
+                throws ConfigurationException
+        {
+            createBuilderChangeListener();
+            for (HierarchicalConfiguration src : srcDecl)
+            {
+                ConfigurationDeclaration decl =
+                        new ConfigurationDeclaration(
+                                CombinedConfigurationBuilder.this, src);
+                ConfigurationBuilder<? extends Configuration> builder =
+                        createConfigurationBuilder(src, decl);
+                addChildConfiguration(ccResult, decl, builder);
+            }
         }
 
         /**
@@ -1406,30 +1403,31 @@ public class CombinedConfigurationBuilde
          */
         public void cleanUp()
         {
-            for (ConfigurationBuilder<?> b : allBuilders)
+            for (ConfigurationBuilder<?> b : namedBuilders.values())
             {
                 b.removeBuilderListener(changeListener);
             }
+            namedBuilders.clear();
         }
 
         /**
-         * Returns a collection with all configuration builders defined in the
-         * override section.
+         * Returns a collection with all configuration source declarations
+         * defined in the override section.
          *
          * @return the override configuration builders
          */
-        public Collection<ConfigurationBuilder<? extends Configuration>> getOverrideBuilders()
+        public Collection<SubnodeConfiguration> getOverrideSources()
         {
             return overrideBuilders;
         }
 
         /**
-         * Returns a collection with all configuration builders defined in the
-         * union section.
+         * Returns a collection with all configuration source declarations
+         * defined in the union section.
          *
          * @return the union configuration builders
          */
-        public Collection<ConfigurationBuilder<? extends Configuration>> getUnionBuilders()
+        public Collection<SubnodeConfiguration> getUnionSources()
         {
             return unionBuilders;
         }
@@ -1459,25 +1457,72 @@ public class CombinedConfigurationBuilde
         }
 
         /**
-         * Returns the {@code ConfigurationDeclaration} associated with the
-         * specified builder. If the builder is unknown, result is <b>null</b>.
+         * Creates a configuration builder based on a source declaration in the
+         * definition configuration.
          *
-         * @param builder the builder in question
-         * @return the {@code ConfigurationDeclaration} for this builder or
-         *         <b>null</b>
+         * @param src the sub configuration for the current configuration source
+         * @param decl the current {@code ConfigurationDeclaration}
+         * @return the newly created bulder
+         * @throws ConfigurationException if an error occurs
          */
-        public ConfigurationDeclaration getDeclaration(
-                ConfigurationBuilder<?> builder)
+        private ConfigurationBuilder<? extends Configuration> createConfigurationBuilder(
+                HierarchicalConfiguration src, ConfigurationDeclaration decl)
+                throws ConfigurationException
         {
-            return declarations.get(builder);
+            ConfigurationBuilderProvider provider =
+                    providerForTag(src.getRootElementName());
+            if (provider == null)
+            {
+                throw new ConfigurationException(
+                        "Unsupported configuration source: "
+                                + src.getRootElementName());
+            }
+
+            ConfigurationBuilder<? extends Configuration> builder =
+                    provider.getConfigurationBuilder(decl);
+            if (decl.getName() != null)
+            {
+                namedBuilders.put(decl.getName(), builder);
+            }
+            builder.addBuilderListener(changeListener);
+            return builder;
+        }
+
+        /**
+         * Creates a new configuration using the specified builder and adds it
+         * to the resulting combined configuration.
+         *
+         * @param ccResult the resulting combined configuration
+         * @param decl the current {@code ConfigurationDeclaration}
+         * @param builder the configuration builder
+         * @throws ConfigurationException if an error occurs
+         */
+        private void addChildConfiguration(CombinedConfiguration ccResult,
+                ConfigurationDeclaration decl,
+                ConfigurationBuilder<? extends Configuration> builder)
+                throws ConfigurationException
+        {
+            try
+            {
+                ccResult.addConfiguration(
+                        (AbstractConfiguration) builder.getConfiguration(),
+                        decl.getName(), decl.getAt());
+            }
+            catch (ConfigurationException cex)
+            {
+                // ignore exceptions for optional configurations
+                if (!decl.isOptional())
+                {
+                    throw cex;
+                }
+            }
         }
 
         /**
-         * Registers a change listener at all sub builders. Whenever one of the
-         * sub builders is reset, the combined configuration managed by this
-         * builder has to be reset, too.
+         * Creates a listener for builder change events. This listener is
+         * registered at all builders for child configurations.
          */
-        private void registerChangeListener()
+        private void createBuilderChangeListener()
         {
             changeListener = new BuilderListener()
             {
@@ -1487,11 +1532,6 @@ public class CombinedConfigurationBuilde
                     resetResult();
                 }
             };
-
-            for (ConfigurationBuilder<?> b : allBuilders)
-            {
-                b.addBuilderListener(changeListener);
-            }
         }
 
         /**
@@ -1525,43 +1565,5 @@ public class CombinedConfigurationBuilde
             }
             return configs;
         }
-
-        /**
-         * Creates configuration builder objects from the given configurations
-         * for configuration sources.
-         *
-         * @param builders the collection with builders to be filled
-         * @param sources the definitions for the single configuration sources
-         * @throws ConfigurationException if an error occurs
-         */
-        private void createBuilders(
-                Collection<ConfigurationBuilder<? extends Configuration>> builders,
-                Collection<? extends HierarchicalConfiguration> sources)
-                throws ConfigurationException
-        {
-            for (HierarchicalConfiguration src : sources)
-            {
-                ConfigurationBuilderProvider provider =
-                        providerForTag(src.getRootElementName());
-                if (provider == null)
-                {
-                    throw new ConfigurationException(
-                            "Unsupported configuration source: "
-                                    + src.getRootElementName());
-                }
-
-                ConfigurationDeclaration decl =
-                        new ConfigurationDeclaration(
-                                CombinedConfigurationBuilder.this, src);
-                ConfigurationBuilder<? extends Configuration> builder =
-                        provider.getConfigurationBuilder(decl);
-                builders.add(builder);
-                declarations.put(builder, decl);
-                if (decl.getName() != null)
-                {
-                    namedBuilders.put(decl.getName(), builder);
-                }
-            }
-        }
     }
 }

Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestCombinedConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestCombinedConfigurationBuilder.java?rev=1426821&r1=1426820&r2=1426821&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestCombinedConfigurationBuilder.java (original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/builder/combined/TestCombinedConfigurationBuilder.java Sat Dec 29 20:16:40 2012
@@ -299,6 +299,19 @@ public class TestCombinedConfigurationBu
     }
 
     /**
+     * Tests the behavior of builderNames() before the result configuration has
+     * been created.
+     */
+    @Test
+    public void testBuilderNamesBeforeConfigurationAccess()
+    {
+        assertTrue("Got builders (1)", factory.builderNames().isEmpty());
+        factory.configure(new FileBasedBuilderParametersImpl()
+                .setFile(TEST_FILE));
+        assertTrue("Got builders (2)", factory.builderNames().isEmpty());
+    }
+
+    /**
      * Tests whether the names of sub builders can be queried.
      */
     @Test
@@ -306,6 +319,7 @@ public class TestCombinedConfigurationBu
     {
         factory.configure(new FileBasedBuilderParametersImpl()
                 .setFile(TEST_FILE));
+        factory.getConfiguration();
         Set<String> names = factory.builderNames();
         List<String> expected = Arrays.asList("props", "xml");
         assertEquals("Wrong number of named builders", expected.size(),
@@ -321,8 +335,9 @@ public class TestCombinedConfigurationBu
     {
         factory.configure(new FileBasedBuilderParametersImpl()
                 .setFile(TEST_FILE));
+        factory.getConfiguration();
         Set<String> names = factory.builderNames();
-        names.clear();
+        names.add(BUILDER_NAME);
     }
 
     /**
@@ -333,6 +348,7 @@ public class TestCombinedConfigurationBu
     {
         factory.configure(new FileBasedBuilderParametersImpl()
                 .setFile(TEST_FILE));
+        factory.getConfiguration();
         ConfigurationBuilder<? extends Configuration> propBuilder =
                 factory.getNamedBuilder("props");
         assertTrue("Wrong builder class",
@@ -350,6 +366,20 @@ public class TestCombinedConfigurationBu
     {
         factory.configure(new FileBasedBuilderParametersImpl()
                 .setFile(TEST_FILE));
+        factory.getConfiguration();
+        factory.getNamedBuilder("nonExistingBuilder");
+    }
+
+    /**
+     * Tries to query a named builder before the result configuration has been
+     * created.
+     */
+    @Test(expected = ConfigurationException.class)
+    public void testGetNamedBuilderBeforeConfigurationAccess()
+            throws ConfigurationException
+    {
+        factory.configure(new FileBasedBuilderParametersImpl()
+                .setFile(TEST_FILE));
         factory.getNamedBuilder("nonExistingBuilder");
     }
 
@@ -406,6 +436,7 @@ public class TestCombinedConfigurationBu
         Map<String, Object> attrs = new HashMap<String, Object>();
         attrs.put("config-reload", Boolean.TRUE);
         prepareSubBuilderTest(attrs);
+        factory.getConfiguration();
         assertTrue(
                 "Not a reloading builder",
                 factory.getNamedBuilder(BUILDER_NAME) instanceof ReloadingFileBasedConfigurationBuilder);
@@ -438,6 +469,7 @@ public class TestCombinedConfigurationBu
     {
         Map<String, Object> attrs = new HashMap<String, Object>();
         prepareSubBuilderTest(attrs);
+        factory.getConfiguration();
         BasicConfigurationBuilder<?> subBuilder =
                 (BasicConfigurationBuilder<?>) factory
                         .getNamedBuilder(BUILDER_NAME);

Modified: commons/proper/configuration/trunk/src/test/resources/testInterpolation.properties
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/resources/testInterpolation.properties?rev=1426821&r1=1426820&r2=1426821&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/resources/testInterpolation.properties (original)
+++ commons/proper/configuration/trunk/src/test/resources/testInterpolation.properties Sat Dec 29 20:16:40 2012
@@ -17,6 +17,7 @@
 # configuration sources created by a DefaultConfigurationBuilder.
 # This properties configuration defines a property which is referenced by
 # another configuration source.
-# $Id:$
+# $Id$
 myvar=abc
+testXmlFile=testInterpolation.xml
 

Modified: commons/proper/configuration/trunk/src/test/resources/testInterpolationBuilder.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/resources/testInterpolationBuilder.xml?rev=1426821&r1=1426820&r2=1426821&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/resources/testInterpolationBuilder.xml (original)
+++ commons/proper/configuration/trunk/src/test/resources/testInterpolationBuilder.xml Sat Dec 29 20:16:40 2012
@@ -20,12 +20,12 @@
   configuration sources created by a DefaultConfigurationBuilder.
   This configuration definition file for a DefaultConfigurationBuilder
   references multiple sources which contain variable references.
-  $Id:$
+  $Id$
 -->
 <configuration>
   <system/>
   <properties fileName="testInterpolation.properties"/>
-  <xml fileName="testInterpolation.xml" config-name="test">
+  <xml fileName="${testXmlFile}" config-name="test">
     <expressionEngine config-class="org.apache.commons.configuration.tree.xpath.XPathExpressionEngine"/>
   </xml>
 </configuration>