commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ohe...@apache.org
Subject svn commit: r1563460 - in /commons/proper/configuration/trunk/src: main/java/org/apache/commons/configuration/tree/DefaultExpressionEngine.java test/java/org/apache/commons/configuration/tree/TestDefaultExpressionEngine.java
Date Sat, 01 Feb 2014 20:07:46 GMT
Author: oheger
Date: Sat Feb  1 20:07:45 2014
New Revision: 1563460

URL: http://svn.apache.org/r1563460
Log:
Reworked DefaultExpressionEngine to handle arbitrary nodes.

DefaultExpressionEngine was adapted to the modified ExpressionEngine interface.
It now uses a passed in NodeHandler to access the properties of the nodes it
has to process.

Modified:
    commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/tree/DefaultExpressionEngine.java
    commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/tree/TestDefaultExpressionEngine.java

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=1563460&r1=1563459&r2=1563460&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
Sat Feb  1 20:07:45 2014
@@ -158,33 +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.
      */
-    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
      */
-    public String nodeKey(ConfigurationNode node, String parentKey)
+    public <T> String nodeKey(T node, String parentKey, NodeHandler<T> handler)
     {
         if (parentKey == null)
         {
@@ -196,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.
@@ -216,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>
@@ -291,11 +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
      */
-    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();
@@ -305,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())
         {
@@ -316,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
@@ -347,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);
 
@@ -379,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);
             }
         }
 
