Author: oheger
Date: Thu Jun  8 13:11:29 2006
New Revision: 412848

URL: http://svn.apache.org/viewvc?rev=412848&view=rev
Log:
Enabled support for variable interpolation in DefaultConfigurationBuilder

Modified:
    
jakarta/commons/proper/configuration/trunk/conf/testComplexInitialization.xml
    
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/DefaultConfigurationBuilder.java
    
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
    
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/SubnodeConfiguration.java
    
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/beanutils/XMLBeanDeclaration.java
    
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestDefaultConfigurationBuilder.java
    
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/beanutils/TestXMLBeanDeclaration.java
    
jakarta/commons/proper/configuration/trunk/xdocs/howto_configurationbuilder.xml

Modified: 
jakarta/commons/proper/configuration/trunk/conf/testComplexInitialization.xml
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/conf/testComplexInitialization.xml?rev=412848&r1=412847&r2=412848&view=diff
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/conf/testComplexInitialization.xml 
(original)
+++ 
jakarta/commons/proper/configuration/trunk/conf/testComplexInitialization.xml 
Thu Jun  8 13:11:29 2006
@@ -15,17 +15,19 @@
       </override>
     </combiner>
   </header>
+  <system/>
   <properties fileName="test.properties" throwExceptionOnMissing="true"
     config-name="properties">
     <reloadingStrategy 
config-class="org.apache.commons.configuration.reloading.FileChangedReloadingStrategy"
       refreshDelay="10000"/>
   </properties>
-  <xml fileName="test.xml" config-name="xml">
+  <!-- Fetch the file name from a variable -->
+  <xml fileName="${test_file_xml}" config-name="xml">
     <expressionEngine 
config-class="org.apache.commons.configuration.tree.DefaultExpressionEngine"
       propertyDelimiter="/" indexStart="[" indexEnd="]"/>
   </xml>
   <additional>
-    <xml config-name="combiner1" fileName="testcombine1.xml"/>
+    <xml config-name="combiner1" fileName="${test_file_combine}"/>  -->
     <xml config-name="combiner2" fileName="testcombine2.xml"/>
   </additional>
 </configuration>

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?rev=412848&r1=412847&r2=412848&view=diff
==============================================================================
--- 
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
 Thu Jun  8 13:11:29 2006
@@ -30,6 +30,7 @@
 import org.apache.commons.configuration.plist.PropertyListConfiguration;
 import org.apache.commons.configuration.plist.XMLPropertyListConfiguration;
 import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.configuration.tree.DefaultExpressionEngine;
 import org.apache.commons.configuration.tree.OverrideCombiner;
 import org.apache.commons.configuration.tree.UnionCombiner;
 import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
@@ -152,6 +153,11 @@
  * configuration under the name defined by the <code>ADDITIONAL_NAME</code>
  * constant.
  * </p>
+ * <p>
+ * Implementation note: This class is not thread-safe. Especially the
+ * <code>getConfiguration()</code> methods should be called by a single thread
+ * only.
+ * </p>
  *
  * @since 1.3
  * @author Oliver Heger
@@ -180,16 +186,40 @@
             + ".CONFIG_BEAN_FACTORY_NAME";
 
     /** Constant for the reserved name attribute. */
-    static final String ATTR_NAME = XMLBeanDeclaration.RESERVED_PREFIX + 
"name";
+    static final String ATTR_NAME = 
DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+            + XMLBeanDeclaration.RESERVED_PREFIX
+            + "name"
+            + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
+
+    /** Constant for the name of the at attribute. */
+    static final String ATTR_ATNAME = "at";
 
     /** Constant for the reserved at attribute. */
-    static final String ATTR_AT = "at";
+    static final String ATTR_AT_RES = 
DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+            + XMLBeanDeclaration.RESERVED_PREFIX
+            + ATTR_ATNAME
+            + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
+
+    /** Constant for the at attribute without the reserved prefix. */
+    static final String ATTR_AT = 
DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+            + ATTR_ATNAME + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
+
+    /** Constant for the name of the optional attribute. */
+    static final String ATTR_OPTIONALNAME = "optional";
 
     /** Constant for the reserved optional attribute. */
