You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by eb...@apache.org on 2009/06/23 12:57:00 UTC
svn commit: r787630 - in
/commons/proper/configuration/branches/configuration2_experimental/src:
main/java/org/apache/commons/configuration2/combined/MergeCombiner.java
test/java/org/apache/commons/configuration2/combined/TestMergeCombiner.java
Author: ebourg
Date: Tue Jun 23 10:57:00 2009
New Revision: 787630
URL: http://svn.apache.org/viewvc?rev=787630&view=rev
Log:
Adapted the MergeCombiner to the NodeHandler paradigm
Added:
commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/MergeCombiner.java (with props)
commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestMergeCombiner.java (with props)
Added: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/MergeCombiner.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/MergeCombiner.java?rev=787630&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/MergeCombiner.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/MergeCombiner.java Tue Jun 23 10:57:00 2009
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.configuration2.combined;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.configuration2.expr.NodeHandler;
+
+/**
+ * <p>
+ * A specialized implementation of the <code>NodeCombiner</code> interface
+ * that performs a merge from two passed in node hierarchies.
+ * </p>
+ * <p>
+ * This combiner performs the merge using a few rules:
+ * <ol>
+ * <li>Nodes can be merged when attributes that appear in both have the same value.</li>
+ * <li>Only a single node in the second file is considered a match to the node in the first file.</li>
+ * <li>Attributes in nodes that match are merged.
+ * <li>Nodes in both files that do not match are added to the result.</li>
+ * </ol>
+ * </p>
+ *
+ * @author <a href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
+ * @version $Id$
+ * @since 1.7
+ */
+public class MergeCombiner extends NodeCombiner
+{
+ /**
+ * Combines the given nodes to a new union node.
+ *
+ * @param node1 the first source node
+ * @param node2 the second source node
+ * @return the union node
+ */
+ public <T, U> CombinedNode combine(T node1, NodeHandler<T> handler1, U node2, NodeHandler<U> handler2)
+ {
+ CombinedNode result = createCombinedNode();
+ result.setName(handler1.nodeName(node1));
+ result.setValue(handler1.getValue(node1));
+ addAttributes(result, node1, handler1, node2, handler2);
+
+ // Check if nodes can be combined
+ List<U> children2 = new LinkedList<U>(handler2.getChildren(node2));
+ for (T child1 : handler1.getChildren(node1))
+ {
+ U child2 = canCombine(node1, handler1, node2, handler2, child1, children2);
+ if (child2 != null)
+ {
+ CombinedNode n = combine(child1, handler1, child2, handler2);
+ result.addChild(n.getName(), n);
+ children2.remove(child2);
+ }
+ else
+ {
+ result.addChild(handler1.nodeName(child1), child1);
+ }
+ }
+
+ // Add remaining children of node 2
+ for (U node : children2)
+ {
+ result.addChild(handler2.nodeName(node), node);
+ }
+
+ return result;
+ }
+
+ /**
+ * Handles the attributes during a combination process. First all attributes
+ * of the first node will be added to the result. Then all attributes of the
+ * second node, which are not contained in the first node, will also be
+ * added.
+ *
+ * @param result the resulting node
+ * @param node1 the first node
+ * @param handler1 the node handler for the first node
+ * @param node2 the second node
+ * @param handler2 the node handler for the second node
+ */
+ protected <T, U> void addAttributes(CombinedNode result, T node1,
+ NodeHandler<T> handler1, U node2, NodeHandler<U> handler2)
+ {
+ appendAttributes(result, node1, handler1);
+ for (String attr : handler2.getAttributes(node2))
+ {
+ if (handler1.getAttributeValue(node1, attr) == null)
+ {
+ result.addAttributeValue(attr, handler2.getAttributeValue(node2, attr));
+ }
+ }
+ }
+
+ /**
+ * Tests if the first node can be combined with the second node. A node can
+ * only be combined if its attributes are all present in the second node and
+ * they all have the same value.
+ *
+ * @param node1 the first node
+ * @param node2 the second node
+ * @param child the child node (of the first node)
+ * @return a child of the second node, with which a combination is possible
+ */
+ protected <T, U> U canCombine(T node1, NodeHandler<T> handler1, U node2, NodeHandler<U> handler2, T child, List<U> children2)
+ {
+ List<String> attrs1 = handler1.getAttributes(child);
+ List<U> nodes = new ArrayList<U>();
+
+ List<U> children = handler2.getChildren(node2, handler1.nodeName(child));
+ for (U node : children)
+ {
+ for (String attr1 : attrs1)
+ {
+ Object attr2val = handler2.getAttributeValue(node, attr1);
+ if (attr2val != null && !handler1.getAttributeValue(child, attr1).equals(attr2val))
+ {
+ node = null;
+ break;
+ }
+ }
+ if (node != null)
+ {
+ nodes.add(node);
+ }
+ }
+
+ if (nodes.size() == 1)
+ {
+ return nodes.get(0);
+ }
+ if (nodes.size() > 1 && !isListNode(child, handler1))
+ {
+ for (U node : nodes)
+ {
+ children2.remove(node);
+ }
+ }
+
+ return null;
+ }
+}
Propchange: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/MergeCombiner.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/configuration/branches/configuration2_experimental/src/main/java/org/apache/commons/configuration2/combined/MergeCombiner.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestMergeCombiner.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestMergeCombiner.java?rev=787630&view=auto
==============================================================================
--- commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestMergeCombiner.java (added)
+++ commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestMergeCombiner.java Tue Jun 23 10:57:00 2009
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.configuration2.combined;
+
+import org.apache.commons.configuration2.AbstractHierarchicalConfiguration;
+import org.apache.commons.configuration2.ConfigurationException;
+import org.apache.commons.configuration2.InMemoryConfiguration;
+import org.apache.commons.configuration2.expr.NodeList;
+import org.apache.commons.configuration2.expr.xpath.XPathExpressionEngine;
+import org.apache.commons.configuration2.tree.ConfigurationNode;
+
+/**
+ * Test class for MergeCombiner.
+ *
+ * @version $Id$
+ */
+public class TestMergeCombiner extends AbstractCombinerTest
+{
+ /**
+ * Creates the combiner.
+ *
+ * @return the combiner
+ */
+ protected NodeCombiner createCombiner()
+ {
+ return new MergeCombiner();
+ }
+
+ /**
+ * Tests combination of simple elements.
+ */
+ public void testSimpleValues() throws ConfigurationException
+ {
+ InMemoryConfiguration config = createCombinedConfiguration();
+ assertEquals("Wrong number of bgcolors", 0, config.getMaxIndex("gui.bgcolor"));
+ assertEquals("Wrong bgcolor", "green", config.getString("gui.bgcolor"));
+ assertEquals("Wrong selcolor", "yellow", config.getString("gui.selcolor"));
+ assertEquals("Wrong fgcolor", "blue", config.getString("gui.fgcolor"));
+ assertEquals("Wrong level", 1, config.getInt("gui.level"));
+ }
+
+ /**
+ * Tests combination of attributes.
+ */
+ public void testAttributes() throws ConfigurationException
+ {
+ InMemoryConfiguration config = createCombinedConfiguration();
+ assertEquals("Wrong value of min attribute", 1, config.getInt("gui.level[@min]"));
+ assertEquals("Wrong value of default attribute", 2, config.getInt("gui.level[@default]"));
+ assertEquals("Wrong number of id attributes", 0, config.getMaxIndex("database.tables.table(0)[@id]"));
+ assertEquals("Wrong value of table id", 1, config.getInt("database.tables.table(0)[@id]"));
+ }
+
+ /**
+ * Tests whether property values are correctly overridden.
+ */
+ public void testOverrideValues() throws ConfigurationException
+ {
+ InMemoryConfiguration config = createCombinedConfiguration();
+ assertEquals("Wrong user", "Admin", config.getString("base.services.security.login.user"));
+ assertEquals("Wrong user type", "default", config.getString("base.services.security.login.user[@type]"));
+ assertNull("Wrong password", config.getString("base.services.security.login.passwd"));
+ assertEquals("Wrong password type", "secret", config.getString("base.services.security.login.passwd[@type]"));
+ }
+
+ /**
+ * Tests if a list from the first node structure overrides a list in the
+ * second structure.
+ */
+ public void testListFromFirstStructure() throws ConfigurationException
+ {
+ InMemoryConfiguration config = createCombinedConfiguration();
+ assertEquals("Wrong number of services", 0, config.getMaxIndex("net.service.url"));
+ assertEquals("Wrong service", "http://service1.org", config.getString("net.service.url"));
+ assertFalse("Type attribute available", config.containsKey("net.service.url[@type]"));
+ }
+
+ /**
+ * Tests if a list from the second structure is added if it is not defined
+ * in the first structure.
+ */
+ public void testListFromSecondStructure() throws ConfigurationException
+ {
+ InMemoryConfiguration config = createCombinedConfiguration();
+ assertEquals("Wrong number of servers", 3, config.getMaxIndex("net.server.url"));
+ assertEquals("Wrong server", "http://testsvr.com", config.getString("net.server.url(2)"));
+ }
+
+ /**
+ * Tests the combination of the table structure. With the merge combiner
+ * both table 1 and table 2 should be present.
+ */
+ public void testCombinedTable() throws ConfigurationException
+ {
+ checkTable(createCombinedConfiguration());
+ }
+
+ public void testMerge() throws ConfigurationException
+ {
+ //combiner.setDebugStream(System.out);
+ InMemoryConfiguration config = createCombinedConfiguration();
+ config.setExpressionEngine(new XPathExpressionEngine());
+ assertEquals("Wrong number of Channels", 3, config.getMaxIndex("Channels/Channel"));
+ assertEquals("Bad Channel 1 Name", "My Channel", config.getString("Channels/Channel[@id='1']/Name"));
+ assertEquals("Bad Channel Type", "half", config.getString("Channels/Channel[@id='1']/@type"));
+ assertEquals("Bad Channel 2 Name", "Channel 2", config.getString("Channels/Channel[@id='2']/Name"));
+ assertEquals("Bad Channel Type", "full", config.getString("Channels/Channel[@id='2']/@type"));
+ assertEquals("Bad Channel Data", "test 1 data", config.getString("Channels/Channel[@id='1']/ChannelData"));
+ assertEquals("Bad Channel Data", "test 2 data", config.getString("Channels/Channel[@id='2']/ChannelData"));
+ assertEquals("Bad Channel Data", "more test 2 data", config.getString("Channels/Channel[@id='2']/MoreChannelData"));
+
+ }
+
+ /**
+ * Helper method for checking the combined table structure.
+ *
+ * @param config the config
+ * @return the node for the table element
+ */
+ private ConfigurationNode checkTable(InMemoryConfiguration config)
+ {
+ assertEquals("Wrong number of tables", 1, config.getMaxIndex("database.tables.table"));
+ AbstractHierarchicalConfiguration c = config.configurationAt("database.tables.table(0)");
+ assertEquals("Wrong table name", "documents", c.getString("name"));
+ assertEquals("Wrong number of fields", 2, c.getMaxIndex("fields.field.name"));
+ assertEquals("Wrong field", "docname", c.getString("fields.field(1).name"));
+
+ NodeList nds = config.getExpressionEngine().query(config.getRootNode(), "database.tables.table", config.getNodeHandler());
+ assertFalse("No node found", nds.size() == 0);
+ return (ConfigurationNode) nds.getNode(0);
+ }
+}
Propchange: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestMergeCombiner.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/configuration/branches/configuration2_experimental/src/test/java/org/apache/commons/configuration2/combined/TestMergeCombiner.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL