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/19 20:02:02 UTC
svn commit: r1588682 - in
/commons/proper/configuration/branches/immutableNodes/src:
main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java
test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java
Author: oheger
Date: Sat Apr 19 18:02:01 2014
New Revision: 1588682
URL: http://svn.apache.org/r1588682
Log:
Implemented interpolatedConfiguration in BaseHierarchicalConfiguration.
This method is a bit more involved when operating on immutable node structures.
Modified:
commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java
commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java
Modified: commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java?rev=1588682&r1=1588681&r2=1588682&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/main/java/org/apache/commons/configuration/BaseHierarchicalConfiguration.java Sat Apr 19 18:02:01 2014
@@ -21,9 +21,11 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import org.apache.commons.configuration.event.ConfigurationEvent;
import org.apache.commons.configuration.event.ConfigurationListener;
@@ -36,9 +38,11 @@ import org.apache.commons.configuration.
import org.apache.commons.configuration.tree.NodeHandler;
import org.apache.commons.configuration.tree.NodeModel;
import org.apache.commons.configuration.tree.NodeSelector;
+import org.apache.commons.configuration.tree.NodeTreeWalker;
import org.apache.commons.configuration.tree.QueryResult;
import org.apache.commons.configuration.tree.ReferenceNodeHandler;
import org.apache.commons.configuration.tree.TrackedNodeModel;
+import org.apache.commons.lang3.ObjectUtils;
/**
* <p>
@@ -642,18 +646,15 @@ public class BaseHierarchicalConfigurati
@Override
public Configuration interpolatedConfiguration()
{
-// BaseHierarchicalConfiguration c = (BaseHierarchicalConfiguration) clone();
-// c.getRootNode().visit(new ConfigurationNodeVisitorAdapter()
-// {
-// @Override
-// public void visitAfterChildren(ConfigurationNode node)
-// {
-// node.setValue(interpolate(node.getValue()));
-// }
-// });
-// return c;
- //TODO implementation
- return null;
+ InterpolatedVisitor visitor = new InterpolatedVisitor();
+ NodeHandler<ImmutableNode> handler = getModel().getNodeHandler();
+ NodeTreeWalker.INSTANCE
+ .walkDFS(handler.getRootNode(), visitor, handler);
+
+ BaseHierarchicalConfiguration c =
+ (BaseHierarchicalConfiguration) clone();
+ c.getNodeModel().setRootNode(visitor.getInterpolatedRoot());
+ return c;
}
/**
@@ -853,4 +854,212 @@ public class BaseHierarchicalConfigurati
}
}
}
+
+ /**
+ * A specialized visitor implementation which constructs the root node of a
+ * configuration with all variables replaced by their interpolated values.
+ */
+ private class InterpolatedVisitor extends
+ ConfigurationNodeVisitorAdapter<ImmutableNode>
+ {
+ /** A stack for managing node builder instances. */
+ private final List<ImmutableNode.Builder> builderStack;
+
+ /** The resulting root node. */
+ private ImmutableNode interpolatedRoot;
+
+ /**
+ * Creates a new instance of {@code InterpolatedVisitor}.
+ */
+ public InterpolatedVisitor()
+ {
+ builderStack = new LinkedList<ImmutableNode.Builder>();
+ }
+
+ /**
+ * Returns the result of this builder: the root node of the interpolated
+ * nodes hierarchy.
+ *
+ * @return the resulting root node
+ */
+ public ImmutableNode getInterpolatedRoot()
+ {
+ return interpolatedRoot;
+ }
+
+ @Override
+ public void visitBeforeChildren(ImmutableNode node,
+ NodeHandler<ImmutableNode> handler)
+ {
+ if (isLeafNode(node, handler))
+ {
+ handleLeafNode(node, handler);
+ }
+ else
+ {
+ ImmutableNode.Builder builder =
+ new ImmutableNode.Builder(handler.getChildrenCount(
+ node, null))
+ .name(handler.nodeName(node))
+ .value(interpolate(handler.getValue(node)))
+ .addAttributes(
+ interpolateAttributes(node, handler));
+ push(builder);
+ }
+ }
+
+ @Override
+ public void visitAfterChildren(ImmutableNode node,
+ NodeHandler<ImmutableNode> handler)
+ {
+ if (!isLeafNode(node, handler))
+ {
+ ImmutableNode newNode = pop().create();
+ storeInterpolatedNode(newNode);
+ }
+ }
+
+ /**
+ * Pushes a new builder on the stack.
+ *
+ * @param builder the builder
+ */
+ private void push(ImmutableNode.Builder builder)
+ {
+ builderStack.add(0, builder);
+ }
+
+ /**
+ * Pops the top-level element from the stack.
+ *
+ * @return the element popped from the stack
+ */
+ private ImmutableNode.Builder pop()
+ {
+ return builderStack.remove(0);
+ }
+
+ /**
+ * Returns the top-level element from the stack without removing it.
+ *
+ * @return the top-level element from the stack
+ */
+ private ImmutableNode.Builder peek()
+ {
+ return builderStack.get(0);
+ }
+
+ /**
+ * Returns a flag whether the given node is a leaf. This is the case if
+ * it does not have children.
+ *
+ * @param node the node in question
+ * @param handler the {@code NodeHandler}
+ * @return a flag whether this is a leaf node
+ */
+ private boolean isLeafNode(ImmutableNode node,
+ NodeHandler<ImmutableNode> handler)
+ {
+ return handler.getChildren(node).isEmpty();
+ }
+
+ /**
+ * Handles interpolation for a node with no children. If interpolation
+ * does not change this node, it is copied as is to the resulting
+ * structure. Otherwise, a new node is created with the interpolated
+ * values.
+ *
+ * @param node the current node to be processed
+ * @param handler the {@code NodeHandler}
+ */
+ private void handleLeafNode(ImmutableNode node,
+ NodeHandler<ImmutableNode> handler)
+ {
+ Object value = interpolate(node.getValue());
+ Map<String, Object> interpolatedAttributes =
+ new HashMap<String, Object>();
+ boolean attributeChanged =
+ interpolateAttributes(node, handler, interpolatedAttributes);
+ ImmutableNode newNode =
+ (valueChanged(value, handler.getValue(node)) || attributeChanged) ? new ImmutableNode.Builder()
+ .name(handler.nodeName(node)).value(value)
+ .addAttributes(interpolatedAttributes).create()
+ : node;
+ storeInterpolatedNode(newNode);
+ }
+
+ /**
+ * Stores a processed node. Per default, the node is added to the
+ * current builder on the stack. If no such builder exists, this is the
+ * result node.
+ *
+ * @param node the node to be stored
+ */
+ private void storeInterpolatedNode(ImmutableNode node)
+ {
+ if (builderStack.isEmpty())
+ {
+ interpolatedRoot = node;
+ }
+ else
+ {
+ peek().addChild(node);
+ }
+ }
+
+ /**
+ * Populates a map with interpolated attributes of the passed in node.
+ *
+ * @param node the current node to be processed
+ * @param handler the {@code NodeHandler}
+ * @param interpolatedAttributes a map for storing the results
+ * @return a flag whether an attribute value was changed by
+ * interpolation
+ */
+ private boolean interpolateAttributes(ImmutableNode node,
+ NodeHandler<ImmutableNode> handler,
+ Map<String, Object> interpolatedAttributes)
+ {
+ boolean attributeChanged = false;
+ for (String attr : handler.getAttributes(node))
+ {
+ Object attrValue =
+ interpolate(handler.getAttributeValue(node, attr));
+ if (valueChanged(attrValue,
+ handler.getAttributeValue(node, attr)))
+ {
+ attributeChanged = true;
+ }
+ interpolatedAttributes.put(attr, attrValue);
+ }
+ return attributeChanged;
+ }
+
+ /**
+ * Returns a map with interpolated attributes of the passed in node.
+ *
+ * @param node the current node to be processed
+ * @param handler the {@code NodeHandler}
+ * @return the map with interpolated attributes
+ */
+ private Map<String, Object> interpolateAttributes(ImmutableNode node,
+ NodeHandler<ImmutableNode> handler)
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ interpolateAttributes(node, handler, attributes);
+ return attributes;
+ }
+
+ /**
+ * Tests whether a value is changed because of interpolation.
+ *
+ * @param interpolatedValue the interpolated value
+ * @param value the original value
+ * @return a flag whether the value was changed
+ */
+ private boolean valueChanged(Object interpolatedValue, Object value)
+ {
+ return ObjectUtils.notEqual(interpolatedValue, value);
+ }
+ }
}
Modified: commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java?rev=1588682&r1=1588681&r2=1588682&view=diff
==============================================================================
--- commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java (original)
+++ commons/proper/configuration/branches/immutableNodes/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.java Sat Apr 19 18:02:01 2014
@@ -533,9 +533,17 @@ public class TestHierarchicalConfigurati
.testInterpolatedConfiguration(config);
// tests whether the hierarchical structure has been maintained
- config = c;
- //testGetProperty();
- //TODO check content
+ checkContent(c);
+ }
+
+ /**
+ * Tests whether interpolation works on an empty configuration.
+ */
+ @Test
+ public void testInterpolatedConfigurationEmpty()
+ {
+ config = new BaseHierarchicalConfiguration();
+ assertTrue("Got content", config.interpolatedConfiguration().isEmpty());
}
/**