@@ -402,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/test/java/org/apache/commons/configuration/tree/TestDefaultExpressionEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/tree/TestDefaultExpressionEngine.java?rev=1563460&r1=1563459&r2=1563460&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/tree/TestDefaultExpressionEngine.java
(original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/tree/TestDefaultExpressionEngine.java
Sat Feb  1 20:07:45 2014
@@ -25,6 +25,7 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 /**
@@ -51,16 +52,25 @@ public class TestDefaultExpressionEngine
     { "uid", "uname", "firstName", "lastName", "email"},
     { "docid", "name", "creationDate", "authorID", "version"}};
 
+    /** The root of a hierarchy with test nodes. */
+    private static ImmutableNode root;
+
+    /** A node handler for the hierarchy of test nodes. */
+    private static NodeHandler<ImmutableNode> handler;
+
     /** The object to be tested. */
     private DefaultExpressionEngine engine;
 
-    /** The root of a hierarchy with configuration nodes. */
-    private ConfigurationNode root;
+    @BeforeClass
+    public static void setUpBeforeClass()
+    {
+        root = setUpNodes();
+        handler = new InMemoryNodeModel(root);
+    }
 
     @Before
     public void setUp() throws Exception
     {
-        root = setUpNodes();
         engine = DefaultExpressionEngine.INSTANCE;
     }
 
@@ -107,7 +117,8 @@ public class TestDefaultExpressionEngine
         for (int i = 0; i < tables.length; i++)
         {
             checkKeyValue("tables.table(" + i + ").name", "name", tables[i]);
-            checkKeyValue("tables.table(" + i + ")[@type]", "type", tabTypes[i]);
+            checkAttributeValue("tables.table(" + i + ")[@type]", "type",
+                    tabTypes[i]);
 
             for (int j = 0; j < fields[i].length; j++)
             {
@@ -130,6 +141,7 @@ public class TestDefaultExpressionEngine
         checkKey("tables.table(0).fields.field(28).name", null, 0);
         checkKey("tables.table(0).fields.field().name", null, 0);
         checkKey("connection.settings.usr.name", null, 0);
+        checkKey("tables.table(0)[@type].additional", null, 0);
     }
 
     /**
@@ -158,21 +170,48 @@ public class TestDefaultExpressionEngine
                         .create();
         engine = new DefaultExpressionEngine(symbols);
         checkKeyValue("tables.table(0).name", "name", tables[0]);
-        checkKeyValue("tables.table(0).type", "type", tabTypes[0]);
+        checkAttributeValue("tables.table(0).type", "type", tabTypes[0]);
         checkKey("tables.table.type", "type", 2);
     }
 
     /**
-     * Tests accessing the root node.
+     * Helper method for testing a query for the root node.
+     *
+     * @param key the key to be used
+     */
+    private void checkQueryRootNode(String key)
+    {
+        List<QueryResult<ImmutableNode>> results = checkKey(key, null, 1);
+        QueryResult<ImmutableNode> result = results.get(0);
+        assertFalse("No node result", result.isAttributeResult());
+        assertSame("Not the root node", root, result.getNode());
+    }
+
+    /**
+     * Tests whether the root node can be retrieved using the null key.
+     */
+    @Test
+    public void testQueryRootNodeNullKey()
+    {
+        checkQueryRootNode(null);
+    }
+
+    /**
+     * Tests whether the root node can be retrieved using the empty key.
+     */
+    @Test
+    public void testQueryRootNodeEmptyKey()
+    {
+        checkQueryRootNode("");
+    }
+
+    /**
+     * Tests whether an attribute of the root node can be queried.
      */
     @Test
-    public void testQueryRootNode()
+    public void testQueryRootAttribute()
     {
-        List<ConfigurationNode> nodes = checkKey(null, null, 1);
-        assertSame("Root node not found", root, nodes.get(0));
-        nodes = checkKey("", null, 1);
-        assertSame("Root node not found", root, nodes.get(0));
-        checkKeyValue("[@test]", "test", "true");
+        checkAttributeValue("[@test]", "test", "true");
     }
 
     /**
@@ -184,8 +223,8 @@ public class TestDefaultExpressionEngine
     {
         setUpAlternativeSyntax();
         checkKeyValue("tables/table[1]/name", "name", tables[1]);
-        checkKeyValue("tables/table[0]@type", "type", tabTypes[0]);
-        checkKeyValue("@test", "test", "true");
+        checkAttributeValue("tables/table[0]@type", "type", tabTypes[0]);
+        checkAttributeValue("@test", "test", "true");
         checkKeyValue("connection.settings/usr.name", "usr.name", "scott");
     }
 
@@ -195,39 +234,56 @@ public class TestDefaultExpressionEngine
     @Test
     public void testNodeKey()
     {
-        ConfigurationNode node = root.getChild(0);
+        ImmutableNode node = root.getChildren().get(0);
         assertEquals("Invalid name for descendant of root", "tables", engine
-                .nodeKey(node, ""));
+                .nodeKey(node, "", handler));
         assertEquals("Parent key not respected", "test.tables", engine.nodeKey(
-                node, "test"));
+                node, "test", handler));
         assertEquals("Full parent key not taken into account",
                 "a.full.parent.key.tables", engine.nodeKey(node,
-                        "a.full.parent.key"));
+                "a.full.parent.key", handler));
     }
 
     /**
-     * Tests obtaining keys when the root node is involved.
+     * Tests obtaining keys if the root node is involved.
      */
     @Test
     public void testNodeKeyWithRoot()
     {
-        assertEquals("Wrong name for root noot", "", engine.nodeKey(root, null));
-        assertEquals("Null name not detected", "test", engine.nodeKey(root,
-                "test"));
+        assertEquals("Wrong name for root node", "",
+                engine.nodeKey(root, null, handler));
+        assertEquals("Null name not detected", "test",
+                engine.nodeKey(root, "test", handler));
     }
 
     /**
      * Tests obtaining keys for attribute nodes.
      */
     @Test
-    public void testNodeKeyWithAttribute()
+    public void testAttributeKey()
     {
-        ConfigurationNode node = root.getChild(0).getChild(0).getAttribute(0);
-        assertEquals("Wrong attribute node", "type", node.getName());
         assertEquals("Wrong attribute key", "tables.table[@type]", engine
-                .nodeKey(node, "tables.table"));
-        assertEquals("Wrong key for root attribute", "[@test]", engine.nodeKey(
-                root.getAttribute(0), ""));
+                .attributeKey("tables.table", "type"));
+    }
+
+    /**
+     * Tests whether an attribute key can be queried if the root node is involved.
+     */
+    @Test
+    public void testAttributeKeyRoot()
+    {
+        assertEquals("Wrong key for root attribute", "[@test]",
+                engine.attributeKey("", "test"));
+    }
+
+    /**
+     * Tests that a null parent key is ignored when constructing an attribute key.
+     */
+    @Test
+    public void testAttributeKeyNoParent()
+    {
+        assertEquals("Wrong key for null parent", "[@test]",
+                engine.attributeKey(null, "test"));
     }
 
     /**
@@ -236,12 +292,14 @@ public class TestDefaultExpressionEngine
     @Test
     public void testNodeKeyWithEscapedDelimiters()
     {
-        ConfigurationNode node = root.getChild(1);
-        assertEquals("Wrong escaped key", "connection..settings", engine
-                .nodeKey(node, ""));
-        assertEquals("Wrong complex escaped key",
-                "connection..settings.usr..name", engine.nodeKey(node
-                        .getChild(0), engine.nodeKey(node, "")));
+        ImmutableNode node = root.getChildren().get(1);
+        assertEquals("Wrong escaped key", "connection..settings",
+                engine.nodeKey(node, "", handler));
+        assertEquals(
+                "Wrong complex escaped key",
+                "connection..settings.usr..name",
+                engine.nodeKey(node.getChildren().get(0),
+                        engine.nodeKey(node, "", handler), handler));
     }
 
     /**
@@ -252,9 +310,19 @@ public class TestDefaultExpressionEngine
     {
         setUpAlternativeSyntax();
         assertEquals("Wrong child key", "tables/table", engine.nodeKey(root
-                .getChild(0).getChild(0), "tables"));
-        assertEquals("Wrong attribute key", "@test", engine.nodeKey(root
-                .getAttribute(0), ""));
+                .getChildren().get(0).getChildren().get(0), "tables", handler));
+    }
+
+    /**
+     * Tests whether a correct attribute key with alternative syntax is
+     * generated.
+     */
+    @Test
+    public void testAttributeKeyWithAlternativeSyntax()
+    {
+        setUpAlternativeSyntax();
+        assertEquals("Wrong attribute key", "@test",
+                engine.attributeKey("", "test"));
     }
 
     /**
@@ -272,7 +340,7 @@ public class TestDefaultExpressionEngine
                         .create();
         engine = new DefaultExpressionEngine(symbols);
         assertEquals("Wrong attribute key", "/test",
-                engine.nodeKey(root.getAttribute(0), ""));
+                engine.attributeKey("", "test"));
     }
 
     /**
@@ -281,43 +349,43 @@ public class TestDefaultExpressionEngine
     @Test
     public void testPrepareAddDirectly()
     {
-        NodeAddData data = engine.prepareAdd(root, "newNode");
+        NodeAddData<ImmutableNode> data = engine.prepareAdd(root, "newNode", handler);
         assertSame("Wrong parent node", root, data.getParent());
         assertTrue("Path nodes available", data.getPathNodes().isEmpty());
         assertEquals("Wrong name of new node", "newNode", data.getNewNodeName());
         assertFalse("New node is an attribute", data.isAttribute());
 
-        data = engine.prepareAdd(root, "tables.table.fields.field.name");
+        data = engine.prepareAdd(root, "tables.table.fields.field.name", handler);
         assertEquals("Wrong name of new node", "name", data.getNewNodeName());
         assertTrue("Path nodes available", data.getPathNodes().isEmpty());
-        assertEquals("Wrong parent node", "field", data.getParent().getName());
-        ConfigurationNode nd = data.getParent().getChild(0);
-        assertEquals("Field has no name node", "name", nd.getName());
+        assertEquals("Wrong parent node", "field", data.getParent().getNodeName());
+        ImmutableNode nd = data.getParent().getChildren().get(0);
+        assertEquals("Field has no name node", "name", nd.getNodeName());
         assertEquals("Incorrect name", "version", nd.getValue());
     }
 
     /**
-     * Tests adding when indices are involved.
+     * Tests adding if indices are involved.
      */
     @Test
     public void testPrepareAddWithIndex()
     {
-        NodeAddData data = engine
-                .prepareAdd(root, "tables.table(0).tableSpace");
+        NodeAddData<ImmutableNode> data = engine
+                .prepareAdd(root, "tables.table(0).tableSpace", handler);
         assertEquals("Wrong name of new node", "tableSpace", data
                 .getNewNodeName());
         assertTrue("Path nodes available", data.getPathNodes().isEmpty());
         assertEquals("Wrong type of parent node", "table", data.getParent()
-                .getName());
-        ConfigurationNode node = data.getParent().getChild(0);
+                .getNodeName());
+        ImmutableNode node = data.getParent().getChildren().get(0);
         assertEquals("Wrong table", tables[0], node.getValue());
 
-        data = engine.prepareAdd(root, "tables.table(1).fields.field(2).alias");
+        data = engine.prepareAdd(root, "tables.table(1).fields.field(2).alias", handler);
         assertEquals("Wrong name of new node", "alias", data.getNewNodeName());
         assertEquals("Wrong type of parent node", "field", data.getParent()
-                .getName());
+                .getNodeName());
         assertEquals("Wrong field node", "creationDate", data.getParent()
-                .getChild(0).getValue());
+                .getChildren().get(0).getValue());
     }
 
     /**
@@ -326,16 +394,23 @@ public class TestDefaultExpressionEngine
     @Test
     public void testPrepareAddAttribute()
     {
-        NodeAddData data = engine.prepareAdd(root,
-                "tables.table(0)[@tableSpace]");
+        NodeAddData<ImmutableNode> data = engine.prepareAdd(root,
+                "tables.table(0)[@tableSpace]", handler);
         assertEquals("Wrong table node", tables[0], data.getParent()
-                .getChild(0).getValue());
+                .getChildren().get(0).getValue());
         assertEquals("Wrong name of new node", "tableSpace", data
                 .getNewNodeName());
         assertTrue("Attribute not detected", data.isAttribute());
         assertTrue("Path nodes available", data.getPathNodes().isEmpty());
+    }
 
-        data = engine.prepareAdd(root, "[@newAttr]");
+    /**
+     * Tests whether an attribute to the root node can be added.
+     */
+    @Test
+    public void testPrepareAddAttributeRoot()
+    {
+        NodeAddData<ImmutableNode> data = engine.prepareAdd(root, "[@newAttr]", handler);
         assertSame("Root node is not parent", root, data.getParent());
         assertEquals("Wrong name of new node", "newAttr", data.getNewNodeName());
         assertTrue("Attribute not detected", data.isAttribute());
@@ -347,25 +422,22 @@ public class TestDefaultExpressionEngine
     @Test
     public void testPrepareAddWithPath()
     {
-        NodeAddData data = engine.prepareAdd(root,
-                "tables.table(1).fields.field(-1).name");
+        NodeAddData<ImmutableNode> data = engine.prepareAdd(root,
+                "tables.table(1).fields.field(-1).name", handler);
         assertEquals("Wrong name of new node", "name", data.getNewNodeName());
-        checkNodePath(data, new String[]
-        { "field"});
+        checkNodePath(data, "field");
         assertEquals("Wrong type of parent node", "fields", data.getParent()
-                .getName());
+                .getNodeName());
 
-        data = engine.prepareAdd(root, "tables.table(-1).name");
+        data = engine.prepareAdd(root, "tables.table(-1).name", handler);
         assertEquals("Wrong name of new node", "name", data.getNewNodeName());
-        checkNodePath(data, new String[]
-        { "table"});
+        checkNodePath(data, "table");
         assertEquals("Wrong type of parent node", "tables", data.getParent()
-                .getName());
+                .getNodeName());
 
