You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by oh...@apache.org on 2006/12/06 22:11:37 UTC

svn commit: r483227 - in /jakarta/commons/proper/configuration/trunk: src/java/org/apache/commons/configuration/ src/test/org/apache/commons/configuration/ xdocs/

Author: oheger
Date: Wed Dec  6 13:11:37 2006
New Revision: 483227

URL: http://svn.apache.org/viewvc?view=rev&rev=483227
Log:
Add support for new config-forceCreate attribute in configuration definition files for DefaultConfigurationBuilder; fix for CONFIGURATION-243

Modified:
    jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DefaultConfigurationBuilder.java
    jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDefaultConfigurationBuilder.java
    jakarta/commons/proper/configuration/trunk/xdocs/changes.xml
    jakarta/commons/proper/configuration/trunk/xdocs/howto_configurationbuilder.xml

Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DefaultConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DefaultConfigurationBuilder.java?view=diff&rev=483227&r1=483226&r2=483227
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DefaultConfigurationBuilder.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DefaultConfigurationBuilder.java Wed Dec  6 13:11:37 2006
@@ -222,6 +222,12 @@
     static final String ATTR_FILENAME = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
             + "fileName" + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
 
+    /** Constant for the forceCreate attribute. */
+    static final String ATTR_FORCECREATE = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+            + XMLBeanDeclaration.RESERVED_PREFIX
+            + "forceCreate"
+            + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
+
     /** Constant for the name of the header section. */
     static final String SEC_HEADER = "header";
 
@@ -761,6 +767,27 @@
             return (AbstractConfiguration) createBean(getConfigurationClass(),
                     decl, null);
         }
+
+        /**
+         * Returns an uninitialized configuration of the represented type. This
+         * method will be called for optional configurations when the
+         * <code>getConfiguration()</code> method caused an error and the
+         * <code>forceCreate</code> attribute is set. A concrete sub class can
+         * here try to create an uninitialized, empty configuration, which may
+         * be possible if the error was created during initialization. This base
+         * implementation just returns <b>null</b>.
+         *
+         * @param decl the bean declaration with initialization parameters for
+         * the configuration
+         * @return the new configuration object
+         * @throws Exception if an error occurs
+         * @since 1.4
+         */
+        public AbstractConfiguration getEmptyConfiguration(
+                ConfigurationDeclaration decl) throws Exception
+        {
+            return null;
+        }
     }
 
     /**
@@ -773,12 +800,12 @@
      * configuration source from the configuration definition file. The
      * declaration of a configuration source is very similar to a bean
      * declaration processed by <code>XMLBeanDeclaration</code>. There are
-     * very few differences, e.g. the two reserved attributes
+     * very few differences, e.g. some reserved attributes like
      * <code>optional</code> and <code>at</code> and the fact that a bean
      * factory is never needed.
      * </p>
      */
-    protected static class ConfigurationDeclaration extends XMLBeanDeclaration
+    public static class ConfigurationDeclaration extends XMLBeanDeclaration
     {
         /** Stores a reference to the associated configuration builder. */
         private DefaultConfigurationBuilder configurationBuilder;
@@ -838,6 +865,23 @@
         }
 
         /**
+         * Returns a flag whether this configuration should always be created
+         * and added to the resulting combined configuration. This flag is
+         * evaluated only for optional configurations whose normal creation has
+         * caused an error. If for such a configuration the
+         * <code>forceCreate</code> attribute is set and the corresponding
+         * configuration provider supports this mode, an empty configuration
+         * will be created and added to the resulting combined configuration.
+         *
+         * @return the value of the <code>forceCreate</code> attribute
+         * @since 1.4
+         */
+        public boolean isForceCreate()
+        {
+            return this.getConfiguration().getBoolean(ATTR_FORCECREATE, false);
+        }
+
+        /**
          * Returns the name of the bean factory. For configuration source
          * declarations always a reserved factory is used. This factory's name
          * is returned by this implementation.
@@ -909,7 +953,9 @@
          * It will determine the responsible configuration provider and delegate
          * the call to this instance. If creation of the configuration fails
          * and the <code>optional</code> attribute is set, the exception will
-         * be ignored and <b>null</b> will be returned.
+         * be ignored. If the <code>forceCreate</code> attribute is set, too,
+         * the provider is asked to create an empty configuration. A return
+         * value of <b>null</b> means that no configuration could be created.
          *
          * @param beanClass the bean class (will be ignored)
          * @param data the declaration
@@ -944,6 +990,17 @@
                 }
                 else
                 {
+                    if (decl.isForceCreate())
+                    {
+                        try
+                        {
+                            return provider.getEmptyConfiguration(decl);
+                        }
+                        catch (Exception ex2)
+                        {
+                            // Ignore exception, return null in this case
+                        }
+                    }
                     return null;
                 }
             }
@@ -1000,10 +1057,32 @@
         public AbstractConfiguration getConfiguration(
                 ConfigurationDeclaration decl) throws Exception
         {
-            FileConfiguration config = (FileConfiguration) super
-                    .getConfiguration(decl);
-            config.load();
-            return (AbstractConfiguration) config;
+            AbstractConfiguration result = getEmptyConfiguration(decl);
+            ((FileConfiguration) result).load();
+            return result;
+        }
+
+        /**
+         * Returns an uninitialized file configuration. This method will be
+         * called for optional configurations when the
+         * <code>getConfiguration()</code> method caused an error and the
+         * <code>forceCreate</code> attribute is set. It will create the
+         * configuration of the represented type, but the <code>load()</code>
+         * method won't be called. This way non-existing configuration files can
+         * be handled gracefully: If loading a the file fails, an empty
+         * configuration will be created that is already configured with the
+         * correct file name.
+         *
+         * @param decl the bean declaration with initialization parameters for
+         * the configuration
+         * @return the new configuration object
+         * @throws Exception if an error occurs
+         * @since 1.4
+         */
+        public AbstractConfiguration getEmptyConfiguration(
+                ConfigurationDeclaration decl) throws Exception
+        {
+            return super.getConfiguration(decl);
         }
 
         /**
@@ -1120,6 +1199,22 @@
             DefaultConfigurationBuilder builder = (DefaultConfigurationBuilder) super
                     .getConfiguration(decl);
             return builder.getConfiguration(true);
+        }
+
+        /**
+         * Returns an empty configuration in case of an optional configuration
+         * could not be created. This implementation returns an empty combined
+         * configuration.
+         *
+         * @param decl the configuration declaration
+         * @return the configuration
+         * @exception Exception if an error occurs
+         * @since 1.4
+         */
+        public AbstractConfiguration getEmptyConfiguration(
+                ConfigurationDeclaration decl) throws Exception
+        {
+            return new CombinedConfiguration();
         }
     }
 

