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/09 22:04:20 UTC
svn commit: r1575767 - 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 9 21:04:20 2014
New Revision: 1575767
URL: http://svn.apache.org/r1575767
Log:
InMemoryNodeModel now supports addProperty() on a tracked node.
The implementation is analogous to other operations on tracked nodes.
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=1575767&r1=1575766&r2=1575767&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 9 21:04:20 2014
@@ -104,17 +104,39 @@ public class InMemoryNodeModel implement
return getTreeData();
}
- public void addProperty(final String key, final Iterable<?> values,
+ public void addProperty(String key, Iterable<?> values,
+ NodeKeyResolver<ImmutableNode> resolver)
+ {
+ addProperty(key, null, values, resolver);
+ }
+
+ /**
+ * Adds new property values using a tracked node as root node. This method
+ * works like the normal {@code addProperty()} method, but the origin of the
+ * operation (also for the interpretation of the passed in key) is a tracked
+ * node identified by the passed in {@code NodeSelector}. The selector can
+ * be <b>null</b>, then the root node is assumed.
+ *
+ * @param key the key
+ * @param selector the {@code NodeSelector} defining the root node (or
+ * <b>null</b>)
+ * @param resolver the {@code NodeKeyResolver}
+ * @throws ConfigurationRuntimeException if the selector cannot be resolved
+ */
+ public void addProperty(final String key, NodeSelector selector,
+ final Iterable<?> values,
final NodeKeyResolver<ImmutableNode> resolver)
{
if (valuesNotEmpty(values))
{
- updateModel(new TransactionInitializer() {
- public boolean initTransaction(ModelTransaction tx) {
+ updateModel(new TransactionInitializer()
+ {
+ public boolean initTransaction(ModelTransaction tx)
+ {
initializeAddTransaction(tx, key, values, resolver);
return true;
}
- }, null, resolver);
+ }, selector, resolver);
}
}
@@ -164,17 +186,14 @@ public class InMemoryNodeModel implement
public void setProperty(final String key, final Object value,
final NodeKeyResolver<ImmutableNode> resolver)
{
- updateModel(new TransactionInitializer()
- {
- public boolean initTransaction(ModelTransaction tx)
- {
+ updateModel(new TransactionInitializer() {
+ public boolean initTransaction(ModelTransaction tx) {
boolean added = false;
NodeUpdateData<ImmutableNode> updateData =
resolver.resolveUpdateKey(
tx.getCurrentData().getRootNode(), key, value,
tx.getCurrentData());
- if (!updateData.getNewValues().isEmpty())
- {
+ if (!updateData.getNewValues().isEmpty()) {
initializeAddTransaction(tx, key,
updateData.getNewValues(), resolver);
added = true;
@@ -211,27 +230,21 @@ public class InMemoryNodeModel implement
* @param selector the {@code NodeSelector} defining the root node (or
* <b>null</b>)
* @param resolver the {@code NodeKeyResolver}
+ * @throws ConfigurationRuntimeException if the selector cannot be resolved
*/
public void clearTree(final String key, NodeSelector selector,
final NodeKeyResolver<ImmutableNode> resolver)
{
- updateModel(new TransactionInitializer()
- {
- public boolean initTransaction(ModelTransaction tx)
- {
+ updateModel(new TransactionInitializer() {
+ public boolean initTransaction(ModelTransaction tx) {
TreeData currentStructure = tx.getCurrentData();
for (QueryResult<ImmutableNode> result : resolver.resolveKey(
- tx.getQueryRoot(), key, currentStructure))
- {
- if (result.isAttributeResult())
- {
+ tx.getQueryRoot(), key, currentStructure)) {
+ if (result.isAttributeResult()) {
tx.addRemoveAttributeOperation(result.getNode(),
result.getAttributeName());
- }
- else
- {
- if (result.getNode() == currentStructure.getRootNode())
- {
+ } else {
+ if (result.getNode() == currentStructure.getRootNode()) {
// the whole model is to be cleared
clear();
return false;
@@ -464,7 +477,7 @@ public class InMemoryNodeModel implement
Iterable<?> values, NodeKeyResolver<ImmutableNode> resolver)
{
NodeAddData<ImmutableNode> addData =
- resolver.resolveAddKey(tx.getCurrentData().getRootNode(), key,
+ resolver.resolveAddKey(tx.getQueryRoot(), key,
tx.getCurrentData());
if (addData.isAttribute())
{
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=1575767&r1=1575766&r2=1575767&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 9 21:04:20 2014
@@ -23,11 +23,13 @@ import static org.junit.Assert.assertSam
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.configuration.ex.ConfigurationRuntimeException;
import org.easymock.EasyMock;
+import org.easymock.IAnswer;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -40,6 +42,9 @@ import org.junit.Test;
*/
public class TestInMemoryNodeModelTrackedNodes
{
+ /** Constant for the name of a new table field. */
+ private static final String NEW_FIELD = "newTableField";
+
/** The root node for the test hierarchy. */
private static ImmutableNode root;
@@ -72,10 +77,26 @@ public class TestInMemoryNodeModelTracke
*/
private static NodeKeyResolver<ImmutableNode> createResolver()
{
+ return createResolver(true);
+ }
+
+ /**
+ * Creates a default resolver which supports arbitrary queries on a target
+ * node and allows specifying the replay flag. If the boolean parameter is
+ * false, the mock is not replayed; so additional behaviors can be defined.
+ *
+ * @param replay the replay flag
+ * @return the resolver mock
+ */
+ private static NodeKeyResolver<ImmutableNode> createResolver(boolean replay)
+ {
NodeKeyResolver<ImmutableNode> resolver =
NodeStructureHelper.createResolverMock();
NodeStructureHelper.expectResolveKeyForQueries(resolver);
- EasyMock.replay(resolver);
+ if (replay)
+ {
+ EasyMock.replay(resolver);
+ }
return resolver;
}
@@ -293,6 +314,27 @@ public class TestInMemoryNodeModelTracke
}
/**
+ * Returns the fields node from the model.
+ *
+ * @return the fields node
+ */
+ private ImmutableNode fieldsNodeFromModel()
+ {
+ return NodeStructureHelper.nodeForKey(model, "tables/table(1)/fields");
+ }
+
+ /**
+ * Returns the fields node from a tracked node.
+ *
+ * @return the fields node
+ */
+ private ImmutableNode fieldsNodeFromTrackedNode()
+ {
+ return NodeStructureHelper.nodeForKey(model.getTrackedNode(selector),
+ "fields");
+ }
+
+ /**
* Helper method for checking whether the expected field node was removed.
*
* @param nodeFields the fields node
@@ -329,8 +371,7 @@ public class TestInMemoryNodeModelTracke
NodeKeyResolver<ImmutableNode> resolver = createResolver();
model.trackNode(selector, resolver);
model.clearProperty("fields.field(0).name", selector, resolver);
- ImmutableNode nodeFields =
- NodeStructureHelper.nodeForKey(model, "tables/table(1)/fields");
+ ImmutableNode nodeFields = fieldsNodeFromModel();
checkForRemovedField(nodeFields, 0);
}
@@ -345,9 +386,7 @@ public class TestInMemoryNodeModelTracke
ImmutableNode rootNode = model.getRootNode();
model.clearProperty("fields.field(0).name", selector, resolver);
assertSame("Model root was changed", rootNode, model.getRootNode());
- ImmutableNode nodeFields =
- NodeStructureHelper.nodeForKey(model.getTrackedNode(selector),
- "fields");
+ ImmutableNode nodeFields = fieldsNodeFromTrackedNode();
checkForRemovedField(nodeFields, 0);
}
@@ -360,8 +399,7 @@ public class TestInMemoryNodeModelTracke
NodeKeyResolver<ImmutableNode> resolver = createResolver();
model.trackNode(selector, resolver);
model.clearTree("fields.field(1)", selector, resolver);
- ImmutableNode nodeFields =
- NodeStructureHelper.nodeForKey(model, "tables/table(1)/fields");
+ ImmutableNode nodeFields = fieldsNodeFromModel();
checkForRemovedField(nodeFields, 1);
}
@@ -376,9 +414,88 @@ public class TestInMemoryNodeModelTracke
ImmutableNode rootNode = model.getRootNode();
model.clearTree("fields.field(1)", selector, resolver);
assertSame("Model root was changed", rootNode, model.getRootNode());
- ImmutableNode nodeFields =
- NodeStructureHelper.nodeForKey(model.getTrackedNode(selector),
- "fields");
+ ImmutableNode nodeFields = fieldsNodeFromTrackedNode();
checkForRemovedField(nodeFields, 1);
}
+
+ /**
+ * Prepares the passed in resolver mock to resolve add keys. They are
+ * interpreted on a default expression engine.
+ *
+ * @param resolver the {@code NodeKeyResolver} mock
+ */
+ private static void prepareResolverForAddKeys(
+ NodeKeyResolver<ImmutableNode> resolver)
+ {
+ EasyMock.expect(
+ resolver.resolveAddKey(EasyMock.anyObject(ImmutableNode.class),
+ EasyMock.anyString(),
+ EasyMock.anyObject(TreeData.class)))
+ .andAnswer(new IAnswer<NodeAddData<ImmutableNode>>() {
+ public NodeAddData<ImmutableNode> answer() throws Throwable {
+ ImmutableNode root =
+ (ImmutableNode) EasyMock.getCurrentArguments()[0];
+ String key = (String) EasyMock.getCurrentArguments()[1];
+ TreeData handler =
+ (TreeData) EasyMock.getCurrentArguments()[2];
+ return DefaultExpressionEngine.INSTANCE.prepareAdd(
+ root, key, handler);
+ }
+ }).anyTimes();
+ }
+
+ /**
+ * Tests whether a field node was added.
+ *
+ * @param nodeFields the fields node
+ */
+ private static void checkForAddedField(ImmutableNode nodeFields)
+ {
+ assertEquals("Wrong number of children",
+ NodeStructureHelper.fieldsLength(1) + 1, nodeFields
+ .getChildren().size());
+ ImmutableNode nodeField =
+ nodeFields.getChildren().get(
+ NodeStructureHelper.fieldsLength(1));
+ assertEquals("Wrong node name", "field", nodeField.getNodeName());
+ assertEquals("Wrong number of children of field node", 1, nodeField
+ .getChildren().size());
+ ImmutableNode nodeName = nodeField.getChildren().get(0);
+ assertEquals("Wrong name of name node", "name", nodeName.getNodeName());
+ assertEquals("Wrong node value", NEW_FIELD, nodeName.getValue());
+ }
+
+ /**
+ * Tests whether an addProperty() operation works on a tracked node.
+ */
+ @Test
+ public void testAddPropertyOnTrackedNode()
+ {
+ NodeKeyResolver<ImmutableNode> resolver = createResolver(false);
+ prepareResolverForAddKeys(resolver);
+ EasyMock.replay(resolver);
+ model.trackNode(selector, resolver);
+ model.addProperty("fields.field(-1).name", selector,
+ Collections.singleton(NEW_FIELD), resolver);
+ checkForAddedField(fieldsNodeFromModel());
+ checkForAddedField(fieldsNodeFromTrackedNode());
+ }
+
+ /**
+ * Tests an addProperty() operation on a tracked node that is detached.
+ */
+ @Test
+ public void testAddPropertyOnDetachedNode()
+ {
+ NodeKeyResolver<ImmutableNode> resolver = createResolver(false);
+ prepareResolverForAddKeys(resolver);
+ EasyMock.replay(resolver);
+ model.trackNode(selector, resolver);
+ initDetachedNode(resolver);
+ ImmutableNode rootNode = model.getRootNode();
+ model.addProperty("fields.field(-1).name", selector,
+ Collections.singleton(NEW_FIELD), resolver);
+ assertSame("Root node was changed", rootNode, model.getRootNode());
+ checkForAddedField(fieldsNodeFromTrackedNode());
+ }
}