-    static final String ATTR_OPTIONAL = "optional";
+    static final String ATTR_OPTIONAL_RES = 
DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+            + XMLBeanDeclaration.RESERVED_PREFIX
+            + ATTR_OPTIONALNAME
+            + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
+
+    /** Constant for the optional attribute without the reserved prefix. */
+    static final String ATTR_OPTIONAL = 
DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+            + ATTR_OPTIONALNAME + 
DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
 
     /** Constant for the file name attribute. */
-    static final String ATTR_FILENAME = "fileName";
+    static final String ATTR_FILENAME = 
DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START
+            + "fileName" + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END;
 
     /** Constant for the name of the header section. */
     static final String SEC_HEADER = "header";
@@ -268,6 +298,9 @@
     { PROPERTIES_PROVIDER, XML_PROVIDER, XML_PROVIDER, JNDI_PROVIDER,
             SYSTEM_PROVIDER, PLIST_PROVIDER, BUILDER_PROVIDER };
 
+    /** Stores the configuration that is currently constructed.*/
+    private CombinedConfiguration constructedConfiguration;
+
     /** Stores a map with the registered configuration providers. */
     private Map providers;
 
@@ -436,15 +469,21 @@
             load();
         }
 
-        CombinedConfiguration result = createOverrideConfiguration();
+        CombinedConfiguration result = createResultConfiguration();
+        constructedConfiguration = result;
+
+        List overrides = configurationsAt(KEY_OVERRIDE1);
+        overrides.addAll(configurationsAt(KEY_OVERRIDE2));
+        initCombinedConfiguration(result, overrides, KEY_OVERRIDE_LIST);
+
         List additionals = configurationsAt(KEY_UNION);
         if (!additionals.isEmpty())
         {
             CombinedConfiguration addConfig = new CombinedConfiguration(
                     new UnionCombiner());
+            result.addConfiguration(addConfig, ADDITIONAL_NAME);
             initCombinedConfiguration(addConfig, additionals,
                     KEY_ADDITIONAL_LIST);
-            result.addConfiguration(addConfig, ADDITIONAL_NAME);
         }
 
         return result;
@@ -452,18 +491,16 @@
 
     /**
      * Creates the resulting combined configuration. This method is called by
-     * <code>getConfiguration()</code>. Its task is to construct the
-     * resulting (override) combined configuration and to add all declared
-     * override configurations to it. This implementation checks whether the
+     * <code>getConfiguration()</code>. It checks whether the
      * <code>header</code> section of the configuration definition file
      * contains a <code>result</code> element. If this is the case, it will be
      * used to initialize the properties of the newly created configuration
      * object.
      *
-     * @return the override configuration object
+     * @return the resulting configuration object
      * @throws ConfigurationException if an error occurs
      */
-    protected CombinedConfiguration createOverrideConfiguration()
+    protected CombinedConfiguration createResultConfiguration()
             throws ConfigurationException
     {
         XMLBeanDeclaration decl = new XMLBeanDeclaration(this, KEY_RESULT, 
true);
@@ -476,9 +513,6 @@
             result.setNodeCombiner(new OverrideCombiner());
         }
 
-        List overrides = configurationsAt(KEY_OVERRIDE1);
-        overrides.addAll(configurationsAt(KEY_OVERRIDE2));
-        initCombinedConfiguration(result, overrides, KEY_OVERRIDE_LIST);
         return result;
     }
 
@@ -491,11 +525,11 @@
      * @param containedConfigs the list with the declaratinos of the contained
      * configurations
      * @param keyListNodes a list with the declaration of list nodes