Modified: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDefaultConfigurationBuilder.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDefaultConfigurationBuilder.java?view=diff&rev=483227&r1=483226&r2=483227
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDefaultConfigurationBuilder.java (original)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDefaultConfigurationBuilder.java Wed Dec  6 13:11:37 2006
@@ -55,6 +55,9 @@
     private static final File INIT_FILE = new File(
             "conf/testComplexInitialization.xml");
 
+    /** Constant for the name of an optional configuration.*/
+    private static final String OPTIONAL_NAME = "optionalConfig";
+
     /** Stores the object to be tested. */
     DefaultConfigurationBuilder factory;
 
@@ -434,16 +437,91 @@
      */
     public void testLoadOptionalNonFileBased() throws ConfigurationException
     {
-        factory.addProperty("override.configuration[@fileName]",
-                "nonExisting.xml");
-        factory.addProperty("override.configuration[@config-optional]",
-                Boolean.TRUE);
-        factory.addProperty("override.configuration[@config-name]",
-                "optionalConfig");
-        CombinedConfiguration config = factory.getConfiguration(false);
+        CombinedConfiguration config = prepareOptionalTest("configuration", false);
         assertTrue("Configuration not empty", config.isEmpty());
         assertEquals("Wrong number of configurations", 0, config
                 .getNumberOfConfigurations());
+    }
+
+    /**
+     * Tests an optional, non existing configuration with the forceCreate
+     * attribute. This configuration should be added to the resulting
+     * configuration.
+     */
+    public void testLoadOptionalForceCreate() throws ConfigurationException
+    {
+        factory.setBasePath(TEST_FILE.getParent());
+        CombinedConfiguration config = prepareOptionalTest("xml", true);
+        assertEquals("Wrong number of configurations", 1, config
+                .getNumberOfConfigurations());
+        FileConfiguration fc = (FileConfiguration) config
+                .getConfiguration(OPTIONAL_NAME);
+        assertNotNull("Optional config not found", fc);
+        assertEquals("File name was not set", "nonExisting.xml", fc
+                .getFileName());
+        assertNotNull("Base path was not set", fc.getBasePath());
+    }
+
+    /**
+     * Tests loading an embedded optional configuration builder with the force
+     * create attribute.
+     */
+    public void testLoadOptionalBuilderForceCreate()
+            throws ConfigurationException
+    {
+        CombinedConfiguration config = prepareOptionalTest("configuration",
+                true);
+        assertEquals("Wrong number of configurations", 1, config
+                .getNumberOfConfigurations());
+        assertTrue(
+                "Wrong optional configuration type",
+                config.getConfiguration(OPTIONAL_NAME) instanceof CombinedConfiguration);
+    }
+
+    /**
+     * Tests loading an optional configuration with the force create attribute
+     * set. The provider will always throw an exception. In this case the
+     * configuration will not be added to the resulting combined configuration.
+     */
+    public void testLoadOptionalForceCreateWithException()
+            throws ConfigurationException
+    {
+        factory.addConfigurationProvider("test",
+                new DefaultConfigurationBuilder.ConfigurationBuilderProvider()
+                {
+                    // Throw an exception here, too
+                    public AbstractConfiguration getEmptyConfiguration(
+                            DefaultConfigurationBuilder.ConfigurationDeclaration decl) throws Exception
+                    {
+                        throw new Exception("Unable to create configuration!");
+                    }
+                });
+        CombinedConfiguration config = prepareOptionalTest("test", true);
+        assertEquals("Optional configuration could be created", 0, config
+                .getNumberOfConfigurations());
+    }
+
+    /**
+     * Prepares a test for loading a configuration definition file with an
+     * optional configuration declaration.
+     *
+     * @param tag the tag name with the optional configuration
+     * @param force the forceCreate attribute
+     * @return the combined configuration obtained from the builder
+     * @throws ConfigurationException if an error occurs
+     */
+    private CombinedConfiguration prepareOptionalTest(String tag, boolean force)
+            throws ConfigurationException
+    {
+        String prefix = "override." + tag;
+        factory.addProperty(prefix + "[@fileName]", "nonExisting.xml");
+        factory.addProperty(prefix + "[@config-optional]", Boolean.TRUE);
+        factory.addProperty(prefix + "[@config-name]", OPTIONAL_NAME);
+        if (force)
+        {
+            factory.addProperty(prefix + "[@config-forceCreate]", Boolean.TRUE);
+        }
+        return factory.getConfiguration(false);
     }
 
     /**

Modified: jakarta/commons/proper/configuration/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/xdocs/changes.xml?view=diff&rev=483227&r1=483226&r2=483227
==============================================================================
--- jakarta/commons/proper/configuration/trunk/xdocs/changes.xml (original)
+++ jakarta/commons/proper/configuration/trunk/xdocs/changes.xml Wed Dec  6 13:11:37 2006
@@ -23,6 +23,16 @@
 
   <body>
     <release version="1.4-dev" date="in SVN">
+      <action dev="oheger" type="add" issue="CONFIGURATION-243">
+        Configuration declarations in the configuration definition file for
+        DefaultConfigurationBuilder that are marked as optional now support a
+        new attribute <code>config-forceCreate</code>. If this attribute is set
+        to true and the initialization of the configuration fails,
+        DefaultConfigurationBuilder tries to add an empty configuration of the
+        correct type to the resulting combined configuration. Before this
+        change optional configurations that caused errors were never added to
+        the combined configuration.
+      </action>
       <action dev="oheger" type="update" issue="CONFIGURATION-241">
         CompositeConfiguration.clearProperty() now generates the correct
         update events.

Modified: jakarta/commons/proper/configuration/trunk/xdocs/howto_configurationbuilder.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/xdocs/howto_configurationbuilder.xml?view=diff&rev=483227&r1=483226&r2=483227
==============================================================================
--- jakarta/commons/proper/configuration/trunk/xdocs/howto_configurationbuilder.xml (original)
+++ jakarta/commons/proper/configuration/trunk/xdocs/howto_configurationbuilder.xml Wed Dec  6 13:11:37 2006
@@ -212,12 +212,38 @@
       <td valign="top"><code>config-optional</code></td>
       <td>Declares a configuration as optional. This means that errors that
       occur when creating the configuration are silently ignored. Note that in
-      case of an error no configuration is added to the resulting combined
+      case of an error per default no configuration is added to the resulting combined
       configuration. This fact can be used to find out whether an optional
       configuration could be successfully created or not: If you specify a name
       for the optional configuration (using the <code>config-name</code>
       attribute), you can later check the combined configuration whether it
-      contains a configuration with this name.</td>
+      contains a configuration with this name. With the
+      <code>config-forceCreate</code> attribute (see below) this default
+      behavior can be changed.</td>
+    </tr>
+    <tr>
+      <td valign="top"><code>config-forceCreate</code></td>
+      <td>This boolean attribute is only evaluated for configurations declared as
+      optional. It determines the behavior of the configuration builder when
+      the optional configuration could not be created. If set to <b>true</b>,
+      the builder tries to create an empty, uninitialized configuration of the
+      correct type and add it to the resulting combined configuration. This is
+      especially useful for file-based configurations. Consider a use case
+      where an application wants to store user specific configuration files in
+      the users' home directories. When a user starts this application for the
+      first time, the user configuration does not exist yet. If it is declared
+      as <em>optional</em> and <em>forceCreate</em>, the missing configuration
+      file won't cause an error, but an empty configuration will be created.
+      The application can then obtain this configuration, add properties to it
+      (e.g. user specific settings) and save it. Without the
+      <code>config-forceCreate</code> attribute the application would have to
+      check whether the user configuration exists in the combined configuration
+      and eventually create it manually. Note that not all configuration
+      providers support this mechanism. Sometimes it may not be possible to
+      create an empty configuration if the standard initialization fails. In
+      this case no configuration will be added to the combined configuration
+      (with other words: the <code>config-forceCreate</code> attribute will not
+      have any effect).</td>
     </tr>
     </table>
     </p>



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org