commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ohe...@apache.org
Subject svn commit: r635081 [2/2] - in /commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2: AbstractHierarchicalConfiguration.java InMemoryConfiguration.java SubConfiguration.java
Date Sat, 08 Mar 2008 20:42:33 GMT
Copied: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/InMemoryConfiguration.java (from r632835, commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/HierarchicalConfiguration.java)
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/InMemoryConfiguration.java?p2=commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/InMemoryConfiguration.java&p1=commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/HierarchicalConfiguration.java&r1=632835&r2=635081&rev=635081&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/HierarchicalConfiguration.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/InMemoryConfiguration.java Sat Mar  8 12:42:32 2008
@@ -17,26 +17,20 @@
 
 package org.apache.commons.configuration2;
 
-import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
 import java.util.Stack;
 
-import org.apache.commons.configuration2.event.ConfigurationEvent;
-import org.apache.commons.configuration2.event.ConfigurationListener;
+import org.apache.commons.configuration2.expr.ConfigurationNodeHandler;
+import org.apache.commons.configuration2.expr.NodeAddData;
+import org.apache.commons.configuration2.expr.NodeHandler;
+import org.apache.commons.configuration2.expr.NodeList;
+import org.apache.commons.configuration2.expr.NodeVisitor;
+import org.apache.commons.configuration2.expr.NodeVisitorAdapter;
 import org.apache.commons.configuration2.tree.ConfigurationNode;
-import org.apache.commons.configuration2.tree.ConfigurationNodeVisitor;
-import org.apache.commons.configuration2.tree.ConfigurationNodeVisitorAdapter;
 import org.apache.commons.configuration2.tree.DefaultConfigurationNode;
-import org.apache.commons.configuration2.tree.DefaultExpressionEngine;
-import org.apache.commons.configuration2.tree.ExpressionEngine;
-import org.apache.commons.configuration2.tree.NodeAddData;
 
 /**
  * <p>A specialized configuration class that extends its base class by the
@@ -123,66 +117,43 @@
  * synchronization has to be performed manually.</p>
  *
  * @author Oliver Heger
+ * @since 2.0
  * @version $Id$
  */
