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/03/17 22:08:34 UTC

svn commit: r1578574 - in /commons/proper/configuration/branches/immutableNodes/src: main/java/org/apache/commons/configuration/tree/ test/java/org/apache/commons/configuration/tree/

Author: oheger
Date: Mon Mar 17 21:08:34 2014
New Revision: 1578574

URL: http://svn.apache.org/r1578574
Log:
Added a replaceTrackedNode() method to InMemoryNodeModel.

This method is useful when working on sub trees of the model. It is then
possible to detach a whole sub tree and to replace its root node.

Modified:
    commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/InMemoryNodeModel.java
    commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/NodeTracker.java
    commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/tree/TestInMemoryNodeModelTrackedNodes.java

Modified: commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/InMemoryNodeModel.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/InMemoryNodeModel.java?rev=1578574&r1=1578573&r2=1578574&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/InMemoryNodeModel.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/InMemoryNodeModel.java Mon Mar 17 21:08:34 2014
@@ -412,6 +412,38 @@ public class InMemoryNodeModel implement
     }
 
     /**
+     * Replaces a tracked node by another node. If the tracked node is not yet
+     * detached, it becomes now detached. The passed in node (which must not be
+     * <b>null</b>) becomes the new root node of an independent model for this
+     * tracked node. Further updates of this model do not affect the tracked
+     * node's model and vice versa.
+     *
+     * @param selector the {@code NodeSelector} defining the tracked node
+     * @param newNode the node replacing the tracked node (must not be
+     *        <b>null</b>)
+     * @throws ConfigurationRuntimeException if the selector cannot be resolved
+     * @throws IllegalArgumentException if the replacement node is <b>null</b>
+     */
+    public void replaceTrackedNode(NodeSelector selector, ImmutableNode newNode)
+    {
+        if (newNode == null)
+        {
+            throw new IllegalArgumentException(
+                    "Replacement node must not be null!");
+        }
+
+        boolean done;
+        do
+        {
+            TreeData currentData = structure.get();
+            done =
+                    replaceDetachedTrackedNode(currentData, selector, newNode)
+                            || replaceActiveTrackedNode(currentData, selector,
+                                    newNode);
+        } while (!done);
+    }
+
+    /**
      * Returns a {@code NodeHandler} for a tracked node. Such a handler may be
      * required for operations on a sub tree of the model. The handler to be
      * returned depends on the current state of the tracked node. If it is still
@@ -886,6 +918,46 @@ public class InMemoryNodeModel implement
     }
 
     /**
+     * Replaces a tracked node if it is already detached.
+     *
+     * @param currentData the current data of the model
+     * @param selector the {@code NodeSelector} defining the tracked node
+     * @param newNode the node replacing the tracked node
+     * @return a flag whether the operation was successful
+     */
+    private boolean replaceDetachedTrackedNode(TreeData currentData,
+            NodeSelector selector, ImmutableNode newNode)
+    {
+        InMemoryNodeModel detachedNodeModel =
+                currentData.getNodeTracker().getDetachedNodeModel(selector);
+        if (detachedNodeModel != null)
+        {
+            detachedNodeModel.setRootNode(newNode);
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Replaces an active tracked node. The node then becomes detached.
+     *
+     * @param currentData the current data of the model
+     * @param selector the {@code NodeSelector} defining the tracked node
+     * @param newNode the node replacing the tracked node
+     * @return a flag whether the operation was successful
+     */
+    private boolean replaceActiveTrackedNode(TreeData currentData,
+            NodeSelector selector, ImmutableNode newNode)
+    {
+        NodeTracker newTracker =
+                currentData.getNodeTracker().replaceAndDetachTrackedNode(
+                        selector, newNode);
+        return structure.compareAndSet(currentData,
+                currentData.updateNodeTracker(newTracker));
+    }
+
+    /**
      * Checks whether the specified collection with values is not empty.
      *
      * @param values the collection with node values

Modified: commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/NodeTracker.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/NodeTracker.java?rev=1578574&r1=1578573&r2=1578574&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/NodeTracker.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/NodeTracker.java Mon Mar 17 21:08:34 2014
@@ -258,6 +258,24 @@ class NodeTracker
     }
 
     /**
+     * Replaces a tracked node by another one. This operation causes the tracked
+     * node to become detached.
+     *
+     * @param selector the {@code NodeSelector}
+     * @param newNode the replacement node
+     * @return the updated instance
+     * @throws ConfigurationRuntimeException if the selector cannot be resolved
+     */
+    public NodeTracker replaceAndDetachTrackedNode(NodeSelector selector,
+            ImmutableNode newNode)
+    {
+        Map<NodeSelector, TrackedNodeData> newState =
+                new HashMap<NodeSelector, TrackedNodeData>(trackedNodes);
+        newState.put(selector, getTrackedNodeData(selector).detach(newNode));
+        return new NodeTracker(newState);
+    }
+
+    /**
      * Obtains the {@code TrackedNodeData} object for the specified selector. If
      * the selector cannot be resolved, an exception is thrown.
      *

Modified: commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/tree/TestInMemoryNodeModelTrackedNodes.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/tree/TestInMemoryNodeModelTrackedNodes.java?rev=1578574&r1=1578573&r2=1578574&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/tree/TestInMemoryNodeModelTrackedNodes.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/tree/TestInMemoryNodeModelTrackedNodes.java Mon Mar 17 21:08:34 2014
@@ -594,7 +594,7 @@ public class TestInMemoryNodeModelTracke
     {
         assertEquals("Wrong number of field nodes",
                 NodeStructureHelper.fieldsLength(1), nodeFields.getChildren()
-                        .size());
+                .size());
         int childIndex = 0;
         for (ImmutableNode field : nodeFields.getChildren())
         {
@@ -693,4 +693,49 @@ public class TestInMemoryNodeModelTracke
         assertTrue("Wrong handler: " + handler, handler instanceof TreeData);
         assertNotSame("Shared handler", model.getNodeHandler(), handler);
     }
+
+    /**
+     * Helper method for testing whether a tracked node can be replaced.
+     */
+    private void checkReplaceTrackedNode()
+    {
+        ImmutableNode newNode =
+                new ImmutableNode.Builder().name("newNode").create();
+        model.replaceTrackedNode(selector, newNode);
+        assertSame("Node not changed", newNode, model.getTrackedNode(selector));
+        assertTrue("Node not detached", model.isTrackedNodeDetached(selector));
+    }
+
+    /**
+     * Tests whether an active tracked node can be replaced.
+     */
+    @Test
+    public void testReplaceTrackedNodeForActiveTrackedNode()
+    {
+        NodeKeyResolver<ImmutableNode> resolver = createResolver();
+        model.trackNode(selector, resolver);
+        checkReplaceTrackedNode();
+    }
+
+    /**
+     * Tests whether a detached tracked node can be replaced.
+     */
+    @Test
+    public void testReplaceTrackedNodeForDetachedNode()
+    {
+        NodeKeyResolver<ImmutableNode> resolver = createResolver();
+        model.trackNode(selector, resolver);
+        initDetachedNode(resolver);
+        checkReplaceTrackedNode();
+    }
+
+    /**
+     * Tries to replace a tracked node with a null node.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testReplaceTrackedNodeNull()
+    {
+        model.trackNode(selector, createResolver());
+        model.replaceTrackedNode(selector, null);
+    }
 }