You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2014/04/20 21:32:10 UTC

svn commit: r1588831 [6/11] - in /commons/proper/configuration/trunk: ./ src/main/java/org/apache/commons/configuration/ src/main/java/org/apache/commons/configuration/beanutils/ src/main/java/org/apache/commons/configuration/builder/combined/ src/main...

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/DefaultExpressionEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/DefaultExpressionEngine.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/DefaultExpressionEngine.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/DefaultExpressionEngine.java Sun Apr 20 19:32:08 2014
@@ -158,35 +158,26 @@ public class DefaultExpressionEngine imp
     }
 
     /**
-     * Evaluates the given key and returns all matching nodes. This method
-     * supports the syntax as described in the class comment.
-     *
-     * @param root the root node
-     * @param key the key
-     * @return a list with the matching nodes
+     * {@inheritDoc} This method supports the syntax as described in the class
+     * comment.
      */
-    @Override
-    public List<ConfigurationNode> query(ConfigurationNode root, String key)
+    public <T> List<QueryResult<T>> query(T root, String key,
+            NodeHandler<T> handler)
     {
-        List<ConfigurationNode> nodes = new LinkedList<ConfigurationNode>();
+        List<QueryResult<T>> results = new LinkedList<QueryResult<T>>();
         findNodesForKey(new DefaultConfigurationKey(this, key).iterator(),
-                root, nodes);
-        return nodes;
+                root, results, handler);
+        return results;
     }
 
     /**
-     * Determines the key of the passed in node. This implementation takes the
+     * {@inheritDoc} This implementation takes the
      * given parent key, adds a property delimiter, and then adds the node's
-     * name. (For attribute nodes the attribute delimiters are used instead.)
-     * The name of the root node is a blanc string. Note that no indices will be
+     * name.
+     * The name of the root node is a blank string. Note that no indices are
      * returned.
-     *
-     * @param node the node whose key is to be determined
-     * @param parentKey the key of this node's parent
-     * @return the key for the given node
      */
-    @Override
-    public String nodeKey(ConfigurationNode node, String parentKey)
+    public <T> String nodeKey(T node, String parentKey, NodeHandler<T> handler)
     {
         if (parentKey == null)
         {
@@ -198,18 +189,43 @@ public class DefaultExpressionEngine imp
         {
             DefaultConfigurationKey key = new DefaultConfigurationKey(this,
                     parentKey);
-            if (node.isAttribute())
-            {
-                key.appendAttribute(node.getName());
-            }
-            else
-            {
-                key.append(node.getName(), true);
-            }
+                key.append(handler.nodeName(node), true);
             return key.toString();
         }
     }
 
+    public String attributeKey(String parentKey, String attributeName)
+    {
+        DefaultConfigurationKey key =
+                new DefaultConfigurationKey(this, parentKey);
+        key.appendAttribute(attributeName);
+        return key.toString();
+    }
+
+    /**
+     * {@inheritDoc} This implementation works similar to {@code nodeKey()};
+     * however, each key returned by this method has an index (except for the
+     * root node). The parent key is prepended to the name of the current node
+     * in any case and without further checks. If it is <b>null</b>, only the
+     * name of the current node with its index is returned.
+     */
+    public <T> String canonicalKey(T node, String parentKey,
+            NodeHandler<T> handler)
+    {
+        String nodeName = handler.nodeName(node);
+        T parent = handler.getParent(node);
+        DefaultConfigurationKey key =
+                new DefaultConfigurationKey(this, parentKey);
+        key.append(StringUtils.defaultString(nodeName));
+
+        if (parent != null)
+        {
+            // this is not the root key
+            key.appendIndex(determineIndex(node, parent, nodeName, handler));
+        }
+        return key.toString();
+    }
+
     /**
      * <p>
      * Prepares Adding the property with the specified key.
@@ -218,7 +234,7 @@ public class DefaultExpressionEngine imp
      * To be able to deal with the structure supported by hierarchical
      * configuration implementations the passed in key is of importance,
      * especially the indices it might contain. The following example should
-     * clarify this: Suppose the actual node structure looks like the
+     * clarify this: Suppose the current node structure looks like the
      * following:
      * </p>
      * <p>
@@ -293,12 +309,13 @@ public class DefaultExpressionEngine imp
      * so there cannot be any ambiguities.)
      * </p>
      *
+     * @param <T> the type of the nodes to be dealt with
      * @param root the root node of the nodes hierarchy
      * @param key the key of the new property
+     * @param handler the node handler
      * @return a data object with information needed for the add operation
      */
-    @Override
-    public NodeAddData prepareAdd(ConfigurationNode root, String key)
+    public <T> NodeAddData<T> prepareAdd(T root, String key, NodeHandler<T> handler)
     {
         DefaultConfigurationKey.KeyIterator it = new DefaultConfigurationKey(
                 this, key).iterator();
@@ -308,8 +325,8 @@ public class DefaultExpressionEngine imp
                     "Key for add operation must be defined!");
         }
 
-        NodeAddData result = new NodeAddData();
-        result.setParent(findLastPathNode(it, root));
+        T parent = findLastPathNode(it, root, handler);
+        List<String> pathNodes = new LinkedList<String>();
 
         while (it.hasNext())
         {
@@ -319,30 +336,32 @@ public class DefaultExpressionEngine imp
                         "Invalid key for add operation: " + key
                                 + " (Attribute key in the middle.)");
             }
-            result.addPathNode(it.currentKey());
+            pathNodes.add(it.currentKey());
             it.next();
         }
 
-        result.setNewNodeName(it.currentKey());
-        result.setAttribute(!it.isPropertyKey());
-        return result;
+        return new NodeAddData<T>(parent, it.currentKey(), !it.isPropertyKey(),
+                pathNodes);
     }
 
     /**
      * Recursive helper method for evaluating a key. This method processes all
      * facets of a configuration key, traverses the tree of properties and
-     * fetches the the nodes of all matching properties.
+     * fetches the results of all matching properties.
      *
+     * @param <T> the type of nodes to be dealt with
      * @param keyPart the configuration key iterator
-     * @param node the actual node
-     * @param nodes here the found nodes are stored
+     * @param node the current node
+     * @param results here the found results are stored
+     * @param handler the node handler
      */
-    protected void findNodesForKey(DefaultConfigurationKey.KeyIterator keyPart,
-            ConfigurationNode node, Collection<ConfigurationNode> nodes)
+    protected <T> void findNodesForKey(
+            DefaultConfigurationKey.KeyIterator keyPart, T node,
+            Collection<QueryResult<T>> results, NodeHandler<T> handler)
     {
         if (!keyPart.hasNext())
         {
-            nodes.add(node);
+            results.add(QueryResult.createNodeResult(node));
         }
 
         else
@@ -350,26 +369,32 @@ public class DefaultExpressionEngine imp
             String key = keyPart.nextKey(false);
             if (keyPart.isPropertyKey())
             {
-                processSubNodes(keyPart, node.getChildren(key), nodes);
+                processSubNodes(keyPart, handler.getChildren(node, key),
+                        results, handler);
             }
-            if (keyPart.isAttribute())
+            if (keyPart.isAttribute() && !keyPart.hasNext())
             {
-                processSubNodes(keyPart, node.getAttributes(key), nodes);
+                if (handler.getAttributeValue(node, key) != null)
+                {
+                    results.add(QueryResult.createAttributeResult(node, key));
+                }
             }
         }
     }
 
     /**
      * Finds the last existing node for an add operation. This method traverses
-     * the configuration node tree along the specified key. The last existing
-     * node on this path is returned.
+     * the node tree along the specified key. The last existing node on this
+     * path is returned.
      *
+     * @param <T> the type of the nodes to be dealt with
      * @param keyIt the key iterator
-     * @param node the actual node
+     * @param node the current node
+     * @param handler the node handler
      * @return the last existing node on the given path
      */
-    protected ConfigurationNode findLastPathNode(
-            DefaultConfigurationKey.KeyIterator keyIt, ConfigurationNode node)
+    protected <T> T findLastPathNode(DefaultConfigurationKey.KeyIterator keyIt,
+            T node, NodeHandler<T> handler)
     {
         String keyPart = keyIt.nextKey(false);
 
@@ -382,15 +407,17 @@ public class DefaultExpressionEngine imp
                         "Invalid path for add operation: "
                                 + "Attribute key in the middle!");
             }
