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/23 21:31:35 UTC
svn commit: r1580594 - in
/commons/proper/configuration/branches/immutableNodes/src:
main/java/org/apache/commons/configuration/tree/InMemoryNodeModel.java
test/java/org/apache/commons/configuration/tree/TestInMemoryNodeModelTrackedNodes.java
Author: oheger
Date: Sun Mar 23 20:31:34 2014
New Revision: 1580594
URL: http://svn.apache.org/r1580594
Log:
Added trackChildNodeWithCreation() method to InMemoryNodeModel.
This method allows tracking a child node of a selected node. If the child does
not exist, it is created dynamically.
Modified:
commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/tree/InMemoryNodeModel.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=1580594&r1=1580593&r2=1580594&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 Sun Mar 23 20:31:34 2014
@@ -489,6 +489,48 @@ public class InMemoryNodeModel implement
}
/**
+ * Tracks a node which is a child of another node selected by the passed in
+ * key. If the selected node has a child node with this name, it is tracked
+ * and its selector is returned. Otherwise, a new child node with this name
+ * is created first.
+ *
+ * @param key the key for selecting the parent node
+ * @param childName the name of the child node
+ * @param resolver the {@code NodeKeyResolver}
+ * @return the {@code NodeSelector} for the tracked child node
+ * @throws ConfigurationRuntimeException if the passed in key does not
+ * select a single node
+ */
+ public NodeSelector trackChildNodeWithCreation(String key,
+ String childName, NodeKeyResolver<ImmutableNode> resolver)
+ {
+ MutableObject<NodeSelector> refSelector =
+ new MutableObject<NodeSelector>();
+ boolean done;
+
+ do
+ {
+ TreeData current = structure.get();
+ List<ImmutableNode> nodes =
+ resolver.resolveNodeKey(current.getRootNode(), key, current);
+ if (nodes.size() != 1)
+ {
+ throw new ConfigurationRuntimeException(
+ "Key does not select a single node: " + key);
+ }
+
+ ImmutableNode parent = nodes.get(0);
+ TreeData newData =
+ createDataWithTrackedChildNode(current, parent, childName,
+ resolver, refSelector);
+
+ done = structure.compareAndSet(current, newData);
+ } while (!done);
+
+ return refSelector.getValue();
+ }
+
+ /**
* Returns the current {@code ImmutableNode} instance associated with the
* given {@code NodeSelector}. The node must be a tracked node, i.e.
* {@link #trackNode(NodeSelector, NodeKeyResolver)} must have been called
@@ -1079,6 +1121,72 @@ public class InMemoryNodeModel implement
}
/**
+ * Adds a tracked node that has already been resolved to the specified data
+ * object.
+ *
+ * @param current the current {@code TreeData} object
+ * @param node the node in question
+ * @param resolver the {@code NodeKeyResolver}
+ * @param refSelector here the newly created {@code NodeSelector} is
+ * returned
+ * @return the new {@code TreeData} instance
+ */
+ private static TreeData updateDataWithNewTrackedNode(TreeData current,
+ ImmutableNode node, NodeKeyResolver<ImmutableNode> resolver,
+ MutableObject<NodeSelector> refSelector)
+ {
+ NodeSelector selector =
+ new NodeSelector(resolver.nodeKey(node,
+ new HashMap<ImmutableNode, String>(), current));
+ refSelector.setValue(selector);
+ NodeTracker newTracker =
+ current.getNodeTracker().trackNodes(
+ Collections.singleton(selector),
+ Collections.singleton(node));
+ return current.updateNodeTracker(newTracker);
+ }
+
+ /**
+ * Creates a new data object with a tracked child node of the given parent
+ * node. If such a child node already exists, it is used. Otherwise, a new
+ * one is created.
+ *
+ * @param current the current {@code TreeData} object
+ * @param parent the parent node
+ * @param childName the name of the child node
+ * @param resolver the {@code NodeKeyResolver}
+ * @param refSelector here the newly created {@code NodeSelector} is
+ * returned
+ * @return the new {@code TreeData} instance
+ */
+ private static TreeData createDataWithTrackedChildNode(TreeData current,
+ ImmutableNode parent, String childName,
+ NodeKeyResolver<ImmutableNode> resolver,
+ MutableObject<NodeSelector> refSelector)
+ {
+ TreeData newData;
+ List<ImmutableNode> namedChildren =
+ current.getChildren(parent, childName);
+ if (!namedChildren.isEmpty())
+ {
+ newData =
+ updateDataWithNewTrackedNode(current, namedChildren.get(0),
+ resolver, refSelector);
+ }
+ else
+ {
+ ImmutableNode child =
+ new ImmutableNode.Builder().name(childName).create();
+ ModelTransaction tx = new ModelTransaction(current, null, resolver);
+ tx.addAddNodeOperation(parent, child);
+ newData =
+ updateDataWithNewTrackedNode(tx.execute(), child, resolver,
+ refSelector);
+ }
+ return newData;
+ }
+
+ /**
* Checks whether the specified collection with values is not empty.
*
* @param values the collection with node values
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=1580594&r1=1580593&r2=1580594&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 Sun Mar 23 20:31:34 2014
@@ -20,10 +20,12 @@ import static org.junit.Assert.assertEqu
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -922,4 +924,105 @@ public class TestInMemoryNodeModelTracke
.singletonList(NodeStructureHelper.nodeForKey(root,
"tables/table(0)/name")));
}
+
+ /**
+ * Tests whether an existing child of a selected node can be tracked.
+ */
+ @Test
+ public void testTrackChildNodeWithCreationExisting()
+ {
+ NodeKeyResolver<ImmutableNode> resolver = createResolver(false);
+ String childName = "name";
+ String parentKey = "tables/table(0)";
+ String childKey = parentKey + "/" + childName;
+ ImmutableNode node = NodeStructureHelper.nodeForKey(model, parentKey);
+ ImmutableNode child = NodeStructureHelper.nodeForKey(node, childName);
+ EasyMock.expect(
+ resolver.resolveNodeKey(root, TEST_KEY, model.getNodeHandler()))
+ .andReturn(Collections.singletonList(node));
+ expectNodeKey(resolver, child, childKey);
+ EasyMock.replay(resolver);
+
+ NodeSelector childSelector =
+ model.trackChildNodeWithCreation(TEST_KEY, childName, resolver);
+ assertEquals("Wrong selector", new NodeSelector(childKey),
+ childSelector);
+ assertSame("Wrong tracked node", child,
+ model.getTrackedNode(childSelector));
+ }
+
+ /**
+ * Tests whether a child node to be tracked is created if necessary.
+ */
+ @Test
+ public void testTrackChildNodeWithCreationNonExisting()
+ {
+ NodeKeyResolver<ImmutableNode> resolver = createResolver(false);
+ String childName = "space";
+ String parentKey = "tables/table(0)";
+ String childKey = parentKey + "/" + childName;
+ ImmutableNode node = NodeStructureHelper.nodeForKey(model, parentKey);
+ EasyMock.expect(
+ resolver.resolveNodeKey(root, TEST_KEY, model.getNodeHandler()))
+ .andReturn(Collections.singletonList(node));
+ EasyMock.expect(
+ resolver.nodeKey(EasyMock.anyObject(ImmutableNode.class),
+ EasyMock.eq(new HashMap<ImmutableNode, String>()),
+ EasyMock.anyObject(TreeData.class)))
+ .andReturn(childKey);
+ EasyMock.replay(resolver);
+
+ NodeSelector childSelector =
+ model.trackChildNodeWithCreation(TEST_KEY, childName, resolver);
+ assertEquals("Wrong selector", new NodeSelector(childKey),
+ childSelector);
+ ImmutableNode child = model.getTrackedNode(childSelector);
+ assertEquals("Wrong child name", childName, child.getNodeName());
+ assertNull("Got a value", child.getValue());
+ ImmutableNode parent = model.getNodeHandler().getParent(child);
+ assertEquals("Wrong parent node", "table", parent.getNodeName());
+ assertEquals("Wrong node path", child,
+ NodeStructureHelper.nodeForKey(model, childKey));
+ }
+
+ /**
+ * Helper method for testing trackChildNodeWithCreation() if invalid query
+ * results are generated.
+ *
+ * @param queryResult the result set of the key
+ */
+ private void checkTrackChildNodeWithCreationInvalidKey(
+ List<ImmutableNode> queryResult)
+ {
+ NodeKeyResolver<ImmutableNode> resolver = createResolver(false);
+ EasyMock.expect(
+ resolver.resolveNodeKey(model.getRootNode(), TEST_KEY,
+ model.getNodeHandler())).andReturn(queryResult);
+ EasyMock.replay(resolver);
+ model.trackChildNodeWithCreation(TEST_KEY, "someChild", resolver);
+ }
+
+ /**
+ * Tests trackChildNodeWithCreation() if the passed in key does not select a
+ * node.
+ */
+ @Test(expected = ConfigurationRuntimeException.class)
+ public void testTrackChildNodeWithCreationNoResults()
+ {
+ checkTrackChildNodeWithCreationInvalidKey(new ArrayList<ImmutableNode>());
+ }
+
+ /**
+ * Tests trackChildNodeWithCreation() if the passed in key selects multiple
+ * nodes.
+ */
+ @Test(expected = ConfigurationRuntimeException.class)
+ public void testTrackChildNodeWithCreationMultipleResults()
+ {
+ List<ImmutableNode> nodes =
+ Arrays.asList(
+ NodeStructureHelper.nodeForKey(root, "tables/table(0)"),
+ NodeStructureHelper.nodeForKey(root, "tables/table(1)"));
+ checkTrackChildNodeWithCreationInvalidKey(nodes);
+ }
}