-        data = engine.prepareAdd(root, "a.complete.new.path");
+        data = engine.prepareAdd(root, "a.complete.new.path", handler);
         assertEquals("Wrong name of new node", "path", data.getNewNodeName());
-        checkNodePath(data, new String[]
-        { "a", "complete", "new"});
+        checkNodePath(data, "a", "complete", "new");
         assertSame("Root is not parent", root, data.getParent());
     }
 
@@ -385,16 +457,16 @@ public class TestDefaultExpressionEngine
                                         .getPropertyDelimiter()).create();
         engine = new DefaultExpressionEngine(symbols);
 
-        NodeAddData data = engine.prepareAdd(root, "tables.table(0).test");
+        NodeAddData<ImmutableNode> data =
+                engine.prepareAdd(root, "tables.table(0).test", handler);
         assertEquals("Wrong name of new node", "test", data.getNewNodeName());
         assertFalse("New node is an attribute", data.isAttribute());
         assertEquals("Wrong type of parent node", "table", data.getParent()
-                .getName());
+                .getNodeName());
 
-        data = engine.prepareAdd(root, "a.complete.new.path");
+        data = engine.prepareAdd(root, "a.complete.new.path", handler);
         assertFalse("New node is an attribute", data.isAttribute());
-        checkNodePath(data, new String[]
-        { "a", "complete", "new"});
+        checkNodePath(data, "a", "complete", "new");
     }
 
     /**
@@ -404,17 +476,17 @@ public class TestDefaultExpressionEngine
     public void testPrepareAddWithAlternativeSyntax()
     {
         setUpAlternativeSyntax();
-        NodeAddData data = engine.prepareAdd(root, "tables/table[0]/test");
+        NodeAddData<ImmutableNode> data =
+                engine.prepareAdd(root, "tables/table[0]/test", handler);
         assertEquals("Wrong name of new node", "test", data.getNewNodeName());
         assertFalse("New node is attribute", data.isAttribute());
-        assertEquals("Wrong parent node", tables[0], data.getParent().getChild(
-                0).getValue());
+        assertEquals("Wrong parent node", tables[0], data.getParent()
+                .getChildren().get(0).getValue());
 
-        data = engine.prepareAdd(root, "a/complete/new/path@attr");
+        data = engine.prepareAdd(root, "a/complete/new/path@attr", handler);
         assertEquals("Wrong name of new attribute", "attr", data
                 .getNewNodeName());
-        checkNodePath(data, new String[]
-        { "a", "complete", "new", "path"});
+        checkNodePath(data, "a", "complete", "new", "path");
         assertSame("Root is not parent", root, data.getParent());
     }
 
@@ -425,27 +497,88 @@ public class TestDefaultExpressionEngine
     @Test(expected = IllegalArgumentException.class)
     public void testPrepareAddInvalidKey()
     {
-        engine.prepareAdd(root, "tables.table(0)[@type].new");
+        engine.prepareAdd(root, "tables.table(0)[@type].new", handler);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testPrepareAddInvalidKeyAttribute()
     {
-        engine
-        .prepareAdd(root,
-                "a.complete.new.path.with.an[@attribute].at.a.non.allowed[@position]");
+        engine.prepareAdd(
+                root,
+                "a.complete.new.path.with.an[@attribute].at.a.non.allowed[@position]",
+                handler);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testPrepareAddNullKey()
     {
-        engine.prepareAdd(root, null);
+        engine.prepareAdd(root, null, handler);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testPrepareAddEmptyKey()
     {
-        engine.prepareAdd(root, "");
+        engine.prepareAdd(root, "", handler);
+    }
+
+    /**
+     * Tests whether a canonical key can be queried if all child nodes have
+     * different names.
+     */
+    @Test
+    public void testCanonicalKeyNoDuplicates()
+    {
+        ImmutableNode node = fetchNode("tables.table(0).name");
+        assertEquals("Wrong canonical key", "table.name(0)",
+                engine.canonicalKey(node, "table", handler));
+    }
+
+    /**
+     * Tests whether duplicates are correctly resolved when querying for
+     * canonical keys.
+     */
+    @Test
+    public void testCanonicalKeyWithDuplicates()
+    {
+        ImmutableNode tab1 = fetchNode("tables.table(0)");
+        ImmutableNode tab2 = fetchNode("tables.table(1)");
+        assertEquals("Wrong key 1", "tables.table(0)",
+                engine.canonicalKey(tab1, "tables", handler));
+        assertEquals("Wrong key 2", "tables.table(1)",
+                engine.canonicalKey(tab2, "tables", handler));
+    }
+
+    /**
+     * Tests whether the parent key can be undefined when querying a canonical
+     * key.
+     */
+    @Test
+    public void testCanonicalKeyNoParentKey()
+    {
+        ImmutableNode node = fetchNode("tables.table(0).fields.field(1).name");
+        assertEquals("Wrong key", "name(0)",
+                engine.canonicalKey(node, null, handler));
+    }
+
+    /**
+     * Tests whether a canonical key for the parent node can be queried if no
+     * parent key was passed in.
+     */
+    @Test
+    public void testCanonicalKeyRootNoParentKey()
+    {
+        assertEquals("Wrong key", "", engine.canonicalKey(root, null, handler));
+    }
+
+    /**
+     * Tests whether a parent key is evaluated when determining the canonical
+     * key of the root node.
+     */
+    @Test
+    public void testCanonicalKeyRootWithParentKey()
+    {
+        assertEquals("Wrong key", "parent",
+                engine.canonicalKey(root, "parent", handler));
     }
 
     /**
@@ -465,39 +598,41 @@ public class TestDefaultExpressionEngine
      *
      * @return the root of the test node hierarchy
      */