-            int idx = keyIt.hasIndex() ? keyIt.getIndex() : node
-                    .getChildrenCount(keyPart) - 1;
-            if (idx < 0 || idx >= node.getChildrenCount(keyPart))
+            int idx =
+                    keyIt.hasIndex() ? keyIt.getIndex() : handler
+                            .getChildrenCount(node, keyPart) - 1;
+            if (idx < 0 || idx >= handler.getChildrenCount(node, keyPart))
             {
                 return node;
             }
             else
             {
-                return findLastPathNode(keyIt, node.getChildren(keyPart).get(idx));
+                return findLastPathNode(keyIt,
+                        handler.getChildren(node, keyPart).get(idx), handler);
             }
         }
 
@@ -405,28 +432,46 @@ public class DefaultExpressionEngine imp
      * the current node depending on the type of the current key part (children,
      * attributes, or both).
      *
+     * @param <T> the type of the nodes to be dealt with
      * @param keyPart the key part
      * @param subNodes a list with the sub nodes to process
      * @param nodes the target collection
+     * @param handler the node handler
      */
-    private void processSubNodes(DefaultConfigurationKey.KeyIterator keyPart,
-            List<ConfigurationNode> subNodes, Collection<ConfigurationNode> nodes)
+    private <T> void processSubNodes(DefaultConfigurationKey.KeyIterator keyPart,
+            List<T> subNodes, Collection<QueryResult<T>> nodes, NodeHandler<T> handler)
     {
         if (keyPart.hasIndex())
         {
             if (keyPart.getIndex() >= 0 && keyPart.getIndex() < subNodes.size())
             {
                 findNodesForKey((DefaultConfigurationKey.KeyIterator) keyPart
-                        .clone(), subNodes.get(keyPart.getIndex()), nodes);
+                        .clone(), subNodes.get(keyPart.getIndex()), nodes, handler);
             }
         }
         else
         {
-            for (ConfigurationNode node : subNodes)
+            for (T node : subNodes)
             {
                 findNodesForKey((DefaultConfigurationKey.KeyIterator) keyPart
-                        .clone(), node, nodes);
+                        .clone(), node, nodes, handler);
             }
         }
     }
+
+    /**
+     * Determines the index of the given node based on its parent node.
+     *
+     * @param node the current node
+     * @param parent the parent node
+     * @param nodeName the name of the current node
+     * @param handler the node handler
+     * @param <T> the type of the nodes to be dealt with
+     * @return the index of this node
+     */
+    private static <T> int determineIndex(T node, T parent, String nodeName,
+                                          NodeHandler<T> handler)
+    {
+        return handler.getChildren(parent, nodeName).indexOf(node);
+    }
 }

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/ExpressionEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/ExpressionEngine.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/ExpressionEngine.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/ExpressionEngine.java Sun Apr 20 19:32:08 2014
@@ -27,56 +27,93 @@ import java.util.List;
  * An <em>expression engine</em> knows how to map a key for a configuration's
  * property to a single or a set of configuration nodes. Thus it defines the way
  * how properties are addressed in this configuration. Methods of a