+     * @param interpolConfig the configuration to be used for interpolation
      * @throws ConfigurationException if an error occurs
      */
     protected void initCombinedConfiguration(CombinedConfiguration config,
-            List containedConfigs, String keyListNodes)
-            throws ConfigurationException
+            List containedConfigs, String keyListNodes) throws 
ConfigurationException
     {
         List listNodes = getList(keyListNodes);
         for (Iterator it = listNodes.iterator(); it.hasNext();)
@@ -512,8 +546,8 @@
             AbstractConfiguration newConf = createConfigurationAt(decl);
             if (newConf != null)
             {
-                config.addConfiguration(newConf, decl
-                        .attributeValueStr(ATTR_NAME), decl.getAt());
+                config.addConfiguration(newConf, decl.getConfiguration()
+                        .getString(ATTR_NAME), decl.getAt());
             }
         }
     }
@@ -532,6 +566,26 @@
     }
 
     /**
+     * Performs interpolation. This method will not only take this 
configuration
+     * instance into account (which is the one that loaded the configuration
+     * definition file), but also the so far constructed combined 
configuration.
+     * So variables can be used that point to properties that are defined in
+     * configuration sources loaded by this builder.
+     *
+     * @param value the value to be interpolated
+     * @return the interpolated value
+     */
+    protected Object interpolate(Object value)
+    {
+        Object result = super.interpolate(value);
+        if (constructedConfiguration != null)
+        {
+            result = constructedConfiguration.interpolate(result);
+        }
+        return result;
+    }
+
+    /**
      * Creates a configuration object from the specified configuration
      * declaration.
      *
@@ -654,15 +708,16 @@
      */
     protected static class ConfigurationDeclaration extends XMLBeanDeclaration
     {
-        /** Stores a reference to the associated configuration factory. */
+        /** Stores a reference to the associated configuration builder. */
         private DefaultConfigurationBuilder configurationBuilder;
 
         /**
          * Creates a new instance of <code>ConfigurationDeclaration</code> and
          * initializes it.
          *
-         * @param buikder the associated configuration builder
+         * @param builder the associated configuration builder
          * @param config the configuration this declaration is based onto
+         * @param interpolConfig the configuration to be used for interpolation
          */
         public ConfigurationDeclaration(DefaultConfigurationBuilder builder,
                 HierarchicalConfiguration config)
@@ -688,8 +743,9 @@
          */
         public String getAt()
         {
-            String result = attributeValueStr(RESERVED_PREFIX + ATTR_AT);
-            return (result == null) ? attributeValueStr(ATTR_AT) : result;
+            String result = getConfiguration().getString(ATTR_AT_RES);
+            return (result == null) ? getConfiguration().getString(ATTR_AT)
+                    : result;
         }
 
         /**
@@ -700,23 +756,14 @@
          */
         public boolean isOptional()
         {
-            Object value = attributeValue(RESERVED_PREFIX + ATTR_OPTIONAL);
+            Boolean value = getConfiguration().getBoolean(ATTR_OPTIONAL_RES,
+                    null);
             if (value == null)
             {
-                value = attributeValue(ATTR_OPTIONAL);
-            }
-
-            try
-            {
-                return (value != null) ? PropertyConverter.toBoolean(value)
-                        .booleanValue() : false;
-            }
-            catch (ConversionException cex)
-            {
-                throw new ConfigurationRuntimeException(
-                        "optional attribute does not have a valid boolean 
value",
-                        cex);
+                value = getConfiguration().getBoolean(ATTR_OPTIONAL,
+                        Boolean.FALSE);
             }
+            return value.booleanValue();
         }
 
         /**
@@ -743,29 +790,6 @@
         }
 
         /**
-         * Returns the value of the specified attribute. This can be useful for
-         * certain <code>ConfigurationProvider</code> implementations.
-         *
-         * @param attrName the attribute's name
-         * @return the attribute's value (or <b>null</b> if it does not exist)
-         */
-        public Object attributeValue(String attrName)
-        {
-            return super.attributeValue(attrName);
-        }
-
-        /**
-         * Returns the string value of the specified attribute.
-         *
-         * @param attrName the attribute's name
-         * @return the attribute's value (or <b>null</b> if it does not exist)
-         */
-        public String attributeValueStr(String attrName)
-        {
-            return super.attributeValueStr(attrName);
-        }
-
-        /**
          * Checks whether the given node is reserved. This method will take
          * further reserved attributes into account
          *
@@ -780,10 +804,23 @@
             }
 
             return nd.isAttribute()
-                    && ((ATTR_AT.equals(nd.getName()) && nd.getParentNode()
-                            .getAttributeCount(RESERVED_PREFIX + ATTR_AT) == 
0) || (ATTR_OPTIONAL
+                    && ((ATTR_ATNAME.equals(nd.getName()) && nd.getParentNode()
+                            .getAttributeCount(RESERVED_PREFIX + ATTR_ATNAME) 
== 0) || (ATTR_OPTIONALNAME
                             .equals(nd.getName()) && nd.getParentNode()
-                            .getAttributeCount(RESERVED_PREFIX + 
ATTR_OPTIONAL) == 0));
+                            .getAttributeCount(RESERVED_PREFIX + 
ATTR_OPTIONALNAME) == 0));
+        }
+
+        /**
+         * Performs interpolation. This implementation will delegate
+         * interpolation to the configuration builder, which takes care that 
the
+         * currently constructed configuration is taken into account, too.
+         *
+         * @param value the value to be interpolated
+         * @return the interpolated value
+         */
+        protected Object interpolate(Object value)
+        {
+            return getConfigurationBuilder().interpolate(value);
         }
     }
 