-    protected ConfigurationNode setUpNodes()
+    private static ImmutableNode setUpNodes()
     {
-        DefaultConfigurationNode rootNode = new DefaultConfigurationNode();
-
-        DefaultConfigurationNode nodeTables = new DefaultConfigurationNode(
-                "tables");
-        rootNode.addChild(nodeTables);
+        ImmutableNode.Builder nodeTablesBuilder =
+                new ImmutableNode.Builder(tables.length);
+        nodeTablesBuilder.name("tables");
         for (int i = 0; i < tables.length; i++)
         {
-            DefaultConfigurationNode nodeTable = new DefaultConfigurationNode(
-                    "table");
-            nodeTables.addChild(nodeTable);
-            nodeTable.addChild(new DefaultConfigurationNode("name", tables[i]));
-            nodeTable.addAttribute(new DefaultConfigurationNode("type",
-                    tabTypes[i]));
-            DefaultConfigurationNode nodeFields = new DefaultConfigurationNode(
-                    "fields");
-            nodeTable.addChild(nodeFields);
+            ImmutableNode.Builder nodeTableBuilder =
+                    new ImmutableNode.Builder(2);
+            nodeTableBuilder.name("table");
+            nodeTableBuilder.addChild(new ImmutableNode.Builder().name("name")
+                    .value(tables[i]).create());
+            nodeTableBuilder.addAttribute("type", tabTypes[i]);
 
+            ImmutableNode.Builder nodeFieldsBuilder =
+                    new ImmutableNode.Builder(fields[i].length);
             for (int j = 0; j < fields[i].length; j++)
             {
-                nodeFields.addChild(createFieldNode(fields[i][j]));
+                nodeFieldsBuilder.addChild(createFieldNode(fields[i][j]));
             }
+            nodeTableBuilder
+                    .addChild(nodeFieldsBuilder.name("fields").create());
+            nodeTablesBuilder.addChild(nodeTableBuilder.create());
         }
 
-        DefaultConfigurationNode nodeConn = new DefaultConfigurationNode(
-                "connection.settings");
-        rootNode.addChild(nodeConn);
-        nodeConn.addChild(new DefaultConfigurationNode("usr.name", "scott"));
-        nodeConn.addChild(new DefaultConfigurationNode("usr.pwd", "tiger"));
-        rootNode.addAttribute(new DefaultConfigurationNode("test", "true"));
+        ImmutableNode.Builder rootBuilder = new ImmutableNode.Builder();
+        rootBuilder.addChild(nodeTablesBuilder.create());
+        ImmutableNode.Builder nodeConnBuilder = new ImmutableNode.Builder();
+        nodeConnBuilder.name("connection.settings");
+        nodeConnBuilder.addChild(createNode("usr.name", "scott"));
+        nodeConnBuilder.addChild(createNode("usr.pwd", "tiger"));
+        rootBuilder.addAttribute("test", "true");
+        rootBuilder.addChild(nodeConnBuilder.create());
 
-        return rootNode;
+        return rootBuilder.create();
     }
 
     /**
@@ -522,20 +657,55 @@ public class TestDefaultExpressionEngine
      * @param count the number of expected result nodes
      * @return the list with the results of the query
      */