- * configuration that have to handle property key (e.g.
- * {@code getProperty()} or {@code addProperty()} do not interpret
- * the passed in keys on their own, but delegate this task to an associated
- * expression engine. This expression engine will then find out, which
- * configuration nodes are addressed by the key.
+ * configuration that have to handle property keys (e.g. {@code getProperty()}
+ * or {@code addProperty()} do not interpret the passed in keys on their own,
+ * but delegate this task to an associated expression engine. This expression
+ * engine will then find out, which configuration nodes are addressed by the
+ * key.
  * </p>
  * <p>
  * Separating the task of evaluating property keys from the configuration object
- * has the advantage that many different expression languages (i.e. ways for
+ * has the advantage that multiple different expression languages (i.e. ways for
  * querying or setting properties) can be supported. Just set a suitable
  * implementation of this interface as the configuration's expression engine,
  * and you can use the syntax provided by this implementation.
  * </p>
+ * <p>
+ * An {@code ExpressionEngine} can deal with nodes of different types. To
+ * achieve this, a {@link NodeHandler} for the desired type must be passed to
+ * the methods.
+ * </p>
  *
  * @since 1.3
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @version $Id$
  */
 public interface ExpressionEngine
 {
     /**
-     * Finds the node(s) that is (are) matched by the specified key. This is the
-     * main method for interpreting property keys. An implementation must
-     * traverse the given root node and its children to find all nodes that are
-     * matched by the given key. If the key is not correct in the syntax
-     * provided by that implementation, it is free to throw a (runtime)
-     * exception indicating this error condition.
+     * Finds the nodes and/or attributes that are matched by the specified key.
+     * This is the main method for interpreting property keys. An implementation
+     * must traverse the given root node and its children to find all results
+     * that are matched by the given key. If the key is not correct in the
+     * syntax provided by that implementation, it is free to throw a (runtime)
+     * exception indicating this error condition. The passed in
+     * {@code NodeHandler} can be used to gather the required information from
+     * the node object.
      *
-     * @param root the root node of a hierarchy of configuration nodes
+     * @param <T> the type of the node to be processed
+     * @param root the root node of a hierarchy of nodes
      * @param key the key to be evaluated
-     * @return a list with the nodes that are matched by the key (should never
-     * be <b>null</b>)
+     * @param handler the {@code NodeHandler} for accessing the node
+     * @return a list with the results that are matched by the key (should never
+     *         be <b>null</b>)
      */
-    List<ConfigurationNode> query(ConfigurationNode root, String key);
+    <T> List<QueryResult<T>> query(T root, String key, NodeHandler<T> handler);
 
     /**
      * Returns the key for the specified node in the expression language
      * supported by an implementation. This method is called whenever a property
      * key for a node has to be constructed, e.g. by the
-     * {@link org.apache.commons.configuration.Configuration#getKeys() getKeys()}
-     * method.
+     * {@link org.apache.commons.configuration.Configuration#getKeys()
+     * getKeys()} method.
      *
+     * @param <T> the type of the node to be processed
      * @param node the node, for which the key must be constructed
      * @param parentKey the key of this node's parent (can be <b>null</b> for
-     * the root node)
+     *        the root node)
+     * @param handler the {@code NodeHandler} for accessing the node
      * @return this node's key
      */
-    String nodeKey(ConfigurationNode node, String parentKey);
+    <T> String nodeKey(T node, String parentKey, NodeHandler<T> handler);
+
+    /**
+     * Returns the key of an attribute. The passed in {@code parentKey} must
+     * reference the parent node of the attribute. A concrete implementation
+     * must concatenate this parent key with the attribute name to a valid key
+     * for this attribute.
+     *
+     * @param parentKey the key to the node owning this attribute
+     * @param attributeName the name of the attribute in question
+     * @return the resulting key referencing this attribute
+     */
+    String attributeKey(String parentKey, String attributeName);
+
+    /**
+     * Determines a &quot;canonical&quot; key for the specified node in the
+     * expression language supported by this implementation. This means that
+     * always a unique key if generated pointing to this specific node. For most
+     * concrete implementations, this means that an index is added to the node
+     * name to ensure that there are no ambiguities with child nodes having the
+     * same names.
+     *
+     * @param <T> the type of the node to be processed
+     * @param node the node, for which the key must be constructed
+     * @param parentKey the key of this node's parent (can be <b>null</b> for
+     *        the root node)
+     * @param handler the {@code NodeHandler} for accessing the node
+     * @return the canonical key of this node
+     */
+    <T> String canonicalKey(T node, String parentKey, NodeHandler<T> handler);
 
     /**
      * Returns information needed for an add operation. This method gets called
@@ -84,9 +121,11 @@ public interface ExpressionEngine
      * has to interpret the specified key, find the parent node for the new
      * elements, and provide all information about new nodes to be added.
      *
+     * @param <T> the type of the node to be processed
      * @param root the root node
      * @param key the key for the new property
+     * @param handler the {@code NodeHandler} for accessing the node
      * @return an object with all information needed for the add operation
      */
-    NodeAddData prepareAdd(ConfigurationNode root, String key);
+    <T> NodeAddData<T> prepareAdd(T root, String key, NodeHandler<T> handler);
 }

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/ImmutableNode.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/ImmutableNode.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/ImmutableNode.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/ImmutableNode.java Sun Apr 20 19:32:08 2014
@@ -40,6 +40,7 @@ import java.util.Map;
  * </p>
  *
  * @version $Id$
+ * @since 2.0
  */
 public class ImmutableNode
 {
@@ -113,6 +114,19 @@ public class ImmutableNode
 
     /**
      * Creates a new {@code ImmutableNode} instance which is a copy of this
+     * object with the name changed to the passed in value.
+     *
+     * @param name the name of the newly created node
+     * @return the new node with the changed name
+     */
+    public ImmutableNode setName(String name)
+    {
+        return new Builder(children, attributes).name(name).value(value)
+                .create();
+    }
+
+    /**
+     * Creates a new {@code ImmutableNode} instance which is a copy of this
      * object with the value changed to the passed in value.
      *
      * @param newValue the value of the newly created node
@@ -202,6 +216,23 @@ public class ImmutableNode
 
     /**
      * Returns a new {@code ImmutableNode} instance which is a copy of this
+     * object, but with the children replaced by the ones in the passed in
+     * collection. With this method all children can be replaced in a single
+     * step. For the collection the same rules apply as for
+     * {@link Builder#addChildren(Collection)}.
+     *
+     * @param newChildren the collection with the new children (may be
+     *        <b>null</b>)
+     */
+    public ImmutableNode replaceChildren(Collection<ImmutableNode> newChildren)
+    {
+        Builder builder = new Builder(null, attributes);
+        builder.addChildren(newChildren);
+        return createWithBasicProperties(builder);
+    }
+
+    /**
+     * Returns a new {@code ImmutableNode} instance which is a copy of this
      * object, but with the specified attribute set to the given value. If an
      * attribute with this name does not exist, it is created now. Otherwise,
      * the new value overrides the old one.
@@ -219,6 +250,28 @@ public class ImmutableNode
 
     /**
      * Returns a new {@code ImmutableNode} instance which is a copy of this
+     * object, but with all attributes added defined by the given map. This
+     * method is analogous to {@link #setAttribute(String, Object)}, but all
+     * attributes in the given map are added. If the map is <b>null</b> or
+     * empty, this method has no effect.
+     *
+     * @param newAttributes the map with attributes to be added
+     * @return the new node with these attributes
+     */
+    public ImmutableNode setAttributes(Map<String, ?> newAttributes)
+    {
+        if (newAttributes == null || newAttributes.isEmpty())
+        {
+            return this;
+        }
+
+        Map<String, Object> newAttrs = new HashMap<String, Object>(attributes);
+        newAttrs.putAll(newAttributes);
+        return createWithNewAttributes(newAttrs);
+    }
+
+    /**
+     * Returns a new {@code ImmutableNode} instance which is a copy of this
      * object, but with the specified attribute removed. If there is no
      * attribute with the given name, the same node instance is returned.
      *
@@ -421,10 +474,11 @@ public class ImmutableNode
          * {@link #addChild(ImmutableNode)}, but it allows setting a number of
          * child nodes at once.
          *
+         *
          * @param children a collection with the child nodes to be added
          * @return a reference to this object for method chaining
          */
-        public Builder addChildren(Collection<ImmutableNode> children)
+        public Builder addChildren(Collection<? extends ImmutableNode> children)
         {
             if (children != null)
             {
@@ -576,11 +630,12 @@ public class ImmutableNode
         /**
          * Filters null entries from the passed in collection with child nodes.
          *
+         *
          * @param children the collection to be filtered
          * @return the collection with null entries removed
          */
         private static Collection<? extends ImmutableNode> filterNull(
-                Collection<ImmutableNode> children)
+                Collection<? extends ImmutableNode> children)
         {
             List<ImmutableNode> result =
                     new ArrayList<ImmutableNode>(children.size());

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/MergeCombiner.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/MergeCombiner.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/MergeCombiner.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/MergeCombiner.java Sun Apr 20 19:32:08 2014
@@ -17,9 +17,12 @@
 package org.apache.commons.configuration.tree;
 
 import java.util.ArrayList;
-import java.util.Iterator;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.ObjectUtils;
 
 /**
  * <p>
@@ -36,9 +39,6 @@ import java.util.List;
  * </ol>
  * </p>
  *
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @version $Id$
  * @since 1.7
  */
@@ -53,18 +53,18 @@ public class MergeCombiner extends NodeC
      */
 
     @Override
-    public ConfigurationNode combine(ConfigurationNode node1, ConfigurationNode node2)
+    public ImmutableNode combine(ImmutableNode node1, ImmutableNode node2)
     {
-        ViewNode result = createViewNode();
-        result.setName(node1.getName());
-        result.setValue(node1.getValue());
+        ImmutableNode.Builder result = new ImmutableNode.Builder();
+        result.name(node1.getNodeName());
+        result.value(node1.getValue());
         addAttributes(result, node1, node2);
 
         // Check if nodes can be combined
-        List<ConfigurationNode> children2 = new LinkedList<ConfigurationNode>(node2.getChildren());
-        for (ConfigurationNode child1 : node1.getChildren())
+        List<ImmutableNode> children2 = new LinkedList<ImmutableNode>(node2.getChildren());
+        for (ImmutableNode child1 : node1.getChildren())
         {
-            ConfigurationNode child2 = canCombine(node1, node2, child1, children2);
+            ImmutableNode child2 = canCombine(node2, child1, children2);
             if (child2 != null)
             {
                 result.addChild(combine(child1, child2));
@@ -77,11 +77,11 @@ public class MergeCombiner extends NodeC
         }
 
         // Add remaining children of node 2
-        for (ConfigurationNode c : children2)
+        for (ImmutableNode c : children2)
         {
             result.addChild(c);
         }
-        return result;
+        return result.create();
     }
 
     /**
@@ -90,21 +90,23 @@ public class MergeCombiner extends NodeC
      * second node, which are not contained in the first node, will also be
      * added.
      *
-     * @param result the resulting node
+     * @param result the builder for the resulting node
      * @param node1 the first node
      * @param node2 the second node
      */
-    protected void addAttributes(ViewNode result, ConfigurationNode node1,
-            ConfigurationNode node2)
+    protected void addAttributes(ImmutableNode.Builder result, ImmutableNode node1,
+            ImmutableNode node2)
     {
-        result.appendAttributes(node1);
-        for (ConfigurationNode attr : node2.getAttributes())
+        Map<String, Object> attributes = new HashMap<String, Object>();
+        attributes.putAll(node1.getAttributes());
+        for (Map.Entry<String, Object> e : node2.getAttributes().entrySet())
         {
-            if (node1.getAttributeCount(attr.getName()) == 0)
+            if (!attributes.containsKey(e.getKey()))
             {
-                result.addAttribute(attr);
+                attributes.put(e.getKey(), e.getValue());
             }
         }
+        result.addAttributes(attributes);
     }
 
     /**
@@ -112,35 +114,22 @@ public class MergeCombiner extends NodeC
      * only be combined if its attributes are all present in the second node and
      * they all have the same value.
      *
-     * @param node1 the first node
      * @param node2 the second node
      * @param child the child node (of the first node)
+     * @param children2 the children of the 2nd node
      * @return a child of the second node, with which a combination is possible
      */
-    protected ConfigurationNode canCombine(ConfigurationNode node1,
-            ConfigurationNode node2, ConfigurationNode child, List<ConfigurationNode> children2)
+    protected ImmutableNode canCombine(ImmutableNode node2,
+            ImmutableNode child, List<ImmutableNode> children2)
     {
-        List<ConfigurationNode> attrs1 = child.getAttributes();
-        List<ConfigurationNode> nodes = new ArrayList<ConfigurationNode>();
+        Map<String, Object> attrs1 = child.getAttributes();
+        List<ImmutableNode> nodes = new ArrayList<ImmutableNode>();
 
-        List<ConfigurationNode> children = node2.getChildren(child.getName());
-        Iterator<ConfigurationNode> it = children.iterator();
-        while (it.hasNext())
-        {
-            ConfigurationNode node = it.next();
-            Iterator<ConfigurationNode> iter = attrs1.iterator();
-            while (iter.hasNext())
-            {
-                ConfigurationNode attr1 = iter.next();
-                List<ConfigurationNode> list2 = node.getAttributes(attr1.getName());
-                if (list2.size() == 1
-                    && !attr1.getValue().equals(list2.get(0).getValue()))
-                {
-                    node = null;
-                    break;
-                }
-            }
-            if (node != null)
+        List<ImmutableNode> children =
+                HANDLER.getChildren(node2, child.getNodeName());
+        for (ImmutableNode node : children)
+        {
+            if (matchAttributes(attrs1, node))
             {
                 nodes.add(node);
             }
@@ -152,13 +141,36 @@ public class MergeCombiner extends NodeC
         }
         if (nodes.size() > 1 && !isListNode(child))
         {
-            Iterator<ConfigurationNode> iter = nodes.iterator();
-            while (iter.hasNext())
+            for (ImmutableNode node : nodes)
             {
-                children2.remove(iter.next());
+                children2.remove(node);
             }
         }
 
         return null;
     }
+
+    /**
+     * Checks whether the attributes of the passed in node are compatible.
+     *
+     * @param attrs1 the attributes of the first node
+     * @param node the 2nd node
+     * @return a flag whether these nodes can be combined regarding their
+     *         attributes
+     */
+    private static boolean matchAttributes(Map<String, Object> attrs1,
+            ImmutableNode node)
+    {
+        Map<String, Object> attrs2 = node.getAttributes();
+        for (Map.Entry<String, Object> e : attrs1.entrySet())
+        {
+            if (attrs2.containsKey(e.getKey())
+                    && !ObjectUtils
+                            .equals(e.getValue(), attrs2.get(e.getKey())))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
 }

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeAddData.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeAddData.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeAddData.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeAddData.java Sun Apr 20 19:32:08 2014
@@ -16,8 +16,9 @@
  */
 package org.apache.commons.configuration.tree;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
 
 /**
@@ -46,47 +47,41 @@ import java.util.List;
  * </p>
  *
  * @since 1.3
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @version $Id$
+ * @param <T> the type of nodes this class can handle
  */
-public class NodeAddData
+public class NodeAddData<T>
 {
     /** Stores the parent node of the add operation. */
-    private ConfigurationNode parent;
+    private final T parent;
 
     /**
-     * Stores a list with nodes that are on the path between the parent node and
-     * the new node.
+     * Stores a list with the names of nodes that are on the path between the
+     * parent node and the new node.
      */
-    private List<String> pathNodes;
+    private final List<String> pathNodes;
 
     /** Stores the name of the new node. */
-    private String newNodeName;
+    private final String newNodeName;
 
     /** Stores the attribute flag. */
-    private boolean attribute;
+    private final boolean attribute;
 
     /**
-     * Creates a new, uninitialized instance of {@code NodeAddData}.
-     */
-    public NodeAddData()
-    {
-        this(null, null);
-    }
-
-    /**
-     * Creates a new instance of {@code NodeAddData} and sets the most
-     * important data fields.
+     * Creates a new instance of {@code NodeAddData} and initializes it.
      *
-     * @param parent the parent node
-     * @param nodeName the name of the new node
+     * @param parentNode the parent node of the add operation
+     * @param newName the name of the new node
+     * @param isAttr flag whether the new node is an attribute
+     * @param intermediateNodes an optional collection with path nodes
      */
-    public NodeAddData(ConfigurationNode parent, String nodeName)
+    public NodeAddData(T parentNode, String newName, boolean isAttr,
+            Collection<String> intermediateNodes)
     {
-        setParent(parent);
-        setNewNodeName(nodeName);
+        parent = parentNode;
+        newNodeName = newName;
+        attribute = isAttr;
+        pathNodes = createPathNodes(intermediateNodes);
     }
 
     /**
@@ -101,17 +96,6 @@ public class NodeAddData
     }
 
     /**
-     * Sets the attribute flag. This flag determines whether an attribute or a
-     * child node will be added.
-     *
-     * @param attribute the attribute flag
-     */
-    public void setAttribute(boolean attribute)
-    {
-        this.attribute = attribute;
-    }
-
-    /**
      * Returns the name of the new node.
      *
      * @return the new node's name
@@ -122,39 +106,18 @@ public class NodeAddData
     }
 
     /**
-     * Sets the name of the new node. A node with this name will be added to the
-     * configuration's node hierarchy.
-     *
-     * @param newNodeName the name of the new node
-     */
-    public void setNewNodeName(String newNodeName)
-    {
-        this.newNodeName = newNodeName;
-    }
-
-    /**
      * Returns the parent node.
      *
      * @return the parent node
      */
-    public ConfigurationNode getParent()
+    public T getParent()
     {
         return parent;
     }
 
     /**
-     * Sets the parent node. New nodes will be added to this node.
-     *
-     * @param parent the parent node
-     */
-    public void setParent(ConfigurationNode parent)
-    {
-        this.parent = parent;
-    }
-
-    /**
      * Returns a list with further nodes that must be added. This is needed if a
-     * complete branch is to be added at once. For instance imagine that there
+     * complete branch is to be added at once. For instance, imagine that there
      * exists only a node {@code database}. Now the key
      * {@code database.connection.settings.username} (assuming the syntax
      * of the default expression engine) is to be added. Then
@@ -168,29 +131,26 @@ public class NodeAddData
      */
     public List<String> getPathNodes()
     {
-        if (pathNodes != null)
-        {
-            return Collections.unmodifiableList(pathNodes);
-        }
-        else
-        {
-            return Collections.emptyList();
-        }
+        return pathNodes;
     }
 
     /**
-     * Adds the name of a path node. With this method an additional node to be
-     * added can be defined.
+     * Creates the list with path nodes. Handles null input.
      *
-     * @param nodeName the name of the node
-     * @see #getPathNodes()
+     * @param intermediateNodes the nodes passed to the constructor
+     * @return an unmodifiable list of path nodes
      */
-    public void addPathNode(String nodeName)
+    private static List<String> createPathNodes(
+            Collection<String> intermediateNodes)
     {
-        if (pathNodes == null)
+        if (intermediateNodes == null)
+        {
+            return Collections.emptyList();
+        }
+        else
         {
-            pathNodes = new LinkedList<String>();
+            return Collections.unmodifiableList(new ArrayList<String>(
+                    intermediateNodes));
         }
-        pathNodes.add(nodeName);
     }
 }

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeCombiner.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeCombiner.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeCombiner.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeCombiner.java Sun Apr 20 19:32:08 2014
@@ -44,16 +44,22 @@ import java.util.Set;
  * can be passed the name of a node, which should be considered a list node.
  * </p>
  *
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @version $Id$
  * @since 1.3
  */
 public abstract class NodeCombiner
 {
+    /**
+     * A default handler object for immutable nodes. This object can be used by
+     * derived classes for dealing with nodes. However, it provides only limited
+     * functionality; it supports only operations on child nodes, but no
+     * references to parent nodes.
+     */
+    protected static final NodeHandler<ImmutableNode> HANDLER =
+            createNodeHandler();
+
     /** Stores a list with node names that are known to be list nodes. */
-    protected Set<String> listNodes;
+    private final Set<String> listNodes;
 
     /**
      * Creates a new instance of {@code NodeCombiner}.
@@ -92,9 +98,9 @@ public abstract class NodeCombiner
      * @param node the node to be tested
      * @return a flag whether this is a list node
      */
-    public boolean isListNode(ConfigurationNode node)
+    public boolean isListNode(ImmutableNode node)
     {
-        return listNodes.contains(node.getName());
+        return listNodes.contains(node.getNodeName());
     }
 
     /**
@@ -104,21 +110,32 @@ public abstract class NodeCombiner
      *
      * @param node1 the first root node
      * @param node2 the second root node
-     * @return the resulting combined node structure
+     * @return the root node of the resulting combined node structure
      */
-    public abstract ConfigurationNode combine(ConfigurationNode node1,
-            ConfigurationNode node2);
+    public abstract ImmutableNode combine(ImmutableNode node1,
+            ImmutableNode node2);
 
     /**
-     * Creates a new view node. This method will be called whenever a new view
-     * node is to be created. It can be overridden to create special view nodes.
-     * This base implementation returns a new instance of
-     * {@link ViewNode}.
+     * Creates a node handler object for immutable nodes which can be used by
+     * sub classes to perform advanced operations on nodes.
      *
-     * @return the new view node
+     * @return the node handler implementation
      */
-    protected ViewNode createViewNode()
+    private static NodeHandler<ImmutableNode> createNodeHandler()
     {
-        return new ViewNode();
+        return new AbstractImmutableNodeHandler()
+        {
+            @Override
+            public ImmutableNode getParent(ImmutableNode node)
+            {
+                return null;
+            }
+
+            @Override
+            public ImmutableNode getRootNode()
+            {
+                return null;
+            }
+        };
     }
 }

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeHandler.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeHandler.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeHandler.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/NodeHandler.java Sun Apr 20 19:32:08 2014
@@ -17,6 +17,7 @@
 package org.apache.commons.configuration.tree;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * <p>
@@ -28,15 +29,15 @@ import java.util.List;
  * {@code NodeHandler} is used. The handler provides a number of methods for
  * querying the internal state of a node in a read-only way.
  * </p>
- * 
+ *
  * @version $Id$
- * @param T the type of the nodes this handler deals with
+ * @param <T> the type of the nodes this handler deals with
  */
 public interface NodeHandler<T>
 {
     /**
      * Returns the name of the specified node
-     * 
+     *
      * @param node the node
      * @return the name of this node
      */
@@ -44,7 +45,7 @@ public interface NodeHandler<T>
 
     /**
      * Returns the value of the specified node.
-     * 
+     *
      * @param node the node
      * @return the value of this node
      */
@@ -52,7 +53,7 @@ public interface NodeHandler<T>
 
     /**
      * Returns the parent of the specified node.
-     * 
+     *
      * @param node the node
      * @return the parent node
      */
@@ -60,7 +61,7 @@ public interface NodeHandler<T>
 
     /**
      * Returns an unmodifiable list with all children of the specified node.
-     * 
+     *
      * @param node the node
      * @return a list with the child nodes of this node
      */
@@ -69,7 +70,7 @@ public interface NodeHandler<T>
     /**
      * Returns an unmodifiable list of all children of the specified node with
      * the given name.
-     * 
+     *
      * @param node the node
      * @param name the name of the desired child nodes
      * @return a list with all children with the given name
@@ -78,7 +79,7 @@ public interface NodeHandler<T>
 
     /**
      * Returns the child with the given index of the specified node.
-     * 
+     *
      * @param node the node
      * @param index the index (0-based)
      * @return the child with the given index
@@ -86,18 +87,18 @@ public interface NodeHandler<T>
     T getChild(T node, int index);
 
     /**
-     * Returns the index of the given child node relative to its name. This
-     * method can be called when a unique identifier for a specific node is
-     * needed. The node name alone might not be sufficient because there may be
-     * multiple child nodes with the same name. This method returns 0 if the
-     * given node is the first child node with this name, 1 for the second child
-     * node and so on. If the node has no parent node or if it is an attribute,
-     * -1 is returned.
-     * 
-     * @param node a child node whose index is to be retrieved
+     * Returns the index of the given child node in the list of children of its
+     * parent. This method is the opposite operation of
+     * {@link #getChild(Object, int)}. This method returns 0 if the given node
+     * is the first child node with this name, 1 for the second child node and
+     * so on. If the node has no parent node or if it is an attribute, -1 is
+     * returned.
+     *
+     * @param parent the parent node
+     * @param child a child node whose index is to be retrieved
      * @return the index of this child node
      */
-    int indexOfChild(T node);
+    int indexOfChild(T parent, T child);
 
     /**
      * Returns the number of children of the specified node with the given name.
@@ -108,7 +109,7 @@ public interface NodeHandler<T>
      * a child name is passed in, only the children with this name are taken
      * into account. If the name <b>null</b> is passed, the total number of
      * children must be returned.
-     * 
+     *
      * @param node the node
      * @param name the name of the children in question (can be <b>null</b> for
      *        all children)
@@ -117,17 +118,17 @@ public interface NodeHandler<T>
     int getChildrenCount(T node, String name);
 
     /**
-     * Returns an unmodifiable list with the names of all attributes of the
+     * Returns an unmodifiable set with the names of all attributes of the
      * specified node.
-     * 
+     *
      * @param node the node
-     * @return a list with the names of all attributes of this node
+     * @return a set with the names of all attributes of this node
      */
-    List<String> getAttributes(T node);
+    Set<String> getAttributes(T node);
 
     /**
      * Returns a flag whether the passed in node has any attributes.
-     * 
+     *
      * @param node the node
      * @return a flag whether this node has any attributes
      */
@@ -137,7 +138,7 @@ public interface NodeHandler<T>
      * Returns the value of the specified attribute from the given node. If a
      * concrete {@code NodeHandler} supports attributes with multiple values,
      * result might be a collection.
-     * 
+     *
      * @param node the node
      * @param name the name of the attribute
      * @return the value of this attribute
@@ -148,9 +149,16 @@ public interface NodeHandler<T>
      * Checks whether the specified node is defined. Nodes are
      * &quot;defined&quot; if they contain any data, e.g. a value, or
      * attributes, or defined children.
-     * 
+     *
      * @param node the node to test
      * @return a flag whether the passed in node is defined
      */
     boolean isDefined(T node);
+
+    /**
+     * Returns the root node of the underlying hierarchy.
+     *
+     * @return the current root node
+     */
+    T getRootNode();
 }

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/OverrideCombiner.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/OverrideCombiner.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/OverrideCombiner.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/OverrideCombiner.java Sun Apr 20 19:32:08 2014
@@ -47,9 +47,6 @@ package org.apache.commons.configuration
  * will never be combined.
  * </p>
  *
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @version $Id$
  * @since 1.3
  */
@@ -63,16 +60,16 @@ public class OverrideCombiner extends No
      * @return the resulting combined node structure
      */
     @Override
-    public ConfigurationNode combine(ConfigurationNode node1,
-            ConfigurationNode node2)
+    public ImmutableNode combine(ImmutableNode node1,
+            ImmutableNode node2)
     {
-        ViewNode result = createViewNode();
-        result.setName(node1.getName());
+        ImmutableNode.Builder result = new ImmutableNode.Builder();
+        result.name(node1.getNodeName());
 
         // Process nodes from the first structure, which override the second
-        for (ConfigurationNode child : node1.getChildren())
+        for (ImmutableNode child : node1.getChildren())
         {
-            ConfigurationNode child2 = canCombine(node1, node2, child);
+            ImmutableNode child2 = canCombine(node1, node2, child);
             if (child2 != null)
             {
                 result.addChild(combine(child, child2));
@@ -85,9 +82,9 @@ public class OverrideCombiner extends No
 
         // Process nodes from the second structure, which are not contained
         // in the first structure
-        for (ConfigurationNode child : node2.getChildren())
+        for (ImmutableNode child : node2.getChildren())
         {
-            if (node1.getChildrenCount(child.getName()) < 1)
+            if (HANDLER.getChildrenCount(node1, child.getNodeName()) < 1)
             {
                 result.addChild(child);
             }
@@ -95,31 +92,31 @@ public class OverrideCombiner extends No
 
         // Handle attributes and value
         addAttributes(result, node1, node2);
-        result.setValue((node1.getValue() != null) ? node1.getValue() : node2
+        result.value((node1.getValue() != null) ? node1.getValue() : node2
                 .getValue());
 
-        return result;
+        return result.create();
     }
 
     /**
      * Handles the attributes during a combination process. First all attributes
-     * of the first node will be added to the result. Then all attributes of the
-     * second node, which are not contained in the first node, will also be
-     * added.
+     * of the first node are added to the result. Then all attributes of the
+     * second node, which are not contained in the first node, are also added.
      *
      * @param result the resulting node
      * @param node1 the first node
      * @param node2 the second node
      */
-    protected void addAttributes(ViewNode result, ConfigurationNode node1,
-            ConfigurationNode node2)
+    protected void addAttributes(ImmutableNode.Builder result,
+            ImmutableNode node1, ImmutableNode node2)
     {
-        result.appendAttributes(node1);
-        for (ConfigurationNode attr : node2.getAttributes())
+        result.addAttributes(node1.getAttributes());
+        for (String attr : node2.getAttributes().keySet())
         {
-            if (node1.getAttributeCount(attr.getName()) == 0)
+            if (!node1.getAttributes().containsKey(attr))
             {
-                result.addAttribute(attr);
+                result.addAttribute(attr,
+                        HANDLER.getAttributeValue(node2, attr));
             }
         }
     }
@@ -136,14 +133,14 @@ public class OverrideCombiner extends No
      * @param child the child node (of the first node)
      * @return a child of the second node, with which a combination is possible
      */
-    protected ConfigurationNode canCombine(ConfigurationNode node1,
-            ConfigurationNode node2, ConfigurationNode child)
+    protected ImmutableNode canCombine(ImmutableNode node1,
+            ImmutableNode node2, ImmutableNode child)
     {
-        if (node2.getChildrenCount(child.getName()) == 1
-                && node1.getChildrenCount(child.getName()) == 1
+        if (HANDLER.getChildrenCount(node2, child.getNodeName()) == 1
+                && HANDLER.getChildrenCount(node1, child.getNodeName()) == 1
                 && !isListNode(child))
         {
-            return node2.getChildren(child.getName()).get(0);
+            return HANDLER.getChildren(node2, child.getNodeName()).get(0);
         }
         else
         {

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/TreeUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/TreeUtils.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/TreeUtils.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/TreeUtils.java Sun Apr 20 19:32:08 2014
@@ -17,13 +17,11 @@
 package org.apache.commons.configuration.tree;
 
 import java.io.PrintStream;
-import java.util.Iterator;
+import java.util.Map;
 
 /**
  * Utility methods.
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
+ *
  * @version $Id$
  * @since 1.7
  */
@@ -39,7 +37,7 @@ public final class TreeUtils
      * @param stream The OutputStream.
      * @param result The root node of the tree.
      */
-    public static void printTree(PrintStream stream, ConfigurationNode result)
+    public static void printTree(PrintStream stream, ImmutableNode result)
     {
         if (stream != null)
         {
@@ -47,14 +45,12 @@ public final class TreeUtils
         }
     }
 
-    private static void printTree(PrintStream stream, String indent, ConfigurationNode result)
+    private static void printTree(PrintStream stream, String indent, ImmutableNode result)
     {
-        StringBuffer buffer = new StringBuffer(indent).append("<").append(result.getName());
-        Iterator<ConfigurationNode> iter = result.getAttributes().iterator();
-        while (iter.hasNext())
+        StringBuilder buffer = new StringBuilder(indent).append("<").append(result.getNodeName());
+        for (Map.Entry<String, Object> e : result.getAttributes().entrySet())
         {
-            ConfigurationNode node = iter.next();
-            buffer.append(" ").append(node.getName()).append("='").append(node.getValue()).append("'");
+            buffer.append(' ').append(e.getKey()).append("='").append(e.getValue()).append("'");
         }
         buffer.append(">");
         stream.print(buffer.toString());
@@ -63,13 +59,12 @@ public final class TreeUtils
             stream.print(result.getValue());
         }
         boolean newline = false;
-        if (result.getChildrenCount() > 0)
+        if (!result.getChildren().isEmpty())
         {
             stream.print("\n");
-            iter = result.getChildren().iterator();
-            while (iter.hasNext())
+            for (ImmutableNode child : result.getChildren())
             {
-                printTree(stream, indent + "  ", iter.next());
+                printTree(stream, indent + "  ", child);
             }
             newline = true;
         }
@@ -77,6 +72,6 @@ public final class TreeUtils
         {
             stream.print(indent);
         }
-        stream.println("</" + result.getName() + ">");
+        stream.println("</" + result.getNodeName() + ">");
     }
 }

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/UnionCombiner.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/UnionCombiner.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/UnionCombiner.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/UnionCombiner.java Sun Apr 20 19:32:08 2014
@@ -25,7 +25,7 @@ import java.util.List;
  * that constructs a union from two passed in node hierarchies.
  * </p>
  * <p>
- * The given source hierarchies are traversed and their nodes are added to the
+ * The given source hierarchies are traversed, and their nodes are added to the
  * resulting structure. Under some circumstances two nodes can be combined
  * rather than adding both. This is the case if both nodes are single children
  * (no lists) of their parents and do not have values. The corresponding check
@@ -108,10 +108,14 @@ import java.util.List;
  * must not combine the {@code Table} nodes, but add it both to the
  * resulting tree.
  * </p>
+ * <p>
+ * Another limitation is the handling of attributes: Attributes can only
+ * have a single value. So if two nodes are to be combined which both have
+ * an attribute with the same name, it is not possible to construct a
+ * proper union attribute. In this case, the attribute value from the
+ * first node is used.
+ * </p>
  *
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @version $Id$
  * @since 1.3
  */
@@ -125,20 +129,22 @@ public class UnionCombiner extends NodeC
      * @return the union node
      */
     @Override
-    public ConfigurationNode combine(ConfigurationNode node1,
-            ConfigurationNode node2)
+    public ImmutableNode combine(ImmutableNode node1,
+            ImmutableNode node2)
     {
-        ViewNode result = createViewNode();
-        result.setName(node1.getName());
-        result.appendAttributes(node1);
-        result.appendAttributes(node2);
+        ImmutableNode.Builder result = new ImmutableNode.Builder();
+        result.name(node1.getNodeName());
+
+        // attributes of the first node take precedence
+        result.addAttributes(node2.getAttributes());
+        result.addAttributes(node1.getAttributes());
 
         // Check if nodes can be combined
-        List<ConfigurationNode> children2 = new LinkedList<ConfigurationNode>(node2.getChildren());
-        for (ConfigurationNode child1 : node1.getChildren())
+        List<ImmutableNode> children2 = new LinkedList<ImmutableNode>(node2.getChildren());
+        for (ImmutableNode child1 : node1.getChildren())
         {
-            ConfigurationNode child2 = findCombineNode(node1, node2, child1,
-                    children2);
+            ImmutableNode child2 = findCombineNode(node1, node2, child1
+            );
             if (child2 != null)
             {
                 result.addChild(combine(child1, child2));
@@ -151,12 +157,12 @@ public class UnionCombiner extends NodeC
         }
 
         // Add remaining children of node 2
-        for (ConfigurationNode c : children2)
+        for (ImmutableNode c : children2)
         {
             result.addChild(c);
         }
 
-        return result;
+        return result.create();
     }
 
     /**
@@ -188,19 +194,18 @@ public class UnionCombiner extends NodeC
      * @param node1 the first source node
      * @param node2 the second source node
      * @param child the child node of the first source node to be checked
-     * @param children a list with all children of the second source node
      * @return the matching child node of the second source node or <b>null</b>
      * if there is none
      */
-    protected ConfigurationNode findCombineNode(ConfigurationNode node1,
-            ConfigurationNode node2, ConfigurationNode child, List<ConfigurationNode> children)
+    protected ImmutableNode findCombineNode(ImmutableNode node1,
+            ImmutableNode node2, ImmutableNode child)
     {
         if (child.getValue() == null && !isListNode(child)
-                && node1.getChildrenCount(child.getName()) == 1
-                && node2.getChildrenCount(child.getName()) == 1)
+                && HANDLER.getChildrenCount(node1, child.getNodeName()) == 1
+                && HANDLER.getChildrenCount(node2, child.getNodeName()) == 1)
         {
-            ConfigurationNode child2 = node2.getChildren(
-                    child.getName()).iterator().next();
+            ImmutableNode child2 =
+                    HANDLER.getChildren(node2, child.getNodeName()).get(0);
             if (child2.getValue() == null)
             {
                 return child2;

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java Sun Apr 20 19:32:08 2014
@@ -18,46 +18,78 @@ package org.apache.commons.configuration
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Set;
 
-import org.apache.commons.configuration.tree.ConfigurationNode;
 import org.apache.commons.jxpath.ri.QName;
 import org.apache.commons.jxpath.ri.model.NodePointer;
 
 /**
  * A specialized node iterator implementation that deals with attribute nodes.
  *
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @version $Id$
+ * @param <T> the type of the nodes this iterator deals with
  */
-class ConfigurationNodeIteratorAttribute extends
-        ConfigurationNodeIteratorBase
+class ConfigurationNodeIteratorAttribute<T> extends
+        ConfigurationNodeIteratorBase<T>
 {
     /** Constant for the wildcard node name.*/
     private static final String WILDCARD = "*";
 
+    /** Stores the parent node pointer. */
+    private ConfigurationNodePointer<T> parentPointer;
+
+    /** A list with the names of the managed attributes. */
+    private List<String> attributeNames;
+
     /**
      * Creates a new instance of {@code ConfigurationNodeIteratorAttribute}.
      * @param parent the parent node pointer
      * @param name the name of the selected attribute
      */
-    public ConfigurationNodeIteratorAttribute(NodePointer parent, QName name)
+    public ConfigurationNodeIteratorAttribute(
+            ConfigurationNodePointer<T> parent, QName name)
     {
         super(parent, false);
-        initSubNodeList(createSubNodeList((ConfigurationNode) parent.getNode(),
-                name));
+        parentPointer = parent;
+        attributeNames = createAttributeDataList(parent, name);
+    }
+
+    /**
+     * Creates a pointer for the node at the specified position.
+     *
+     * @param position the desired position
+     * @return a pointer for the attribute at this position
+     */
+    @Override
+    protected NodePointer createNodePointer(int position)
+    {
+        return new ConfigurationAttributePointer<T>(parentPointer,
+                attributeNames.get(position));
+    }
+
+    /**
+     * Returns the size of the managed iteration.
+     *
+     * @return the iteration size
+     */
+    @Override
+    protected int size()
+    {
+        return attributeNames.size();
     }
 
     /**
      * Determines which attributes are selected based on the passed in node
      * name.
-     * @param node the current node
+     *
+     * @param parent the parent node pointer
      * @param name the name of the selected attribute
      * @return a list with the selected attributes
      */
-    protected List<ConfigurationNode> createSubNodeList(ConfigurationNode node, QName name)
+    private List<String> createAttributeDataList(
+            ConfigurationNodePointer<T> parent, QName name)
     {
         if (name.getPrefix() != null)
         {
@@ -65,16 +97,40 @@ class ConfigurationNodeIteratorAttribute
             return Collections.emptyList();
         }
 
-        List<ConfigurationNode> result = new ArrayList<ConfigurationNode>();
+        List<String> result = new ArrayList<String>();
         if (!WILDCARD.equals(name.getName()))
         {
-            result.addAll(node.getAttributes(name.getName()));
+            addAttributeData(parent, result, name.getName());
         }
         else
         {
-            result.addAll(node.getAttributes());
+            Set<String> names =
+                    new LinkedHashSet<String>(parent.getNodeHandler()
+                            .getAttributes(parent.getConfigurationNode()));
+            for (String n : names)
+            {
+                addAttributeData(parent, result, n);
+            }
         }
 
         return result;
     }
+
+    /**
+     * Helper method for checking whether an attribute is defined and adding it
+     * to the list of attributes to iterate over.
+     *
+     * @param parent the parent node pointer
+     * @param result the result list
+     * @param name the name of the current attribute
+     */
+    private void addAttributeData(ConfigurationNodePointer<T> parent,
+            List<String> result, String name)
+    {
+        if (parent.getNodeHandler().getAttributeValue(
+                parent.getConfigurationNode(), name) != null)
+        {
+            result.add(name);
+        }
+    }
 }

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java Sun Apr 20 19:32:08 2014
@@ -16,9 +16,7 @@
  */
 package org.apache.commons.configuration.tree.xpath;
 
-import java.util.List;
-
-import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.configuration.tree.NodeHandler;
 import org.apache.commons.jxpath.ri.model.NodeIterator;
 import org.apache.commons.jxpath.ri.model.NodePointer;
 
@@ -33,18 +31,13 @@ import org.apache.commons.jxpath.ri.mode
  * </p>
  *
  * @since 1.3
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @version $Id$
+ * @param <T> the type of the nodes this iterator deals with
  */
-abstract class ConfigurationNodeIteratorBase implements NodeIterator
+abstract class ConfigurationNodeIteratorBase<T> implements NodeIterator
 {
     /** Stores the parent node pointer. */
-    private final NodePointer parent;
-
-    /** Stores the list with the sub nodes. */
-    private List<ConfigurationNode> subNodes;
+    private final ConfigurationNodePointer<T> parent;
 
     /** Stores the current position. */
     private int position;
@@ -62,7 +55,8 @@ abstract class ConfigurationNodeIterator
      * @param parent the parent pointer
      * @param reverse the reverse flag
      */
-    protected ConfigurationNodeIteratorBase(NodePointer parent, boolean reverse)
+    protected ConfigurationNodeIteratorBase(ConfigurationNodePointer<T> parent,
+            boolean reverse)
     {
         this.parent = parent;
         this.reverse = reverse;
@@ -73,7 +67,6 @@ abstract class ConfigurationNodeIterator
      *
      * @return the position
      */
-    @Override
     public int getPosition()
     {
         return position;
@@ -85,7 +78,6 @@ abstract class ConfigurationNodeIterator
      * @param pos the new position
      * @return a flag if this is a valid position
      */
-    @Override
     public boolean setPosition(int pos)
     {
         position = pos;
@@ -97,7 +89,6 @@ abstract class ConfigurationNodeIterator
      *
      * @return the current pointer in this iteration
      */
-    @Override
     public NodePointer getNodePointer()
     {
         if (getPosition() < 1 && !setPosition(1))
@@ -105,7 +96,7 @@ abstract class ConfigurationNodeIterator
             return null;
         }
 
-        return createNodePointer(subNodes.get(positionToIndex(getPosition())));
+        return createNodePointer(positionToIndex(getPosition()));
     }
 
     /**
@@ -113,12 +104,23 @@ abstract class ConfigurationNodeIterator
      *
      * @return the parent node pointer
      */
-    protected NodePointer getParent()
+    protected ConfigurationNodePointer<T> getParent()
     {
         return parent;
     }
 
     /**
+     * Returns the node handler for the managed nodes. This is a convenience
+     * method.
+     *
+     * @return the node handler
+     */
+    protected NodeHandler<T> getNodeHandler()
+    {
+        return getParent().getNodeHandler();
+    }
+
+    /**
      * Returns the start offset of the iteration.
      *
      * @return the start offset
@@ -148,29 +150,25 @@ abstract class ConfigurationNodeIterator
     }
 
     /**
-     * Initializes the list of sub nodes for the iteration. This method must be
-     * called during initialization phase.
+     * Returns the maximum position for this iterator.
      *
-     * @param nodes the list with the sub nodes
+     * @return the maximum allowed position
      */
-    protected void initSubNodeList(List<ConfigurationNode> nodes)
+    protected int getMaxPosition()
     {
-        subNodes = nodes;
-        if (reverse)
-        {
-            setStartOffset(subNodes.size());
-        }
+        return reverse ? getStartOffset() + 1 : size() - getStartOffset();
     }
 
     /**
-     * Returns the maximum position for this iterator.
+     * Returns the index in the data list for the given position. This method
+     * also checks the reverse flag.
      *
-     * @return the maximum allowed position
+     * @param pos the position (1-based)
+     * @return the corresponding list index
      */
-    protected int getMaxPosition()
+    protected int positionToIndex(int pos)
     {
-        return reverse ? getStartOffset() + 1 : subNodes.size()
-                - getStartOffset();
+        return (reverse ? 1 - pos : pos - 1) + getStartOffset();
     }
 
     /**
@@ -178,23 +176,15 @@ abstract class ConfigurationNodeIterator
      * method is called by {@code getNodePointer()}. Derived classes
      * must create the correct pointer object.
      *
-     * @param node the current configuration node
+     * @param position the current position in the iteration
      * @return the node pointer
      */
-    protected NodePointer createNodePointer(ConfigurationNode node)
-    {
-        return new ConfigurationNodePointer(getParent(), node);
-    }
+    protected abstract NodePointer createNodePointer(int position);
 
     /**
-     * Returns the index in the data list for the given position. This method
-     * also checks the reverse flag.
+     * Returns the number of elements in this iteration.
      *
-     * @param pos the position (1-based)
-     * @return the corresponding list index
+     * @return the number of elements
      */
-    protected int positionToIndex(int pos)
-    {
-        return (reverse ? 1 - pos : pos - 1) + getStartOffset();
-    }
+    protected abstract int size();
 }

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java Sun Apr 20 19:32:08 2014
@@ -20,7 +20,6 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.apache.commons.configuration.tree.ConfigurationNode;
 import org.apache.commons.jxpath.ri.Compiler;
 import org.apache.commons.jxpath.ri.QName;
 import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
@@ -34,37 +33,71 @@ import org.apache.commons.lang3.StringUt
  * node.
  *
  * @since 1.3
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @version $Id$
  */
-class ConfigurationNodeIteratorChildren extends ConfigurationNodeIteratorBase
+class ConfigurationNodeIteratorChildren<T> extends
+        ConfigurationNodeIteratorBase<T>
 {
+    /** The list with the sub nodes to iterate over. */
+    private final List<T> subNodes;
+
     /**
-     * Creates a new instance of {@code ConfigurationNodeIteratorChildren}
-     * and initializes it.
+     * Creates a new instance of {@code ConfigurationNodeIteratorChildren} and
+     * initializes it.
      *
      * @param parent the parent pointer
      * @param nodeTest the test selecting the sub nodes
      * @param reverse the reverse flag
      * @param startsWith the first element of the iteration
      */
-    public ConfigurationNodeIteratorChildren(NodePointer parent,
-            NodeTest nodeTest, boolean reverse, NodePointer startsWith)
+    public ConfigurationNodeIteratorChildren(
+            ConfigurationNodePointer<T> parent, NodeTest nodeTest,
+            boolean reverse, ConfigurationNodePointer<T> startsWith)
     {
         super(parent, reverse);
-        ConfigurationNode root = (ConfigurationNode) parent.getNode();
-        List<ConfigurationNode> childNodes = createSubNodeList(root, nodeTest);
-        initSubNodeList(childNodes);
+        T root = parent.getConfigurationNode();
+        subNodes = createSubNodeList(root, nodeTest);
+
         if (startsWith != null)
         {
-            setStartOffset(findStartIndex(root,
-                    (ConfigurationNode) startsWith.getNode()));
+            setStartOffset(findStartIndex(subNodes,
+                    startsWith.getConfigurationNode()));
+        }
+        else
+        {
+            if (reverse)
+            {
+                setStartOffset(size());
+            }
         }
     }
 
     /**
+     * Creates the configuration node pointer for the current position.
+     *
+     * @param position the current position in the iteration
+     * @return the node pointer
+     */
+    @Override
+    protected NodePointer createNodePointer(int position)
+    {
+        return new ConfigurationNodePointer<T>(getParent(), subNodes
+                .get(position), getNodeHandler());
+    }
+
+    /**
+     * Returns the number of elements in this iteration. This is the number of
+     * elements in the children list.
+     *
+     * @return the number of elements
+     */
+    @Override
+    protected int size()
+    {
+        return subNodes.size();
+    }
+
+    /**
      * Creates the list with sub nodes. This method gets called during
      * initialization phase. It finds out, based on the given test, which nodes
      * must be iterated over.
@@ -73,9 +106,9 @@ class ConfigurationNodeIteratorChildren 
      * @param test the test object
      * @return a list with the matching nodes
      */
-    protected List<ConfigurationNode> createSubNodeList(ConfigurationNode node, NodeTest test)
+    private List<T> createSubNodeList(T node, NodeTest test)
     {
-        List<ConfigurationNode> children = node.getChildren();
+        List<T> children = getNodeHandler().getChildren(node);
 
         if (test == null)
         {
@@ -94,10 +127,11 @@ class ConfigurationNodeIteratorChildren 
                         return children;
                     }
 
-                    List<ConfigurationNode> result = new ArrayList<ConfigurationNode>();
-                    for (ConfigurationNode child : children)
+                    List<T> result = new ArrayList<T>();
+                    for (T child : children)
                     {
-                        if (StringUtils.equals(name.getName(), child.getName()))
+                        if (StringUtils.equals(name.getName(), getNodeHandler()
+                                .nodeName(child)))
                         {
                             result.add(child);
                         }
@@ -124,19 +158,20 @@ class ConfigurationNodeIteratorChildren 
      * Determines the start position of the iteration. Finds the index of the
      * given start node in the children of the root node.
      *
-     * @param node the root node
+     * @param children the children of the root node
      * @param startNode the start node
      * @return the start node's index
      */
-    protected int findStartIndex(ConfigurationNode node,
-            ConfigurationNode startNode)
+    private int findStartIndex(List<T> children, T startNode)
     {
-        for (int index = 0; index < node.getChildrenCount(); index++)
+        int index = 0;
+        for(T child : children)
         {
-            if (node.getChild(index) == startNode)
+            if(child == startNode)
             {
                 return index;
             }
+            index++;
         }
 
         return -1;

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java?rev=1588831&r1=1588830&r2=1588831&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java Sun Apr 20 19:32:08 2014
@@ -16,10 +16,9 @@
  */
 package org.apache.commons.configuration.tree.xpath;
 
-import java.util.List;
 import java.util.Locale;
 
-import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.configuration.tree.NodeHandler;
 import org.apache.commons.jxpath.ri.Compiler;
 import org.apache.commons.jxpath.ri.QName;
 import org.apache.commons.jxpath.ri.compiler.NodeTest;
@@ -36,31 +35,36 @@ import org.apache.commons.jxpath.ri.mode
  * </p>
  *
  * @since 1.3
- * @author <a
- * href="http://commons.apache.org/configuration/team-list.html">Commons
- * Configuration team</a>
  * @version $Id$
+ * @param <T> the type of the nodes this pointer deals with
  */
-class ConfigurationNodePointer extends NodePointer
+class ConfigurationNodePointer<T> extends NodePointer
 {
     /**
      * The serial version UID.
      */
     private static final long serialVersionUID = -1087475639680007713L;
 
-    /** Stores the associated configuration node. */
-    private final ConfigurationNode node;
+    /** The node handler. */
+    private final NodeHandler<T> handler;
+
+    /** Stores the associated node. */
+    private final T node;
 
     /**
-     * Creates a new instance of {@code ConfigurationNodePointer}.
+     * Creates a new instance of {@code ConfigurationNodePointer} pointing to
+     * the specified node.
      *
-     * @param node the node
+     * @param node the wrapped node
      * @param locale the locale
+     * @param handler the {@code NodeHandler}
      */
-    public ConfigurationNodePointer(ConfigurationNode node, Locale locale)
+    public ConfigurationNodePointer(T node, Locale locale,
+            NodeHandler<T> handler)
     {
         super(null, locale);
         this.node = node;
+        this.handler = handler;
     }
 
     /**
@@ -69,11 +73,14 @@ class ConfigurationNodePointer extends N
      *
      * @param parent the parent pointer
      * @param node the associated node
+     * @param handler the {@code NodeHandler}
      */
-    public ConfigurationNodePointer(NodePointer parent, ConfigurationNode node)
+    public ConfigurationNodePointer(ConfigurationNodePointer<T> parent, T node,
+            NodeHandler<T> handler)
     {
         super(parent);
         this.node = node;
+        this.handler = handler;
     }
 
     /**
@@ -85,7 +92,7 @@ class ConfigurationNodePointer extends N
     @Override
     public boolean isLeaf()
     {
-        return node.getChildrenCount() < 1;
+        return getNodeHandler().getChildrenCount(node, null) < 1;
     }
 
     /**
@@ -111,15 +118,15 @@ class ConfigurationNodePointer extends N
     }
 
     /**
-     * Checks whether this node pointer refers to an attribute node. This method
-     * checks the attribute flag of the associated configuration node.
+     * Checks whether this node pointer refers to an attribute node. This is
+     * not the case.
      *
      * @return the attribute flag
      */
     @Override
     public boolean isAttribute()
     {
-        return node.isAttribute();
+        return false;
     }
 
     /**
@@ -130,7 +137,7 @@ class ConfigurationNodePointer extends N
     @Override
     public QName getName()
     {
-        return new QName(null, node.getName());
+        return new QName(null, getNodeHandler().nodeName(node));
     }
 
     /**
@@ -164,18 +171,19 @@ class ConfigurationNodePointer extends N
     @Override
     public Object getValue()
     {
-        return node.getValue();
+        return getNodeHandler().getValue(node);
     }
 
     /**
-     * Sets the value of this node.
+     * Sets the value of this node. This is not supported, so always an
+     * exception is thrown.
      *
      * @param value the new value
      */
     @Override
     public void setValue(Object value)
     {
-        node.setValue(value);
+        throw new UnsupportedOperationException("Node value cannot be set!");
     }
 
     /**
@@ -189,37 +197,22 @@ class ConfigurationNodePointer extends N
     public int compareChildNodePointers(NodePointer pointer1,
             NodePointer pointer2)
     {
-        ConfigurationNode node1 = (ConfigurationNode) pointer1.getBaseValue();
-        ConfigurationNode node2 = (ConfigurationNode) pointer2.getBaseValue();
-
-        // attributes will be sorted before child nodes
-        if (node1.isAttribute() && !node2.isAttribute())
-        {
-            return -1;
-        }
-        else if (node2.isAttribute() && !node1.isAttribute())
-        {
-            return 1;
-        }
+        Object node1 = pointer1.getBaseValue();
+        Object node2 = pointer2.getBaseValue();
 
-        else
+        // sort based on the occurrence in the sub node list
+        for (T child : getNodeHandler().getChildren(node))
         {
-            // sort based on the occurrence in the sub node list
-            List<ConfigurationNode> subNodes = node1.isAttribute() ? node.getAttributes() : node
-                    .getChildren();
-            for (ConfigurationNode child : subNodes)
+            if (child == node1)
             {
-                if (child == node1)
-                {
-                    return -1;
-                }
-                else if (child == node2)
-                {
-                    return 1;
-                }
+                return -1;
+            }
+            else if (child == node2)
+            {
+                return 1;
             }
-            return 0; // should not happen
         }
+        return 0; // should not happen
     }
 
     /**
@@ -231,7 +224,7 @@ class ConfigurationNodePointer extends N
     @Override
     public NodeIterator attributeIterator(QName name)
     {
-        return new ConfigurationNodeIteratorAttribute(this, name);
+        return new ConfigurationNodeIteratorAttribute<T>(this, name);
     }
 
     /**
@@ -246,8 +239,8 @@ class ConfigurationNodePointer extends N
     public NodeIterator childIterator(NodeTest test, boolean reverse,
             NodePointer startWith)
     {
-        return new ConfigurationNodeIteratorChildren(this, test, reverse,
-                startWith);
+        return new ConfigurationNodeIteratorChildren<T>(this, test, reverse,
+                castPointer(startWith));
     }
 
     /**
@@ -267,4 +260,40 @@ class ConfigurationNodePointer extends N
         }
         return super.testNode(test);
     }
+
+    /**
+     * Returns the {@code NodeHandler} used by this instance.
+     *
+     * @return the {@code NodeHandler}
+     */
+    public NodeHandler<T> getNodeHandler()
+    {
+        return handler;
+    }
+
+    /**
+     * Returns the wrapped configuration node.
+     *
+     * @return the wrapped node
+     */
+    public T getConfigurationNode()
+    {
+        return node;
+    }
+
+    /**
+     * Casts the given child pointer to a node pointer of this type. This is a
+     * bit dangerous. However, in a typical setup, child node pointers can only
+     * be created by this instance which ensures that they are of the correct
+     * type. Therefore, this cast is safe.
+     *
+     * @param p the {@code NodePointer} to cast
+     * @return the resulting {@code ConfigurationNodePointer}
+     */
+    private ConfigurationNodePointer<T> castPointer(NodePointer p)
+    {
+        @SuppressWarnings("unchecked") // see method comment
+        ConfigurationNodePointer<T> result = (ConfigurationNodePointer<T>) p;
+        return result;
+    }
 }