-public class HierarchicalConfiguration extends AbstractConfiguration implements Serializable, Cloneable
+public class InMemoryConfiguration extends AbstractHierarchicalConfiguration<ConfigurationNode> implements Cloneable
 {
     /**
-     * Constant for the clear tree event.
-     * @since 1.3
-     */
-    public static final int EVENT_CLEAR_TREE = 10;
-
-    /**
      * Constant for the add nodes event.
-     * @since 1.3
      */
     public static final int EVENT_ADD_NODES = 11;
 
-    /**
-     * Constant for the subnode configuration modified event.
-     * @since 1.5
-     */
-    public static final int EVENT_SUBNODE_CHANGED = 12;
-
-    /**
-     * The serial version UID.
-     */
-    private static final long serialVersionUID = 3373812230395363192L;
-
-    /** Stores the default expression engine to be used for new objects.*/
-    private static ExpressionEngine defaultExpressionEngine;
-
     /** Stores the root configuration node.*/
     private ConfigurationNode rootNode;
 
-    /** Stores the expression engine for this instance.*/
-    private transient ExpressionEngine expressionEngine;
-
     /**
-     * Creates a new instance of <code>HierarchicalConfiguration</code>.
+     * Creates a new instance of <code>InMemoryConfiguration</code>.
      */
-    public HierarchicalConfiguration()
+    public InMemoryConfiguration()
     {
+        super(new ConfigurationNodeHandler());
         setRootNode(new DefaultConfigurationNode());
     }
 
     /**
-     * Creates a new instance of <code>HierarchicalConfiguration</code> and
+     * Creates a new instance of <code>InMemoryConfiguration</code> and
      * copies all data contained in the specified configuration into the new
      * one.
      *
      * @param c the configuration that is to be copied (if <b>null</b>, this
      * constructor will behave like the standard constructor)
-     * @since 1.4
      */
-    public HierarchicalConfiguration(HierarchicalConfiguration c)
+    public InMemoryConfiguration(InMemoryConfiguration c)
     {
         this();
         if (c != null)
         {
             CloneVisitor visitor = new CloneVisitor();
-            c.getRootNode().visit(visitor);
+            visit(c.getRootNode(), visitor);
             setRootNode(visitor.getClone());
         }
     }
@@ -191,8 +162,8 @@
      * Returns the root node of this hierarchical configuration.
      *
      * @return the root node
-     * @since 1.3
      */
+    @Override
     public ConfigurationNode getRootNode()
     {
         return rootNode;
@@ -202,7 +173,6 @@
      * Sets the root node of this hierarchical configuration.
      *
      * @param rootNode the root node
-     * @since 1.3
      */
     public void setRootNode(ConfigurationNode rootNode)
     {
@@ -214,119 +184,6 @@
     }
 
     /**
-     * Returns the default expression engine.
-     *
-     * @return the default expression engine
-     * @since 1.3
-     */
-    public static synchronized ExpressionEngine getDefaultExpressionEngine()
-    {
-        if (defaultExpressionEngine == null)
-        {
-            defaultExpressionEngine = new DefaultExpressionEngine();
-        }
-        return defaultExpressionEngine;
-    }
-
-    /**
-     * Sets the default expression engine. This expression engine will be used
-     * if no specific engine was set for an instance. It is shared between all
-     * hierarchical configuration instances. So modifying its properties will
-     * impact all instances, for which no specific engine is set.
-     *
-     * @param engine the new default expression engine
-     * @since 1.3
-     */
-    public static synchronized void setDefaultExpressionEngine(ExpressionEngine engine)
-    {
-        if (engine == null)
-        {
-            throw new IllegalArgumentException("Default expression engine must not be null!");
-        }
-        defaultExpressionEngine = engine;
-    }
-
-    /**
-     * Returns the expression engine used by this configuration. This method
-     * will never return <b>null</b>; if no specific expression engine was set,
-     * the default expression engine will be returned.
-     *
-     * @return the current expression engine
-     * @since 1.3
-     */
-    public ExpressionEngine getExpressionEngine()
-    {
-        return (expressionEngine != null) ? expressionEngine : getDefaultExpressionEngine();
-    }
-
-    /**
-     * Sets the expression engine to be used by this configuration. All property
-     * keys this configuration has to deal with will be interpreted by this
-     * engine.
-     *
-     * @param expressionEngine the new expression engine; can be <b>null</b>,
-     * then the default expression engine will be used
-     * @since 1.3
-     */
-    public void setExpressionEngine(ExpressionEngine expressionEngine)
-    {
-        this.expressionEngine = expressionEngine;
-    }
-
-    /**
-     * Fetches the specified property. This task is delegated to the associated
-     * expression engine.
-     *
-     * @param key the key to be looked up
-     * @return the found value
-     */
-    public Object getProperty(String key)
-    {
-        List<ConfigurationNode> nodes = fetchNodeList(key);
-
-        if (nodes.size() == 0)
-        {
-            return null;
-        }
-        else
-        {
-            List<Object> list = new ArrayList<Object>();
-            for (ConfigurationNode node : nodes)
-            {
-                if (node.getValue() != null)
-                {
-                    list.add(node.getValue());
-                }
-            }
-
-            if (list.size() < 1)
-            {
-                return null;
-            }
-            else
-            {
-                return (list.size() == 1) ? list.get(0) : list;
-            }
-        }
-    }
-
-    /**
-     * Adds the property with the specified key. This task will be delegated to
-     * the associated <code>ExpressionEngine</code>, so the passed in key
-     * must match the requirements of this implementation.
-     *
-     * @param key the key of the new property
-     * @param obj the value of the new property
-     */
-    @Override
-    protected void addPropertyDirect(String key, Object obj)
-    {
-        NodeAddData data = getExpressionEngine().prepareAdd(getRootNode(), key);
-        ConfigurationNode node = processNodeAddData(data);
-        node.setValue(obj);
-    }
-
-    /**
      * Adds a collection of nodes at the specified position of the configuration
      * tree. This method works similar to <code>addProperty()</code>, but
      * instead of a single property a whole collection of nodes can be added -
@@ -346,6 +203,7 @@
      * then they are added to the root node
      * @param nodes a collection with the <code>Node</code> objects to be
      * added
+     * @throws IllegalArgumentException if the key specifies an attribute
      */
     public void addNodes(String key, Collection<? extends ConfigurationNode> nodes)
     {
@@ -356,28 +214,32 @@
 
         fireEvent(EVENT_ADD_NODES, key, nodes, true);
         ConfigurationNode parent;
-        List<ConfigurationNode> target = fetchNodeList(key);
+        NodeList<ConfigurationNode> target = fetchNodeList(key);
         if (target.size() == 1)
         {
             // existing unique key
-            parent = target.get(0);
+            parent = target.getNode(0);
         }
         else
         {
             // otherwise perform an add operation
-            parent = processNodeAddData(getExpressionEngine().prepareAdd(getRootNode(), key));
-        }
-
-        if (parent.isAttribute())
-        {
-            throw new IllegalArgumentException("Cannot add nodes to an attribute node!");
+            NodeAddData<ConfigurationNode> addData = getExpressionEngine()
+                    .prepareAdd(getRootNode(), key, getNodeHandler());
+            if (addData.isAttribute())
+            {
+                throw new IllegalArgumentException(
+                        "Cannot add nodes to an attribute node!");
+            }
+            parent = processNodeAddData(addData, null);
         }
 
         // a visitor to ensure that the nodes' references are cleared; this is
         // necessary if the nodes are moved from another configuration
-        ConfigurationNodeVisitor clearRefVisitor = new ConfigurationNodeVisitorAdapter()
+        NodeVisitor<ConfigurationNode> clearRefVisitor = new NodeVisitorAdapter<ConfigurationNode>()
         {
-            public void visitBeforeChildren(ConfigurationNode node)
+            @Override
+            public void visitBeforeChildren(ConfigurationNode node,
+                    NodeHandler<ConfigurationNode> handler)
             {
                 node.setReference(null);
             }
@@ -393,26 +255,15 @@
             {
                 parent.addChild(child);
             }
-            child.visit(clearRefVisitor);
+            visit(child, clearRefVisitor);
         }
         fireEvent(EVENT_ADD_NODES, key, nodes, false);
     }
 
     /**
-     * Checks if this configuration is empty. Empty means that there are no keys
-     * with any values, though there can be some (empty) nodes.
-     *
-     * @return a flag if this configuration is empty
-     */
-    public boolean isEmpty()
-    {
-        return !nodeDefined(getRootNode());
-    }
-
-    /**
      * Creates a new <code>Configuration</code> object containing all keys
-     * that start with the specified prefix. This implementation will return a
-     * <code>HierarchicalConfiguration</code> object so that the structure of
+     * that start with the specified prefix. This implementation will return an
+     * <code>InMemoryConfiguration</code> object so that the structure of
      * the keys will be saved. The nodes selected by the prefix (it is possible
      * that multiple nodes are selected) are mapped to the root node of the
      * returned configuration, i.e. their children and attributes will become
@@ -431,16 +282,17 @@
     @SuppressWarnings("serial")
     public Configuration subset(String prefix)
     {
-        Collection<ConfigurationNode> nodes = fetchNodeList(prefix);
-        if (nodes.isEmpty())
+        NodeList<ConfigurationNode> nodes = fetchNodeList(prefix);
+        if (nodes.size() < 1)
         {
-            return new HierarchicalConfiguration();
+            return new InMemoryConfiguration();
         }
 
-        final HierarchicalConfiguration parent = this;
-        HierarchicalConfiguration result = new HierarchicalConfiguration()
+        final InMemoryConfiguration parent = this;
+        InMemoryConfiguration result = new InMemoryConfiguration()
         {
             // Override interpolate to always interpolate on the parent
+            @Override
             protected Object interpolate(Object value)
             {
                 return parent.interpolate(value);
@@ -451,22 +303,34 @@
         // Initialize the new root node
         Object value = null;
         int valueCount = 0;
-        for (ConfigurationNode nd : nodes)
+        for (int index = 0; index < nodes.size(); index++)
         {
-            if (nd.getValue() != null)
+            Object v = nodes.getValue(index, getNodeHandler());
+            if (v != null)
             {
-                value = nd.getValue();
+                value = v;
                 valueCount++;
             }
-            nd.visit(visitor);
 
-            for (ConfigurationNode child : visitor.getClone().getChildren())
+            if (nodes.isAttribute(index))
             {
-                result.getRootNode().addChild(child);
+                getNodeHandler().setAttributeValue(result.getRootNode(),
+                        nodes.getName(index, getNodeHandler()),
+                        nodes.getValue(index, getNodeHandler()));
             }
-            for (ConfigurationNode attr : visitor.getClone().getAttributes())
+
+            else
             {
-                result.getRootNode().addAttribute(attr);
+                visit(nodes.getNode(index), visitor);
+                for (ConfigurationNode child : visitor.getClone().getChildren())
+                {
+                    result.getRootNode().addChild(child);
+                }
+                for (ConfigurationNode attr : visitor.getClone()
+                        .getAttributes())
+                {
+                    result.getRootNode().addAttribute(attr);
+                }
             }
         }
 
@@ -479,356 +343,22 @@
     }
 
     /**
-     * <p>
-     * 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>
-     * The difference between this method and the
-     * <code>{@link #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.
-     * 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>
-     * <p>
-     * With the <code>supportUpdate</code> flag the behavior of the returned
-     * <code>SubnodeConfiguration</code> regarding updates of its parent
-     * configuration can be determined. A subnode configuration operates on the
-     * same nodes as its parent, so changes at one configuration are normally
-     * directly visible for the other configuration. There are however changes
-     * of the parent configuration, which are not recognized by the subnode
-     * configuration per default. An example for this is a reload operation (for
-     * file-based configurations): Here the complete node set of the parent
-     * configuration is replaced, but the subnode configuration still references
-     * the old nodes. If such changes should be detected by the subnode
-     * configuration, the <code>supportUpdates</code> flag must be set to
-     * <b>true</b>. This causes the subnode configuration to reevaluate the key
-     * used for its creation each time it is accessed. This guarantees that the
-     * subnode configuration always stays in sync with its key, even if the
-     * parent configuration's data significantly changes. If such a change
-     * makes the key invalid - because it now no longer points to exactly one
-     * node -, the subnode configuration is not reconstructed, but keeps its
-     * old data. It is then quasi detached from its parent.
-     * </p>
-     *
-     * @param key the key that selects the sub tree
-     * @param supportUpdates a flag whether the returned subnode configuration
-     * should be able to handle updates of its parent
-     * @return a hierarchical configuration that contains this sub tree
-     * @see SubnodeConfiguration
-     * @since 1.5
-     */
-    public SubnodeConfiguration configurationAt(String key, boolean supportUpdates)
-    {
-        List<ConfigurationNode> nodes = fetchNodeList(key);
-        if (nodes.size() != 1)
-        {
-            throw new IllegalArgumentException("Passed in key must select exactly one node: " + key);
-        }
-        return supportUpdates ? createSubnodeConfiguration(nodes.get(0), key) : createSubnodeConfiguration(nodes.get(0));
-    }
-
-    /**
-     * Returns a hierarchical subnode configuration for the node specified by
-     * the given key. This is a short form for <code>configurationAt(key,
-     * <b>false</b>)</code>.
-     * 
-     * @param key the key that selects the sub tree
-     * @return a hierarchical configuration that contains this sub tree
-     * @see SubnodeConfiguration
-     * @since 1.3
-     */
-    public SubnodeConfiguration configurationAt(String key)
-    {
-        return configurationAt(key, false);
-    }
-
-    /**
-     * Returns a list of sub configurations for all configuration nodes selected
-     * by the given key. This method will evaluate the passed in key (using the
-     * current <code>ExpressionEngine</code>) and then create a subnode
-     * configuration for each returned node (like
-     * <code>{@link #configurationAt(String)}</code>}). This is especially
-     * useful when dealing with list-like structures. As an example consider the
-     * configuration that contains data about database tables and their fields.
-     * If you need access to all fields of a certain table, you can simply do
-     *
-     * <pre>
-     * List fields = config.configurationsAt("tables.table(0).fields.field");
-     * for(Iterator it = fields.iterator(); it.hasNext();)
-     * {
-     *     HierarchicalConfiguration sub = (HierarchicalConfiguration) it.next();
-     *     // now the children and attributes of the field node can be
-     *     // directly accessed
-     *     String fieldName = sub.getString("name");
-     *     String fieldType = sub.getString("type");
-     *     ...
-     * </pre>
-     *
-     * @param key the key for selecting the desired nodes
-     * @return a list with hierarchical configuration objects; each
-     * configuration represents one of the nodes selected by the passed in key
-     * @since 1.3
-     */
-    public List<HierarchicalConfiguration> configurationsAt(String key)
-    {
-        List<ConfigurationNode> nodes = fetchNodeList(key);
-        List<HierarchicalConfiguration> configs = new ArrayList<HierarchicalConfiguration>(nodes.size());
-        for (ConfigurationNode node : nodes)
-        {
-            configs.add(createSubnodeConfiguration(node));
-        }
-        return configs;
-    }
-
-    /**
-     * Creates a subnode configuration for the specified node. This method is
-     * called by <code>configurationAt()</code> and
-     * <code>configurationsAt()</code>.
-     *
-     * @param node the node, for which a subnode configuration is to be created
-     * @return the configuration for the given node
-     * @since 1.3
-     */
-    protected SubnodeConfiguration createSubnodeConfiguration(ConfigurationNode node)
-    {
-        SubnodeConfiguration result = new SubnodeConfiguration(this, node);
-        registerSubnodeConfiguration(result);
-        return result;
-    }
-
-    /**
-     * Creates a new subnode configuration for the specified node and sets its
-     * construction key. A subnode configuration created this way will be aware
-     * of structural changes of its parent.
-     *
-     * @param node the node, for which a subnode configuration is to be created
-     * @param subnodeKey the key used to construct the configuration
-     * @return the configuration for the given node
-     * @since 1.5
-     */
-    protected SubnodeConfiguration createSubnodeConfiguration(ConfigurationNode node, String subnodeKey)
-    {
-        SubnodeConfiguration result = createSubnodeConfiguration(node);
-        result.setSubnodeKey(subnodeKey);
-        return result;
-    }
-
-    /**
-     * This method is always called when a subnode configuration created from
-     * this configuration has been modified. This implementation transforms the
-     * received event into an event of type <code>EVENT_SUBNODE_CHANGED</code>
-     * and notifies the registered listeners.
-     *
-     * @param event the event describing the change
-     * @since 1.5
-     */
-    protected void subnodeConfigurationChanged(ConfigurationEvent event)
-    {
-        fireEvent(EVENT_SUBNODE_CHANGED, null, event, event.isBeforeUpdate());
-    }
-
-    /**
-     * Registers this instance at the given subnode configuration. This
-     * implementation will register a change listener, so that modifications of
-     * the subnode configuration can be tracked.
-     *
-     * @param config the subnode configuration
-     * @since 1.5
-     */
-    void registerSubnodeConfiguration(SubnodeConfiguration config)
-    {
-        config.addConfigurationListener(new ConfigurationListener()
-        {
-            public void configurationChanged(ConfigurationEvent event)
-            {
-                subnodeConfigurationChanged(event);
-            }
-        });
-    }
-
-    /**
-     * Checks if the specified key is contained in this configuration. Note that
-     * for this configuration the term &quot;contained&quot; means that the key
-     * has an associated value. If there is a node for this key that has no
-     * value but children (either defined or undefined), this method will still
-     * return <b>false </b>.
-     *
-     * @param key the key to be checked
-     * @return a flag if this key is contained in this configuration
-     */
-    public boolean containsKey(String key)
-    {
-        return getProperty(key) != null;
-    }
-
-    /**
-     * Sets the value of the specified property.
-     *
-     * @param key the key of the property to set
-     * @param value the new value of this property
-     */
-    @Override
-    public void setProperty(String key, Object value)
-    {
-        fireEvent(EVENT_SET_PROPERTY, key, value, true);
-
-        // Update the existing nodes for this property
-        Iterator<ConfigurationNode> itNodes = fetchNodeList(key).iterator();
-        Iterator<?> itValues;
-        if (!isDelimiterParsingDisabled())
-        {
-            itValues = PropertyConverter.toIterator(value, getListDelimiter());
-        }
-        else
-        {
-            itValues = Collections.singleton(value).iterator();
-        }
-
-        while (itNodes.hasNext() && itValues.hasNext())
-        {
-            itNodes.next().setValue(itValues.next());
-        }
-
-        // Add additional nodes if necessary
-        while (itValues.hasNext())
-        {
-            addPropertyDirect(key, itValues.next());
-        }
-
-        // Remove remaining nodes
-        while (itNodes.hasNext())
-        {
-            clearNode(itNodes.next());
-        }
-
-        fireEvent(EVENT_SET_PROPERTY, key, value, false);
-    }
-
-    /**
-     * Removes all values of the property with the given name and of keys that
-     * start with this name. So if there is a property with the key
-     * &quot;foo&quot; and a property with the key &quot;foo.bar&quot;, a call
-     * of <code>clearTree("foo")</code> would remove both properties.
-     *
-     * @param key the key of the property to be removed
-     */
-    public void clearTree(String key)
-    {
-        fireEvent(EVENT_CLEAR_TREE, key, null, true);
-        List<ConfigurationNode> nodes = fetchNodeList(key);
-
-        for (ConfigurationNode node : nodes)
-        {
-            removeNode(node);
-        }
-        fireEvent(EVENT_CLEAR_TREE, key, nodes, false);
-    }
-
-    /**
-     * Removes the property with the given key. Properties with names that start
-     * with the given key (i.e. properties below the specified key in the
-     * hierarchy) won't be affected.
-     *
-     * @param key the key of the property to be removed
-     */
-    @Override
-    public void clearProperty(String key)
-    {
-        fireEvent(EVENT_CLEAR_PROPERTY, key, null, true);
-        List<ConfigurationNode> nodes = fetchNodeList(key);
-
-        for (ConfigurationNode node : nodes)
-        {
-            clearNode(node);
-        }
-
-        fireEvent(EVENT_CLEAR_PROPERTY, key, null, false);
-    }
-
-    /**
-     * Returns an iterator with all keys defined in this configuration.
-     * Note that the keys returned by this method will not contain any
-     * indices. This means that some structure will be lost.</p>
-     *
-     * @return an iterator with the defined keys in this configuration
-     */
-    public Iterator<String> getKeys()
-    {
-        DefinedKeysVisitor visitor = new DefinedKeysVisitor();
-        getRootNode().visit(visitor);
-
-        return visitor.getKeyList().iterator();
-    }
-
-    /**
-     * Returns an iterator with all keys defined in this configuration that
-     * start with the given prefix. The returned keys will not contain any
-     * indices.
-     *
-     * @param prefix the prefix of the keys to start with
-     * @return an iterator with the found keys
-     */
-    @Override
-    public Iterator<String> getKeys(String prefix)
-    {
-        DefinedKeysVisitor visitor = new DefinedKeysVisitor(prefix);
-        List<ConfigurationNode> nodes = fetchNodeList(prefix);
-
-        for (ConfigurationNode node : nodes)
-        {
-            for (ConfigurationNode child : node.getChildren())
-            {
-                child.visit(visitor);
-            }
-            for (ConfigurationNode attr : node.getAttributes())
-            {
-                attr.visit(visitor);
-            }
-        }
-
-        return visitor.getKeyList().iterator();
-    }
-
-    /**
-     * Returns the maximum defined index for the given key. This is useful if
-     * there are multiple values for this key. They can then be addressed
-     * separately by specifying indices from 0 to the return value of this
-     * method.
-     *
-     * @param key the key to be checked
-     * @return the maximum defined index for this key
-     */
-    public int getMaxIndex(String key)
-    {
-        return fetchNodeList(key).size() - 1;
-    }
-
-    /**
      * Creates a copy of this object. This new configuration object will contain
      * copies of all nodes in the same structure. Registered event listeners
      * won't be cloned; so they are not registered at the returned copy.
      *
      * @return the copy
-     * @since 1.2
      */
     @Override
     public Object clone()
     {
         try
         {
-            HierarchicalConfiguration copy = (HierarchicalConfiguration) super.clone();
+            InMemoryConfiguration copy = (InMemoryConfiguration) super.clone();
 
             // clone the nodes, too
             CloneVisitor v = new CloneVisitor();
-            getRootNode().visit(v);
+            visit(getRootNode(), v);
             copy.setRootNode(v.getClone());
 
             return copy;
@@ -848,15 +378,16 @@
      * interpolation on the single configuration nodes.
      *
      * @return a configuration with all variables interpolated
-     * @since 1.5
      */
     @Override
     public Configuration interpolatedConfiguration()
     {
-        HierarchicalConfiguration c = (HierarchicalConfiguration) clone();
-        c.getRootNode().visit(new ConfigurationNodeVisitorAdapter()
+        InMemoryConfiguration c = (InMemoryConfiguration) clone();
+        visit(c.getRootNode(), new NodeVisitorAdapter<ConfigurationNode>()
         {
-            public void visitAfterChildren(ConfigurationNode node)
+            @Override
+            public void visitAfterChildren(ConfigurationNode node,
+                    NodeHandler<ConfigurationNode> handler)
             {
                 node.setValue(interpolate(node.getValue()));
             }
@@ -865,113 +396,6 @@
     }
 
     /**
-     * Helper method for fetching a list of all nodes that are addressed by the
-     * specified key.
-     *
-     * @param key the key
-     * @return a list with all affected nodes (never <b>null </b>)
-     */
-    protected List<ConfigurationNode> fetchNodeList(String key)
-    {
-        return getExpressionEngine().query(getRootNode(), key);
-    }
-
-    /**
-     * Checks if the specified node is defined.
-     *
-     * @param node the node to be checked
-     * @return a flag if this node is defined
-     */
-    protected boolean nodeDefined(ConfigurationNode node)
-    {
-        DefinedVisitor visitor = new DefinedVisitor();
-        node.visit(visitor);
-        return visitor.isDefined();
-    }
-
-    /**
-     * Removes the specified node from this configuration. This method ensures
-     * that parent nodes that become undefined by this operation are also
-     * removed.
-     *
-     * @param node the node to be removed
-     */
-    protected void removeNode(ConfigurationNode node)
-    {
-        ConfigurationNode parent = node.getParentNode();
-        if (parent != null)
-        {
-            parent.removeChild(node);
-            if (!nodeDefined(parent))
-            {
-                removeNode(parent);
-            }
-        }
-    }
-
-    /**
-     * Clears the value of the specified node. If the node becomes undefined by
-     * this operation, it is removed from the hierarchy.
-     *
-     * @param node the node to be cleared
-     */
-    protected void clearNode(ConfigurationNode node)
-    {
-        node.setValue(null);
-        if (!nodeDefined(node))
-        {
-            removeNode(node);
-        }
-    }
-
-    /**
-     * Creates a new <code>Node</code> object with the specified name. This
-     * method can be overloaded in derived classes if a specific node type is
-     * needed. This base implementation always returns a new object of the
-     * <code>Node</code> class.
-     *
-     * @param name the name of the new node
-     * @return the new node
-     */
-    protected ConfigurationNode createNode(String name)
-    {
-        return new DefaultConfigurationNode(name);
-    }
-
-    /**
-     * Helper method for processing a node add data object obtained from the
-     * expression engine. This method will create all new nodes.
-     *
-     * @param data the data object
-     * @return the new node
-     * @since 1.3
-     */
-    private ConfigurationNode processNodeAddData(NodeAddData data)
-    {
-        ConfigurationNode node = data.getParent();
-
-        // Create missing nodes on the path
-        for (String nodeName : data.getPathNodes())
-        {
-            ConfigurationNode child = createNode(nodeName);
-            node.addChild(child);
-            node = child;
-        }
-
-        // Add new target node
-        ConfigurationNode child = createNode(data.getNewNodeName());
-        if (data.isAttribute())
-        {
-            node.addAttribute(child);
-        }
-        else
-        {
-            node.addChild(child);
-        }
-        return child;
-    }
-
-    /**
      * Clears all reference fields in a node structure. A configuration node can
      * store a so-called &quot;reference&quot;. The meaning of this data is
      * determined by a concrete sub class. Typically such references are
@@ -980,13 +404,14 @@
      *
      * @param node the root node of the node hierarchy, in which the references
      * are to be cleared
-     * @since 1.4
      */
-    protected static void clearReferences(ConfigurationNode node)
+    protected void clearReferences(ConfigurationNode node)
     {
-        node.visit(new ConfigurationNodeVisitorAdapter()
+        visit(node, new NodeVisitorAdapter<ConfigurationNode>()
         {
-            public void visitBeforeChildren(ConfigurationNode node)
+            @Override
+            public void visitBeforeChildren(ConfigurationNode node,
+                    NodeHandler<ConfigurationNode> handler)
             {
                 node.setReference(null);
             }
@@ -994,129 +419,10 @@
     }
 
     /**
-     * A specialized visitor that checks if a node is defined.
-     * &quot;Defined&quot; in this terms means that the node or at least one of
-     * its sub nodes is associated with a value.
-     *
-     */
-    static class DefinedVisitor extends ConfigurationNodeVisitorAdapter
-    {
-        /** Stores the defined flag. */
-        private boolean defined;
-
-        /**
-         * Checks if iteration should be stopped. This can be done if the first
-         * defined node is found.
-         *
-         * @return a flag if iteration should be stopped
-         */
-        @Override
-        public boolean terminate()
-        {
-            return isDefined();
-        }
-
-        /**
-         * Visits the node. Checks if a value is defined.
-         *
-         * @param node the actual node
-         */
-        @Override
-        public void visitBeforeChildren(ConfigurationNode node)
-        {
-            defined = node.getValue() != null;
-        }
-
-        /**
-         * Returns the defined flag.
-         *
-         * @return the defined flag
-         */
-        public boolean isDefined()
-        {
-            return defined;
-        }
-    }
-
-    /**
-     * A specialized visitor that fills a list with keys that are defined in a
-     * node hierarchy.
-     */
-    class DefinedKeysVisitor extends ConfigurationNodeVisitorAdapter
-    {
-        /** Stores the list to be filled. */
-        private Set<String> keyList;
-
-        /** A stack with the keys of the already processed nodes. */
-        private Stack<String> parentKeys;
-
-        /**
-         * Default constructor.
-         */
-        public DefinedKeysVisitor()
-        {
-            keyList = new LinkedHashSet<String>();
-            parentKeys = new Stack<String>();
-        }
-
-        /**
-         * Creates a new <code>DefinedKeysVisitor</code> instance and sets the
-         * prefix for the keys to fetch.
-         *
-         * @param prefix the prefix
-         */
-        public DefinedKeysVisitor(String prefix)
-        {
-            this();
-            parentKeys.push(prefix);
-        }
-
-        /**
-         * Returns the list with all defined keys.
-         *
-         * @return the list with the defined keys
-         */
-        public Set<String> getKeyList()
-        {
-            return keyList;
-        }
-
-        /**
-         * Visits the node after its children has been processed. Removes this
-         * node's key from the stack.
-         *
-         * @param node the node
-         */
-        @Override
-        public void visitAfterChildren(ConfigurationNode node)
-        {
-            parentKeys.pop();
-        }
-
-        /**
-         * Visits the specified node. If this node has a value, its key is added
-         * to the internal list.
-         *
-         * @param node the node to be visited
-         */
-        @Override
-        public void visitBeforeChildren(ConfigurationNode node)
-        {
-            String parentKey = parentKeys.isEmpty() ? null : (String) parentKeys.peek();
-            String key = getExpressionEngine().nodeKey(node, parentKey);
-            parentKeys.push(key);
-            if (node.getValue() != null)
-            {
-                keyList.add(key);
-            }
-        }
-    }
-
-    /**
      * A specialized visitor that is able to create a deep copy of a node
      * hierarchy.
      */
-    static class CloneVisitor extends ConfigurationNodeVisitorAdapter
+    static class CloneVisitor extends NodeVisitorAdapter<ConfigurationNode>
     {
         /** A stack with the actual object to be copied. */
         private Stack<ConfigurationNode> copyStack;
@@ -1138,7 +444,7 @@
          * @param node the node
          */
         @Override
-        public void visitAfterChildren(ConfigurationNode node)
+        public void visitAfterChildren(ConfigurationNode node, NodeHandler<ConfigurationNode> handler)
         {
             ConfigurationNode copy = copyStack.pop();
             if (copyStack.isEmpty())
@@ -1153,21 +459,18 @@
          * @param node the node
          */
         @Override
-        public void visitBeforeChildren(ConfigurationNode node)
+        public void visitBeforeChildren(ConfigurationNode node, NodeHandler<ConfigurationNode> handler)
         {
             ConfigurationNode copy = (ConfigurationNode) node.clone();
             copy.setParentNode(null);
 
+            for(ConfigurationNode attr : node.getAttributes())
+            {
+                copy.addAttribute((ConfigurationNode) attr.clone());
+            }
             if (!copyStack.isEmpty())
             {
-                if (node.isAttribute())
-                {
-                    copyStack.peek().addAttribute(copy);
-                }
-                else
-                {
-                    copyStack.peek().addChild(copy);
-                }
+                copyStack.peek().addChild(copy);
             }
 
             copyStack.push(copy);
@@ -1199,7 +502,7 @@
      * method can perform all steps to integrate the new node into the original
      * structure.
      */
-    protected abstract static class BuilderVisitor extends ConfigurationNodeVisitorAdapter
+    protected abstract static class BuilderVisitor extends NodeVisitorAdapter<ConfigurationNode>
     {
         /**
          * Visits the specified node before its children have been traversed.
@@ -1207,7 +510,7 @@
          * @param node the node to visit
          */
         @Override
-        public void visitBeforeChildren(ConfigurationNode node)
+        public void visitBeforeChildren(ConfigurationNode node, NodeHandler<ConfigurationNode> handler)
         {
             Collection<ConfigurationNode> subNodes = new LinkedList<ConfigurationNode>(node.getChildren());
             subNodes.addAll(node.getAttributes());

Copied: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/SubConfiguration.java (from r632835, commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/SubnodeConfiguration.java)
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/SubConfiguration.java?p2=commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/SubConfiguration.java&p1=commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/SubnodeConfiguration.java&r1=632835&r2=635081&rev=635081&view=diff
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/SubnodeConfiguration.java (original)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/SubConfiguration.java Sat Mar  8 12:42:32 2008
@@ -18,10 +18,9 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 
-import org.apache.commons.configuration2.tree.ConfigurationNode;
+import org.apache.commons.configuration2.expr.NodeList;
 
 /**
  * <p>
@@ -31,71 +30,71 @@
  * <p>
  * Configurations of this type are initialized with a parent configuration and a
  * configuration node of this configuration. This node becomes the root node of
- * the subnode configuration. All property accessor methods are evaluated
+ * the sub configuration. All property accessor methods are evaluated
  * relative to this root node. A good use case for a
- * <code>SubnodeConfiguration</code> is when multiple properties from a
+ * <code>SubConfiguration</code> is when multiple properties from a
  * specific sub tree of the whole configuration need to be accessed. Then a
- * <code>SubnodeConfiguration</code> can be created with the parent node of
+ * <code>SubConfiguration</code> can be created with the parent node of
  * the affected sub tree as root node. This allows for simpler property keys and
  * is also more efficient.
  * </p>
  * <p>
- * A subnode configuration and its parent configuration operate on the same
+ * A sub configuration and its parent configuration operate on the same
  * hierarchy of configuration nodes. So if modifications are performed at the
- * subnode configuration, these changes are immideately visible in the parent
+ * sub configuration, these changes are immediately visible in the parent
  * configuration. Analogously will updates of the parent configuration affect
- * the subnode configuration if the sub tree spanned by the subnode
+ * the sub configuration if the sub tree spanned by the sub
  * configuration's root node is involved.
  * </p>
  * <p>
  * There are however changes at the parent configuration, which cause the
- * subnode configuration to become detached. An example for such a change is a
+ * sub configuration to become detached. An example for such a change is a
  * reload operation of a file-based configuration, which replaces all nodes of
- * the parent configuration. The subnode configuration per default still
- * references the old nodes. Another example are list structures: a subnode
+ * the parent configuration. The sub configuration per default still
+ * references the old nodes. Another example are list structures: a sub
  * configuration can be created to point on the <em>i</em>th element of the
  * list. Now list elements can be added or removed, so that the list elements'
- * indices change. In such a scenario the subnode configuration would always
+ * indices change. In such a scenario the sub configuration would always
  * point to the same list element, regardless of its current index.
  * </p>
  * <p>
- * To solve these problems and make a subnode configuration aware of
+ * To solve these problems and make a sub configuration aware of
  * such structural changes of its parent, it is possible to associate a
- * subnode configuration with a configuration key. This can be done by calling
- * the <code>setSubnodeKey()</code> method. If here a key is set, the subnode
+ * sub configuration with a configuration key. This can be done by calling
+ * the <code>setSubnodeKey()</code> method. If here a key is set, the sub
  * configuration will evaluate it on each access, thus ensuring that it is
- * always in sync with its parent. In this mode the subnode configuration really
+ * always in sync with its parent. In this mode the sub configuration really
  * behaves like a live-view on its parent. The price for this is a decreased
  * performance because now an additional evaluation has to be performed on each
  * property access. So this mode should only be used if necessary; if for
- * instance a subnode configuration is only used for a temporary convenient
+ * instance a sub configuration is only used for a temporary convenient
  * access to a complex configuration, there is no need to make it aware for
- * structural changes of its parent. If a subnode configuration is created
- * using the <code>{@link HierarchicalConfiguration#configurationAt(String, boolean)
- * configurationAt()}</code> method of <code>HierarchicalConfiguration</code>
+ * structural changes of its parent. If a sub configuration is created
+ * using the <code>{@link AbstractHierarchicalConfiguration#configurationAt(String, boolean)
+ * configurationAt()}</code> method of <code>AbstractHierarchicalConfiguration</code>
  * (which should be the preferred way), with an additional boolean parameter it
- * can be specified whether the resulting subnode configuration should be
+ * can be specified whether the resulting sub configuration should be
  * aware of structural changes or not. Then the configuration key will be
  * automatically set.
  * </p>
  * <p>
- * <em>Note:</em> At the moment support for creating a subnode configuration
- * that is aware of structural changes of its parent from another subnode
- * configuration (a "sub subnode configuration") is limited. This only works if
- * <ol><li>the subnode configuration that serves as the parent for the new
- * subnode configuration is itself associated with a configuration key and</li>
- * <li>the key passed in to create the new subnode configuration is not too
+ * <em>Note:</em> At the moment support for creating a sub configuration
+ * that is aware of structural changes of its parent from another sub
+ * configuration (a "sub sub configuration") is limited. This only works if
+ * <ol><li>the sub configuration that serves as the parent for the new
+ * sub configuration is itself associated with a configuration key and</li>
+ * <li>the key passed in to create the new sub configuration is not too
  * complex (if configuration keys are used that contain indices, a corresponding
  * key that is valid from the parent configuration's point of view cannot be
  * constructed).</li></ol>
  * </p>
  * <p>
- * When a subnode configuration is created, it inherits the settings of its
+ * When a sub configuration is created, it inherits the settings of its
  * parent configuration, e.g. some flags like the
  * <code>throwExceptionOnMissing</code> flag or the settings for handling list
  * delimiters) or the expression engine. If these settings are changed later in
- * either the subnode or the parent configuration, the changes are not visible
- * for each other. So you could create a subnode configuration, change its
+ * either the sub or the parent configuration, the changes are not visible
+ * for each other. So you could create a sub configuration and then change its
  * expression engine without affecting the parent configuration.
  * </p>
  * <p>
@@ -103,25 +102,23 @@
  * <code>{@link SubsetConfiguration}</code>. The difference is that a subset
  * configuration of a hierarchical configuration may combine multiple
  * configuration nodes from different sub trees of the configuration, while all
- * nodes in a subnode configuration belong to the same sub tree. If an
+ * nodes in a sub configuration belong to the same sub tree. If an
  * application can live with this limitation, it is recommended to use this
  * class instead of <code>SubsetConfiguration</code> because creating a subset
- * configuration is more expensive than creating a subnode configuration.
+ * configuration is more expensive than creating a sub configuration.
  * </p>
  *
- * @since 1.3
+ * @since 2.0
  * @author Oliver Heger
  * @version $Id$
  */
-public class SubnodeConfiguration extends HierarchicalConfiguration
+public class SubConfiguration<T> extends AbstractHierarchicalConfiguration<T>
 {
-    /**
-     * The serial version UID.
-     */
-    private static final long serialVersionUID = 3105734147019386480L;
-
     /** Stores the parent configuration. */
-    private HierarchicalConfiguration parent;
+    private AbstractHierarchicalConfiguration<T> parent;
+
+    /** Stores the root node of this sub configuration.*/
+    private T rootNode;
 
     /** Stores the key that was used to construct this configuration.*/
     private String subnodeKey;
@@ -131,10 +128,13 @@
      * initializes it with the parent configuration and the new root node.
      *
      * @param parent the parent configuration
-     * @param root the root node of this subnode configuration
+     * @param root the root node of this sub configuration
+     * @throws IllegalArgumentException if the parent or the root node are <b>null</b>
      */
-    public SubnodeConfiguration(HierarchicalConfiguration parent, ConfigurationNode root)
+    public SubConfiguration(AbstractHierarchicalConfiguration<T> parent, T root)
     {
+        super((parent != null) ? parent.getNodeHandler() : null);
+
         if (parent == null)
         {
             throw new IllegalArgumentException(
@@ -145,29 +145,28 @@
             throw new IllegalArgumentException("Root node must not be null!");
         }
 
-        setRootNode(root);
+        rootNode = root;
         this.parent = parent;
         initFromParent(parent);
     }
 
     /**
-     * Returns the parent configuration of this subnode configuration.
+     * Returns the parent configuration of this sub configuration.
      *
      * @return the parent configuration
      */
-    public HierarchicalConfiguration getParent()
+    public AbstractHierarchicalConfiguration<T> getParent()
     {
         return parent;
     }
 
     /**
      * Returns the key that was used to construct this configuration. If here a
-     * non-<b>null</b> value is returned, the subnode configuration will
+     * non-<b>null</b> value is returned, the sub configuration will
      * always check its parent for structural changes and reconstruct itself if
      * necessary.
      *
      * @return the key for selecting this configuration's root node
-     * @since 1.5
      */
     public String getSubnodeKey()
     {
@@ -175,12 +174,11 @@
     }
 
     /**
-     * Sets the key to the root node of this subnode configuration. If here a
-     * key is set, the subnode configuration will behave like a live-view on its
+     * Sets the key to the root node of this sub configuration. If here a
+     * key is set, the sub configuration will behave like a live-view on its
      * parent for this key. See the class comment for more details.
      *
      * @param subnodeKey the key used to construct this configuration
-     * @since 1.5
      */
     public void setSubnodeKey(String subnodeKey)
     {
@@ -188,34 +186,34 @@
     }
 
     /**
-     * Returns the root node for this configuration. If a subnode key is set,
-     * this implementation re-evaluates this key to find out if this subnode
-     * configuration needs to be reconstructed. This ensures that the subnode
+     * Returns the root node for this configuration. If a sub key is set,
+     * this implementation re-evaluates this key to find out if this sub
+     * configuration needs to be reconstructed. This ensures that the sub
      * configuration is always synchronized with its parent configuration.
      *
      * @return the root node of this configuration
-     * @since 1.5
      * @see #setSubnodeKey(String)
      */
-    public ConfigurationNode getRootNode()
+    @Override
+    public T getRootNode()
     {
         if (getSubnodeKey() != null)
         {
             try
             {
-                List<ConfigurationNode> nodes = getParent().fetchNodeList(getSubnodeKey());
-                if (nodes.size() != 1)
+                NodeList<T> nodes = getParent().fetchNodeList(getSubnodeKey());
+                if (nodes.size() != 1 || !nodes.isNode(0))
                 {
-                    // key is invalid, so detach this subnode configuration
+                    // key is invalid, so detach this sub configuration
                     setSubnodeKey(null);
                 }
                 else
                 {
-                    ConfigurationNode currentRoot = nodes.get(0);
-                    if (currentRoot != super.getRootNode())
+                    T currentRoot = nodes.getNode(0);
+                    if (currentRoot != rootNode)
                     {
                         // the root node was changed due to a change of the parent
-                        setRootNode(currentRoot);
+                        rootNode = currentRoot;
                     }
                     return currentRoot;
                 }
@@ -229,21 +227,22 @@
             }
         }
 
-        return super.getRootNode(); // use stored root node
+        return rootNode; // use stored root node
     }
 
     /**
      * Returns a hierarchical configuration object for the given sub node.
      * This implementation will ensure that the returned
-     * <code>SubnodeConfiguration</code> object will have the same parent than
+     * <code>SubConfiguration</code> object will have the same parent as
      * this object.
      *
      * @param node the sub node, for which the configuration is to be created
      * @return a hierarchical configuration for this sub node
      */
-    protected SubnodeConfiguration createSubnodeConfiguration(ConfigurationNode node)
+    @Override
+    protected SubConfiguration<T> createSubnodeConfiguration(T node)
     {
-        SubnodeConfiguration result = new SubnodeConfiguration(getParent(), node);
+        SubConfiguration<T> result = new SubConfiguration<T>(getParent(), node);
         getParent().registerSubnodeConfiguration(result);
         return result;
     }
@@ -251,43 +250,43 @@
     /**
      * Returns a hierarchical configuration object for the given sub node that
      * is aware of structural changes of its parent. Works like the method with
-     * the same name, but also sets the subnode key for the new subnode
+     * the same name, but also sets the subnode key for the new sub
      * configuration, so it can check whether the parent has been changed. This
-     * only works if this subnode configuration has itself a valid subnode key.
-     * So if a subnode configuration that should be aware of structural changes
-     * is created from an already existing subnode configuration, this subnode
+     * only works if this sub configuration has itself a valid sub key.
+     * So if a sub configuration that should be aware of structural changes
+     * is created from an already existing sub configuration, this sub
      * configuration must also be aware of such changes.
      *
      * @param node the sub node, for which the configuration is to be created
      * @param subnodeKey the construction key
      * @return a hierarchical configuration for this sub node
-     * @since 1.5
      */
-    protected SubnodeConfiguration createSubnodeConfiguration(
-            ConfigurationNode node, String subnodeKey)
+    @Override
+    protected SubConfiguration<T> createSubnodeConfiguration(
+            T node, String subnodeKey)
     {
-        SubnodeConfiguration result = createSubnodeConfiguration(node);
+        SubConfiguration<T> result = createSubnodeConfiguration(node);
 
         if (getSubnodeKey() != null)
         {
             // construct the correct subnode key
             // determine path to root node
-            List<ConfigurationNode> lstPathToRoot = new ArrayList<ConfigurationNode>();
-            ConfigurationNode top = super.getRootNode();
-            ConfigurationNode nd = node;
+            List<T> lstPathToRoot = new ArrayList<T>();
+            T top = rootNode;
+            T nd = node;
             while (nd != top)
             {
                 lstPathToRoot.add(nd);
-                nd = nd.getParentNode();
+                nd = getNodeHandler().getParent(nd);
             }
 
             // construct the keys for the nodes on this path
             Collections.reverse(lstPathToRoot);
             String key = getSubnodeKey();
-            for (Iterator it = lstPathToRoot.iterator(); it.hasNext();)
+            for (T currentNode : lstPathToRoot)
             {
                 key = getParent().getExpressionEngine().nodeKey(
-                        (ConfigurationNode) it.next(), key);
+                        currentNode, key, getNodeHandler());
             }
             result.setSubnodeKey(key);
         }
@@ -298,23 +297,24 @@
     /**
      * Creates a new node. This task is delegated to the parent.
      *
+     * @param parent the parent node
      * @param name the node's name
      * @return the new node
      */
     @Override
-    protected ConfigurationNode createNode(String name)
+    protected T createNode(T parent, String name)
     {
-        return getParent().createNode(name);
+        return getParent().createNode(parent, name);
     }
 
     /**
-     * Initializes this subnode configuration from the given parent
+     * Initializes this sub configuration from the given parent
      * configuration. This method is called by the constructor. It will copy
      * many settings from the parent.
      *
      * @param parentConfig the parent configuration
      */
-    protected void initFromParent(HierarchicalConfiguration parentConfig)
+    protected void initFromParent(AbstractHierarchicalConfiguration<T> parentConfig)
     {
         setExpressionEngine(parentConfig.getExpressionEngine());
         setListDelimiter(parentConfig.getListDelimiter());



Mime
View raw message