@@ -971,7 +1008,7 @@
                 BeanDeclaration data) throws Exception
         {
             String fileName = ((ConfigurationDeclaration) data)
-                    .attributeValueStr(ATTR_FILENAME);
+                    .getConfiguration().getString(ATTR_FILENAME);
             if (fileName != null
                     && fileName.toLowerCase().trim().endsWith(fileExtension))
             {

Modified: 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java?rev=412848&r1=412847&r2=412848&view=diff
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
 (original)
+++ 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/HierarchicalConfiguration.java
 Thu Jun  8 13:11:29 2006
@@ -407,12 +407,12 @@
 
     /**
      * <p>
-     * Returns a hierarchical 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
+     * 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</code> will be thrown.
      * </p>
      * <p>
@@ -420,18 +420,17 @@
      * <code>[EMAIL PROTECTED] #subset(String)}</code> method is that
      * <code>subset()</code> supports arbitrary subsets of configuration nodes
      * while <code>configurationAt()</code> only returns a single sub tree.
-     * Actually, the object returned by this method is an instance of
-     * <code>SubnodeConfiguration</code>. Please refer to the documentation
-     * of this class to obtain further information about subnode configurations
-     * and when they should be used.
+     * Please refer to the documentation of the
+     * <code>SubnodeConfiguration</code> class to obtain further information
+     * about subnode configurations and when they should be used.
      * </p>
-     *
+     * 
      * @param key the key that selects the sub tree
      * @return a hierarchical configuration that contains this sub tree
      * @see SubnodeConfiguration
      * @since 1.3
      */
-    public HierarchicalConfiguration configurationAt(String key)
+    public SubnodeConfiguration configurationAt(String key)
     {
         List nodes = fetchNodeList(key);
         if (nodes.size() != 1)
@@ -489,7 +488,7 @@
      * @return the configuration for the given node
      * @since 1.3
      */
-    protected HierarchicalConfiguration 
createSubnodeConfiguration(ConfigurationNode node)
+    protected SubnodeConfiguration 
createSubnodeConfiguration(ConfigurationNode node)
     {
         return new SubnodeConfiguration(this, node);
     }

Modified: 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/SubnodeConfiguration.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/SubnodeConfiguration.java?rev=412848&r1=412847&r2=412848&view=diff
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/SubnodeConfiguration.java
 (original)
+++ 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/SubnodeConfiguration.java
 Thu Jun  8 13:11:29 2006
@@ -113,7 +113,7 @@
      * @param node the sub node, for which the configuration is to be created
      * @return a hierarchical configuration for this sub node
      */
-    protected HierarchicalConfiguration 
createSubnodeConfiguration(ConfigurationNode node)
+    protected SubnodeConfiguration 
createSubnodeConfiguration(ConfigurationNode node)
     {
         return new SubnodeConfiguration(getParent(), node);
     }

Modified: 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/beanutils/XMLBeanDeclaration.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/beanutils/XMLBeanDeclaration.java?rev=412848&r1=412847&r2=412848&view=diff
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/beanutils/XMLBeanDeclaration.java
 (original)
+++ 
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/beanutils/XMLBeanDeclaration.java
 Thu Jun  8 13:11:29 2006
@@ -17,11 +17,11 @@
 
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.configuration.HierarchicalConfiguration;
 import org.apache.commons.configuration.PropertyConverter;
+import org.apache.commons.configuration.SubnodeConfiguration;
 import org.apache.commons.configuration.tree.ConfigurationNode;
 import org.apache.commons.configuration.tree.DefaultConfigurationNode;
 
@@ -85,6 +85,16 @@
  * it can have attributes defining meta data or bean properties and even 
further
  * nested elements for complex bean properties.
  * </p>
+ * <p>
+ * A <code>XMLBeanDeclaration</code> object is usually created from a
+ * <code>HierarchicalConfiguration</code>. From this it will derive a
+ * <code>SubnodeConfiguration</code>, which is used to access the needed
+ * properties. This subnode configuration can be obtained using the
+ * <code>[EMAIL PROTECTED] #getConfiguration()}</code> method. All of its 
properties can
+ * be accessed in the usual way. To ensure that the property keys used by this
+ * class are understood by the configuration, the default expression engine 
will
+ * be set.
+ * </p>
  *
  * @since 1.3
  * @author Oliver Heger
@@ -95,18 +105,21 @@
     /** Constant for the prefix of reserved attributes. */
     public static final String RESERVED_PREFIX = "config-";
 
+    /** Constant for the prefix for reserved attributes.*/
+    private static final String ATTR_PREFIX = "[@" + RESERVED_PREFIX;
+
     /** Constant for the bean class attribute. */
-    public static final String ATTR_BEAN_CLASS = RESERVED_PREFIX + "class";
+    public static final String ATTR_BEAN_CLASS = ATTR_PREFIX + "class]";
 
     /** Constant for the bean factory attribute. */
-    public static final String ATTR_BEAN_FACTORY = RESERVED_PREFIX + "factory";
+    public static final String ATTR_BEAN_FACTORY = ATTR_PREFIX + "factory]";
 
     /** Constant for the bean factory parameter attribute. */
-    public static final String ATTR_FACTORY_PARAM = RESERVED_PREFIX
-            + "factoryParam";
+    public static final String ATTR_FACTORY_PARAM = ATTR_PREFIX
+            + "factoryParam]";
 
     /** Stores the associated configuration. */
-    private HierarchicalConfiguration configuration;
+    private SubnodeConfiguration configuration;
 
     /** Stores the configuration node that contains the bean declaration. */
     private ConfigurationNode node;
@@ -153,8 +166,8 @@
 
         try
         {
-            node = (key == null) ? config.getRoot() : config.configurationAt(
-                    key).getRoot();
+            configuration = config.configurationAt(key);
+            node = configuration.getRootNode();
         }
         catch (IllegalArgumentException iex)
         {
@@ -163,9 +176,10 @@
             {
                 throw iex;
             }
+            configuration = config.configurationAt(null);
             node = new DefaultConfigurationNode();
         }
-        configuration = config;
+        initSubnodeConfiguration(getConfiguration());
     }
 
     /**
@@ -188,7 +202,7 @@
      * @param config the configuration
      * @param node the node with the bean declaration.
      */
-    public XMLBeanDeclaration(HierarchicalConfiguration config,
+    public XMLBeanDeclaration(SubnodeConfiguration config,
             ConfigurationNode node)
     {
         if (config == null)
@@ -203,6 +217,7 @@
 
         this.node = node;
         configuration = config;
+        initSubnodeConfiguration(config);
     }
 
     /**
@@ -210,7 +225,7 @@
      *
      * @return the associated configuration
      */
-    public HierarchicalConfiguration getConfiguration()
+    public SubnodeConfiguration getConfiguration()
     {
         return configuration;
     }
@@ -233,7 +248,7 @@
      */
     public String getBeanFactoryName()
     {
-        return attributeValueStr(ATTR_BEAN_FACTORY);
+        return getConfiguration().getString(ATTR_BEAN_FACTORY);
     }
 
     /**
@@ -244,7 +259,7 @@
      */
     public Object getBeanFactoryParameter()
     {
-        return attributeValue(ATTR_FACTORY_PARAM);
+        return getConfiguration().getProperty(ATTR_FACTORY_PARAM);
     }
 
     /**
@@ -255,7 +270,7 @@
      */
     public String getBeanClassName()
     {
-        return attributeValueStr(ATTR_BEAN_CLASS);
+        return getConfiguration().getString(ATTR_BEAN_CLASS);
     }
 
     /**
@@ -272,8 +287,7 @@
             ConfigurationNode attr = (ConfigurationNode) it.next();
             if (!isReservedNode(attr))
             {
-                props.put(attr.getName(), PropertyConverter.interpolate(attr
-                        .getValue(), getConfiguration()));
+                props.put(attr.getName(), interpolate(attr .getValue()));
             }
         }
 
@@ -296,7 +310,7 @@
             if (!isReservedNode(child))
             {
                 nested.put(child.getName(), new XMLBeanDeclaration(
-                        getConfiguration(), child));
+                        getConfiguration().configurationAt(child.getName()), 
child));
             }
         }
 
@@ -304,18 +318,18 @@
     }
 
     /**
-     * Returns the value of the specified attribute node or <b>null</b> if it
-     * does not exist. If there are multiple attributes with this name, this
-     * implementation selects the first one.
-     *
-     * @param attrName the name of the attribute
-     * @return the value of this attribute
-     */
-    protected Object attributeValue(String attrName)
-    {
-        List attrs = getNode().getAttributes(attrName);
-        return attrs.isEmpty() ? null : ((ConfigurationNode) attrs.get(0))
-                .getValue();
+     * Performs interpolation for the specified value. This implementation will
+     * interpolate against the current subnode configuration's parent. If sub
+     * classes need a different interpolation mechanism, they should override
+     * this method.
+     *
+     * @param value the value that is to be interpolated
+     * @return the interpolated value
+     */
+    protected Object interpolate(Object value)
+    {
+        return PropertyConverter.interpolate(value, getConfiguration()
+                .getParent());
     }
 
     /**
@@ -336,15 +350,14 @@
     }
 
     /**
-     * Returns the value of the specified attribute as string. This is a
-     * convenience method.
+     * Initializes the internally managed subnode configuration. This method
+     * will set some default values for some properties.
      *
-     * @param attrName the name of the attribute
-     * @return the attribute's value as string
+     * @param conf the configuration to initialize
      */
-    protected String attributeValueStr(String attrName)
+    private void initSubnodeConfiguration(SubnodeConfiguration conf)
     {
-        Object value = attributeValue(attrName);
-        return (value != null) ? value.toString() : null;
+        conf.setThrowExceptionOnMissing(false);
+        conf.setExpressionEngine(null);
     }
 }

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?rev=412848&r1=412847&r2=412848&view=diff
==============================================================================
--- 
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
 Thu Jun  8 13:11:29 2006
@@ -20,7 +20,6 @@
 import java.util.Set;
 
 import org.apache.commons.configuration.beanutils.BeanHelper;
-import org.apache.commons.configuration.beanutils.XMLBeanDeclaration;
 import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
 import org.apache.commons.configuration.tree.DefaultConfigurationNode;
 import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
@@ -64,6 +63,8 @@
         System
                 .setProperty("java.naming.factory.initial",
                         
"org.apache.commons.configuration.MockStaticMemoryInitialContextFactory");
+        System.setProperty("test_file_xml", "test.xml");
+        System.setProperty("test_file_combine", "testcombine1.xml");
         factory = new DefaultConfigurationBuilder();
     }
 
@@ -81,7 +82,7 @@
         nd = new DefaultConfigurationNode("optional");
         parent.addAttribute(nd);
         assertTrue("Attribute optional not recognized", 
decl.isReservedNode(nd));
-        nd = new DefaultConfigurationNode(XMLBeanDeclaration.ATTR_BEAN_CLASS);
+        nd = new DefaultConfigurationNode("config-class");
         parent.addAttribute(nd);
         assertTrue("Inherited attribute not recognized", decl
                 .isReservedNode(nd));
@@ -502,8 +503,10 @@
         CombinedConfiguration cc = (CombinedConfiguration) factory
                 .getConfiguration();
 
+        assertEquals("System property not found", "test.xml",
+                cc.getString("test_file_xml"));
         PropertiesConfiguration c1 = (PropertiesConfiguration) cc
-                .getConfiguration(0);
+                .getConfiguration(1);
         assertTrue(
                 "Reloading strategy was not set",
                 c1.getReloadingStrategy() instanceof 
FileChangedReloadingStrategy);
@@ -516,6 +519,8 @@
                 .getString("element2/subelement/subsubelement"));
         assertEquals("List index not found", "two", xmlConf
                 .getString("list[0]/item[1]"));
+        assertEquals("Property in combiner file not found", "yellow", cc
+                .getString("/gui/selcolor"));
 
         assertTrue("Delimiter flag was not set", cc
                 .isDelimiterParsingDisabled());
@@ -534,7 +539,7 @@
         assertNotNull("Properties configuration not found", cc
                 .getConfiguration("properties"));
         assertNotNull("XML configuration not found", 
cc.getConfiguration("xml"));
-        assertEquals("Wrong number of contained configs", 3, cc
+        assertEquals("Wrong number of contained configs", 4, cc
                 .getNumberOfConfigurations());
 
         CombinedConfiguration cc2 = (CombinedConfiguration) cc

Modified: 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/beanutils/TestXMLBeanDeclaration.java
URL: 
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/beanutils/TestXMLBeanDeclaration.java?rev=412848&r1=412847&r2=412848&view=diff
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/beanutils/TestXMLBeanDeclaration.java
 (original)
+++ 
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/beanutils/TestXMLBeanDeclaration.java
 Thu Jun  8 13:11:29 2006
@@ -77,7 +77,7 @@
     {
         try
         {
-            decl = new XMLBeanDeclaration(new HierarchicalConfiguration(),
+            decl = new XMLBeanDeclaration(new 
HierarchicalConfiguration().configurationAt(null),
                     (ConfigurationNode) null);
             fail("Could init declaration with null node!");
         }

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?rev=412848&r1=412847&r2=412848&view=diff
==============================================================================
--- 
jakarta/commons/proper/configuration/trunk/xdocs/howto_configurationbuilder.xml 
(original)
+++ 
jakarta/commons/proper/configuration/trunk/xdocs/howto_configurationbuilder.xml 
Thu Jun  8 13:11:29 2006
@@ -231,6 +231,29 @@
       <code>additional</code> section).
     </p>
     <p>
+      Another useful feature is the built-in support for interpolation (i.e.
+      variable substitution): You can use variables in your configuration
+      definition file that are defined in declared configuration sources. For
+      instance, if the name of a configuration file to be loaded is defined by
+      the system property <code>CONFIG_FILE</code>, you can do something like
+      this:
+    </p>
+    <source><![CDATA[
+<configuration>
+  <!-- Load the system properties -->
+  <system/>
+  <!-- Now load the config file, using a system property as file name -->
+  <properties fileName="${CONFIG_FILE}"/>
+</configuration>
+]]></source>
+    <p>
+      Note that you can refer only to properties that have already been loaded.
+      If you change the order of the <code>&lt;system&gt;</code> and the
+      <code>&lt;properties&gt;</code> elements in the example above, an error
+      will occur because the <code>${CONFIG_FILE}</code> variable will then be
+      undefined at the moment it is evaluated.
+    </p>
+    <p>
       <strong>The header section</strong>
     </p>
     <p>



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to