You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by oh...@apache.org on 2006/04/16 19:29:11 UTC
svn commit: r394519 - in
/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree:
NodeCombiner.java OverrideCombiner.java UnionCombiner.java ViewNode.java
Author: oheger
Date: Sun Apr 16 10:29:10 2006
New Revision: 394519
URL: http://svn.apache.org/viewcvs?rev=394519&view=rev
Log:
Added NodeCombiner classes
Added:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/NodeCombiner.java (with props)
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/OverrideCombiner.java (with props)
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/UnionCombiner.java (with props)
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ViewNode.java (with props)
Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/NodeCombiner.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/NodeCombiner.java?rev=394519&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/NodeCombiner.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/NodeCombiner.java Sun Apr 16 10:29:10 2006
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.configuration.tree;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * <p>
+ * A base class for node combiner implementations.
+ * </p>
+ * <p>
+ * A <em>node combiner</em> is an object that knows how two hierarchical node
+ * structures can be combined into a single one. Of course, there are many
+ * possible ways of implementing such a combination, e.g. constructing a union,
+ * an intersection, or an "override" structure (were nodes in the first
+ * hierarchy take precedence over nodes in the second hierarchy). This abstract
+ * base class only provides some helper methods and defines the common interface
+ * for node combiners. Concrete sub classes will implement the diverse
+ * combination algorithms.
+ * </p>
+ * <p>
+ * For some concrete combiner implementations it is important to distinguish
+ * whether a node is a single node or whether it belongs to a list structure.
+ * Alone from the input structures, the combiner will not always be able to make
+ * this decision. So sometimes it may be necessary for the developer to
+ * configure the combiner and tell it, which nodes should be treated as list
+ * nodes. For this purpose the <code>addListNode()</code> method exists. It
+ * can be passed the name of a node, which should be considered a list node.
+ * </p>
+ *
+ * @version $Id$
+ * @since 1.3
+ */
+public abstract class NodeCombiner
+{
+ /**
+ * Creates a new instance of <code>NodeCombiner</code>.
+ */
+ public NodeCombiner()
+ {
+ listNodes = new HashSet();
+ }
+
+ /** Stores a list with node names that are known to be list nodes. */
+ protected Set listNodes;
+
+ /**
+ * Adds the name of a node to the list of known list nodes. This means that
+ * nodes with this name will never be combined.
+ *
+ * @param nodeName the name to be added
+ */
+ public void addListNode(String nodeName)
+ {
+ listNodes.add(nodeName);
+ }
+
+ /**
+ * Returns a set with the names of nodes that are known to be list nodes.
+ *
+ * @return a set with the names of list nodes
+ */
+ public Set getListNodes()
+ {
+ return Collections.unmodifiableSet(listNodes);
+ }
+
+ /**
+ * Checks if a node is a list node. This implementation tests if the given
+ * node name is contained in the set of known list nodes. Derived classes
+ * which use different criteria may overload this method.
+ *
+ * @param node the node to be tested
+ * @return a flag whether this is a list node
+ */
+ public boolean isListNode(ConfigurationNode node)
+ {
+ return listNodes.contains(node.getName());
+ }
+
+ /**
+ * Combines the hierarchies represented by the given root nodes. This method
+ * must be defined in concrete sub classes with the implementation of a
+ * specific combination algorithm.
+ *
+ * @param node1 the first root node
+ * @param node2 the second root node
+ * @return the resulting combined node structure
+ */
+ public abstract ConfigurationNode combine(ConfigurationNode node1,
+ ConfigurationNode node2);
+
+ /**
+ * Creates a new view node. This method will be called whenever a new view
+ * node is to be created. It can be overriden to create special view nodes.
+ * This base implementation returns a new instance of
+ * <code>{@link ViewNode}</code>.
+ *
+ * @return the new view node
+ */
+ protected ViewNode createViewNode()
+ {
+ return new ViewNode();
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/NodeCombiner.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/NodeCombiner.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/NodeCombiner.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/OverrideCombiner.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/OverrideCombiner.java?rev=394519&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/OverrideCombiner.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/OverrideCombiner.java Sun Apr 16 10:29:10 2006
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.configuration.tree;
+
+import java.util.Iterator;
+
+/**
+ * <p>
+ * A concrete combiner implementation that is able to construct an override
+ * combination.
+ * </p>
+ * <p>
+ * An <em>override combination</em> means that nodes in the first node
+ * structure take precedence over nodes in the second, or - in other words -
+ * nodes of the second structure are only added to the resulting structure if
+ * they do not occure in the first one. This is especially suitable for dealing
+ * with the properties of configurations that are defined in an
+ * <code>override</code> section of a configuration definition file (hence the
+ * name).
+ * </p>
+ * <p>
+ * This combiner will iterate over the second node hierarchy and find all nodes
+ * that are not contained in the first hierarchy; these are added to the result.
+ * If a node can be found in both structures, it is checked whether a
+ * combination (in a recursive way) can be constructed for the two, which will
+ * then be added. Per default, nodes are combined, which occur only once in both
+ * structures. This test is implemented in the <code>canCombine()</code>
+ * method.
+ * </p>
+ * <p>
+ * As is true for the <code>{@link UnionCombiner}</code>, for this combiner
+ * list nodes are important. The <code>addListNode()</code> can be called to
+ * declare certain nodes as list nodes. This has the effect that these nodes
+ * will never be combined.
+ * </p>
+ *
+ * @version $Id$
+ * @since 1.3
+ */
+public class OverrideCombiner extends NodeCombiner
+{
+ /**
+ * Constructs an override combination for the passed in node structures.
+ *
+ * @param node1 the first node
+ * @param node2 the second node
+ * @return the resulting combined node structure
+ */
+ public ConfigurationNode combine(ConfigurationNode node1,
+ ConfigurationNode node2)
+ {
+ ViewNode result = createViewNode();
+ result.setName(node1.getName());
+
+ // Process nodes from the first structure, which override the second
+ for (Iterator it = node1.getChildren().iterator(); it.hasNext();)
+ {
+ ConfigurationNode child = (ConfigurationNode) it.next();
+ ConfigurationNode child2 = canCombine(node1, node2, child);
+ if (child2 != null)
+ {
+ result.addChild(combine(child, child2));
+ }
+ else
+ {
+ result.addChild(child);
+ }
+ }
+
+ // Process nodes from the second structure, which are not contained
+ // in the first structure
+ for (Iterator it = node2.getChildren().iterator(); it.hasNext();)
+ {
+ ConfigurationNode child = (ConfigurationNode) it.next();
+ if (node1.getChildrenCount(child.getName()) < 1)
+ {
+ result.addChild(child);
+ }
+ }
+
+ // Handle attributes and value
+ addAttributes(result, node1, node2);
+ result.setValue((node1.getValue() != null) ? node1.getValue() : node2
+ .getValue());
+
+ 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 node2 the second node
+ */
+ protected void addAttributes(ViewNode result, ConfigurationNode node1,
+ ConfigurationNode node2)
+ {
+ result.appendAttributes(node1);
+ for (Iterator it = node2.getAttributes().iterator(); it.hasNext();)
+ {
+ ConfigurationNode attr = (ConfigurationNode) it.next();
+ if (node1.getAttributeCount(attr.getName()) == 0)
+ {
+ result.addAttribute(attr);
+ }
+ }
+ }
+
+ /**
+ * Tests if a child node of the second node can be combined with the given
+ * child node of the first node. If this is the case, the corresponding node
+ * will be returned, otherwise <b>null</b>. This implementation checks
+ * whether the child node occurs only once in both hierarchies and is no
+ * known list node.
+ *
+ * @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 ConfigurationNode canCombine(ConfigurationNode node1,
+ ConfigurationNode node2, ConfigurationNode child)
+ {
+ if (node2.getChildrenCount(child.getName()) == 1
+ && node1.getChildrenCount(child.getName()) == 1
+ && !isListNode(child))
+ {
+ return (ConfigurationNode) node2.getChildren(child.getName())
+ .get(0);
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/OverrideCombiner.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/OverrideCombiner.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/OverrideCombiner.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/UnionCombiner.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/UnionCombiner.java?rev=394519&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/UnionCombiner.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/UnionCombiner.java Sun Apr 16 10:29:10 2006
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.configuration.tree;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * <p>
+ * A specialized implementation of the <code>NodeCombiner</code> interface
+ * that constructs a union from two passed in node hierarchies.
+ * </p>
+ * <p>
+ * The given source hierarchies are traversed and their nodes are added to the
+ * resulting structure. Under some circumstances two nodes can be combined
+ * rather than adding both. This is the case if both nodes are single children
+ * (no lists) of their parents and do not have values. The corresponding check
+ * is implemented in the <code>findCombineNode()</code> method.
+ * </p>
+ * <p>
+ * Sometimes it is not possible for this combiner to detect whether two nodes
+ * can be combined or not. Consider the following two node hierarchies:
+ * </p>
+ * <p>
+ *
+ * <pre>
+ * Hierarchy 1:
+ *
+ * Database
+ * +--Tables
+ * +--Table
+ * +--name [users]
+ * +--fields
+ * +--field
+ * | +--name [uid]
+ * +--field
+ * | +--name [usrname]
+ * ...
+ * </pre>
+ *
+ * </p>
+ * <p>
+ *
+ * <pre>
+ * Hierarchy 2:
+ *
+ * Database
+ * +--Tables
+ * +--Table
+ * +--name [documents]
+ * +--fields
+ * +--field
+ * | +--name [docid]
+ * +--field
+ * | +--name [docname]
+ * ...
+ * </pre>
+ *
+ * </p>
+ * <p>
+ * Both hierarchies contain data about database tables. Each describes a single
+ * table. If these hierarchies are to be combined, the result should probably
+ * look like the following:
+ * <p>
+ *
+ * <pre>
+ * Database
+ * +--Tables
+ * +--Table
+ * | +--name [users]
+ * | +--fields
+ * | +--field
+ * | | +--name [uid]
+ * | ...
+ * +--Table
+ * +--name [documents]
+ * +--fields
+ * +--field
+ * | +--name [docid]
+ * ...
+ * </pre>
+ *
+ * </p>
+ * <p>
+ * i.e. the <code>Tables</code> nodes should be combined, while the
+ * <code>Table</code> nodes should both be added to the resulting tree. From
+ * the combiner's point of view there is no difference between the
+ * <code>Tables</code> and the <code>Table</code> nodes in the source trees,
+ * so the developer has to help out and give a hint that the <code>Table</code>
+ * nodes belong to a list structure. This can be done using the
+ * <code>addListNode()</code> method; this method expects the name of a node,
+ * which should be treated as a list node. So if
+ * <code>addListNode("Table");</code> was called, the combiner knows that it
+ * must not combine the <code>Table</code> nodes, but add it both to the
+ * resulting tree.
+ * </p>
+ *
+ * @version $Id$
+ * @since 1.3
+ */
+public class UnionCombiner 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 ConfigurationNode combine(ConfigurationNode node1,
+ ConfigurationNode node2)
+ {
+ ViewNode result = createViewNode();
+ result.setName(node1.getName());
+ result.appendAttributes(node1);
+ result.appendAttributes(node2);
+
+ // Check if nodes can be combined
+ List children2 = new LinkedList(node2.getChildren());
+ for (Iterator it = node1.getChildren().iterator(); it.hasNext();)
+ {
+ ConfigurationNode child1 = (ConfigurationNode) it.next();
+ ConfigurationNode child2 = findCombineNode(node1, node2, child1,
+ children2);
+ if (child2 != null)
+ {
+ result.addChild(combine(child1, child2));
+ children2.remove(child2);
+ }
+ else
+ {
+ result.addChild(child1);
+ }
+ }
+
+ // Add remaining children of node 2
+ for (Iterator it = children2.iterator(); it.hasNext();)
+ {
+ result.addChild((ConfigurationNode) it.next());
+ }
+
+ return result;
+ }
+
+ /**
+ * <p>
+ * Tries to find a child node of the second source node, with whitch a child
+ * of the first source node can be combined. During combining of the source
+ * nodes an iteration over the first source node's children is performed.
+ * For each child node it is checked whether a corresponding child node in
+ * the second source node exists. If this is the case, these corresponsing
+ * child nodes are recursively combined and the result is added to the
+ * combined node. This method implements the checks whether such a recursive
+ * combination is possible. The actual implementation tests the following
+ * conditions:
+ * </p>
+ * <p>
+ * <ul>
+ * <li>In both the first and the second source node there is only one child
+ * node with the given name (no list structures).</li>
+ * <li>The given name is not in the list of known list nodes, i.e. it was
+ * not passed to the <code>addListNode()</code> method.</li>
+ * <li>None of these matching child nodes has a value.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * If all of these tests are successfull, the matching child node of the
+ * second source node is returned. Otherwise the result is <b>null</b>.
+ * </p>
+ *
+ * @param node1 the first source node
+ * @param node2 the second source node
+ * @param child the child node of the first source node to be checked
+ * @param children a list with all children of the second source node
+ * @return the matching child node of the second source node or <b>null</b>
+ * if there is none
+ */
+ protected ConfigurationNode findCombineNode(ConfigurationNode node1,
+ ConfigurationNode node2, ConfigurationNode child, List children)
+ {
+ if (child.getValue() == null && !isListNode(child)
+ && node1.getChildrenCount(child.getName()) == 1
+ && node2.getChildrenCount(child.getName()) == 1)
+ {
+ ConfigurationNode child2 = (ConfigurationNode) node2.getChildren(
+ child.getName()).iterator().next();
+ if (child2.getValue() == null)
+ {
+ return child2;
+ }
+ }
+ return null;
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/UnionCombiner.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/UnionCombiner.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/UnionCombiner.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ViewNode.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ViewNode.java?rev=394519&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ViewNode.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ViewNode.java Sun Apr 16 10:29:10 2006
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.configuration.tree;
+
+import java.util.Iterator;
+
+/**
+ * <p>
+ * A specialized node implementation to be used in view configurations.
+ * </p>
+ * <p>
+ * Some configurations provide a logical view on the nodes of other
+ * configurations. These configurations construct their own hierarchy of nodes
+ * based on the node trees of their source configurations. This special node
+ * class can be used for this purpose. It allows child nodes and attributes to
+ * be added without changing their parent node. So a node can belong to a
+ * hierarchy of nodes of a source configuration, but be also contained in a view
+ * configuration.
+ * </p>
+ *
+ * @version $Id$
+ * @since 1.3
+ */
+public class ViewNode extends DefaultConfigurationNode
+{
+ /**
+ * Adds an attribute to this view node. The new attribute's parent node will
+ * be saved.
+ *
+ * @param attr the attribute node to be added
+ */
+ public void addAttribute(ConfigurationNode attr)
+ {
+ ConfigurationNode parent = null;
+
+ if (attr != null)
+ {
+ parent = attr.getParentNode();
+ }
+ super.addAttribute(attr);
+ attr.setParentNode(parent);
+ }
+
+ /**
+ * Adds a child node to this view node. The new child's parent node will be
+ * saved.
+ *
+ * @param child the child node to be added
+ */
+ public void addChild(ConfigurationNode child)
+ {
+ ConfigurationNode parent = null;
+
+ if (child != null)
+ {
+ parent = child.getParentNode();
+ }
+ super.addChild(child);
+ child.setParentNode(parent);
+ }
+
+ /**
+ * Adds all attribute nodes of the given source node to this view node.
+ *
+ * @param source the source node
+ */
+ public void appendAttributes(ConfigurationNode source)
+ {
+ if (source != null)
+ {
+ for (Iterator it = source.getAttributes().iterator(); it.hasNext();)
+ {
+ addAttribute((ConfigurationNode) it.next());
+ }
+ }
+ }
+
+ /**
+ * Adds all child nodes of the given source node to this view node.
+ *
+ * @param source the source node
+ */
+ public void appendChildren(ConfigurationNode source)
+ {
+ if (source != null)
+ {
+ for (Iterator it = source.getChildren().iterator(); it.hasNext();)
+ {
+ addChild((ConfigurationNode) it.next());
+ }
+ }
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ViewNode.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ViewNode.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ViewNode.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org