-    private List<ConfigurationNode> checkKey(String key, String name, int count)
+    private List<QueryResult<ImmutableNode>> checkKey(String key, String name,
+            int count)
     {
-        List<ConfigurationNode> nodes = engine.query(root, key);
-        assertEquals("Wrong number of result nodes for key " + key, count,
-                nodes.size());
-        for (Iterator<ConfigurationNode> it = nodes.iterator(); it.hasNext();)
+        List<QueryResult<ImmutableNode>> nodes = query(key, count);
+        for (QueryResult<ImmutableNode> result : nodes)
         {
-            assertEquals("Wrong result node for key " + key, name,
-                    it.next().getName());
+            if (result.isAttributeResult())
+            {
+                assertEquals("Wrong attribute name for key " + key, name,
+                        result.getAttributeName());
+            }
+            else
+            {
+                assertEquals("Wrong result node for key " + key, name, result
+                        .getNode().getNodeName());
+            }
         }
         return nodes;
     }
 
     /**
+     * Helper method for querying the test engine for a specific key.
+     *
+     * @param key the key
+     * @param expCount the expected number of result nodes
+     * @return the collection of retrieved nodes
+     */
+    private List<QueryResult<ImmutableNode>> query(String key, int expCount)
+    {
+        List<QueryResult<ImmutableNode>> nodes = engine.query(root, key, handler);
+        assertEquals("Wrong number of result nodes for key " + key, expCount,
+                nodes.size());
+        return nodes;
+    }
+
+    /**
+     * Helper method for fetching a specific node by its key.
+     *
+     * @param key the key
+     * @return the node with this key
+     */
+    private ImmutableNode fetchNode(String key)
+    {
+        QueryResult<ImmutableNode> result = query(key, 1).get(0);
+        assertFalse("An attribute result", result.isAttributeResult());
+        return result.getNode();
+    }
+
+    /**
      * Helper method for checking the value of a node specified by the given
      * key. This method evaluates the key and checks whether the resulting node
      * has the expected value.
@@ -546,9 +716,28 @@ public class TestDefaultExpressionEngine
      */
     private void checkKeyValue(String key, String name, String value)
     {
-        List<ConfigurationNode> nodes = checkKey(key, name, 1);
+        List<QueryResult<ImmutableNode>> results = checkKey(key, name, 1);
+        QueryResult<ImmutableNode> result = results.get(0);
+        assertFalse("No node result", result.isAttributeResult());
         assertEquals("Wrong value for key " + key, value,
-                nodes.get(0).getValue());
+                result.getNode().getValue());
+    }
+
+    /**
+     * Helper method for checking whether an attribute key is correctly
+     * evaluated.
+     *
+     * @param key the attribute key
+     * @param attr the attribute name
+     * @param expValue the expected attribute value
+     */
+    private void checkAttributeValue(String key, String attr, Object expValue)
+    {
+        List<QueryResult<ImmutableNode>> results = checkKey(key, attr, 1);
+        QueryResult<ImmutableNode> result = results.get(0);
+        assertTrue("Not an attribute result", result.isAttributeResult());
+        assertEquals("Wrong attribute value for key " + key, expValue,
+                result.getAttributeValue(handler));
     }
 
     /**
@@ -557,7 +746,8 @@ public class TestDefaultExpressionEngine
      * @param data the add data object
      * @param expected the expected path nodes
      */
-    private void checkNodePath(NodeAddData data, String[] expected)
+    private void checkNodePath(NodeAddData<ImmutableNode> data,
+            String... expected)
     {
         assertEquals("Wrong number of path nodes", expected.length, data
                 .getPathNodes().size());
@@ -575,11 +765,22 @@ public class TestDefaultExpressionEngine
      * @param name the name of the field
      * @return the field node
      */
-    private static ConfigurationNode createFieldNode(String name)
+    private static ImmutableNode createFieldNode(String name)
+    {
+        ImmutableNode.Builder nodeFieldBuilder = new ImmutableNode.Builder(1);
+        nodeFieldBuilder.addChild(createNode("name", name));
+        return nodeFieldBuilder.name("field").create();
+    }
+
+    /**
+     * Convenience method for creating a simple node with a name and a value.
+     *
+     * @param name the node name
+     * @param value the node value
+     * @return the node instance
+     */
+    private static ImmutableNode createNode(String name, Object value)
     {
-        DefaultConfigurationNode nodeField = new DefaultConfigurationNode(
-                "field");
-        nodeField.addChild(new DefaultConfigurationNode("name", name));
-        return nodeField;
+        return new ImmutableNode.Builder().name(name).value(value).create();
     }
 }



Mime
View raw message