commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ohe...@apache.org
Subject svn commit: r359620 - in /jakarta/commons/proper/configuration/trunk/src: java/org/apache/commons/configuration/tree/ test/org/apache/commons/configuration/tree/
Date Wed, 28 Dec 2005 20:20:29 GMT
Author: oheger
Date: Wed Dec 28 12:20:17 2005
New Revision: 359620

URL: http://svn.apache.org/viewcvs?rev=359620&view=rev
Log:
Adding a new tree package for interfaces and classes supporting hierarchical configurations as a first step for adding support for other expression languages (e.g. XPATH)

Added:
    jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/
    jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNode.java   (with props)
    jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitor.java   (with props)
    jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/DefaultConfigurationNode.java   (with props)
    jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/
    jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/TestDefaultConfigurationNode.java   (with props)

Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNode.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNode.java?rev=359620&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNode.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNode.java Wed Dec 28 12:20:17 2005
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2001-2005 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.List;
+
+/**
+ * <p>
+ * Definition of an interface for the nodes of a hierarchical configuration.
+ * </p>
+ * <p>
+ * This interface defines a tree like structure for configuration data. A node
+ * has a value and can have an arbitrary number of children and attribures.
+ * </p>
+ *
+ * @since 1.3
+ * @author Oliver Heger
+ */
+public interface ConfigurationNode
+{
+    /**
+     * Returns the name of this node.
+     *
+     * @return the node name
+     */
+    String getName();
+
+    /**
+     * Sets the name of this node.
+     *
+     * @param name the node name
+     */
+    void setName(String name);
+
+    /**
+     * Returns the value of this node.
+     *
+     * @return the node's value
+     */
+    Object getValue();
+
+    /**
+     * Sets the value of this node.
+     *
+     * @param val the node's value
+     */
+    void setValue(Object val);
+
+    /**
+     * Returns this node's reference.
+     *
+     * @return the reference
+     */
+    Object getReference();
+
+    /**
+     * Sets this node's reference. This reference can be used by concrete
+     * Configuration implementations to store data associated with each node. A
+     * XML based configuration for instance could here store a reference to the
+     * corresponding DOM element.
+     *
+     * @param ref the reference
+     */
+    void setReference(Object ref);
+
+    /**
+     * Returns this node's parent. Can be <b>null</b>, then this node is the
+     * top level node.
+     *
+     * @return the parent of this node
+     */
+    ConfigurationNode getParentNode();
+
+    /**
+     * Sets the parent of this node.
+     *
+     * @param parent the parent of this node
+     */
+    void setParentNode(ConfigurationNode parent);
+
+    /**
+     * Adds a child to this node.
+     *
+     * @param node the new child
+     */
+    void addChild(ConfigurationNode node);
+
+    /**
+     * Returns a list with the child nodes of this node. The nodes in this list
+     * should be in the order they were inserted into this node.
+     *
+     * @return a list with the children of this node (never <b>null</b>)
+     */
+    List getChildren();
+
+    /**
+     * Returns the number of this node's children.
+     *
+     * @return the number of the children of this node
+     */
+    int getChildrenCount();
+
+    /**
+     * Returns a list with all children of this node with the given name.
+     *
+     * @param name the name of the searched children
+     * @return a list with all child nodes with this name (never <b>null</b>)
+     */
+    List getChildren(String name);
+
+    /**
+     * Returns the number of children with the given name.
+     *
+     * @param name the name
+     * @return the number of children with this name
+     */
+    int getChildrenCount(String name);
+
+    /**
+     * Returns the child node with the given index. If the index does not
+     * exist, an exception will be thrown.
+     * @param index the index of the child node (0-based)
+     * @return the child node with this index
+     */
+    ConfigurationNode getChild(int index);
+
+    /**
+     * Removes the given node from this node's children.
+     *
+     * @param child the child node to be removed
+     * @return a flag if the node could be removed
+     */
+    boolean removeChild(ConfigurationNode child);
+
+    /**
+     * Removes all child nodes of this node with the given name.
+     *
+     * @param childName the name of the children to be removed
+     * @return a flag if at least one child was removed
+     */
+    boolean removeChild(String childName);
+
+    /**
+     * Removes all children from this node.
+     */
+    void removeChildren();
+
+    /**
+     * Returns a flag whether this node is an attribute.
+     *
+     * @return a flag whether this node is an attribute
+     */
+    boolean isAttribute();
+
+    /**
+     * Sets a flag whether this node is an attribute.
+     *
+     * @param f the attribute flag
+     */
+    void setAttribute(boolean f);
+
+    /**
+     * Returns a list with this node's attributes. Attributes are also modeled
+     * as <code>ConfigurationNode</code> objects.
+     *
+     * @return a list with the attributes
+     */
+    List getAttributes();
+
+    /**
+     * Returns the number of attributes of this node.
+     * @return the number of attributes
+     */
+    int getAttributeCount();
+
+    /**
+     * Returns a list with the attribute nodes with the given name. Attributes
+     * with same names can be added multiple times, so the return value of this
+     * method is a list.
+     *
+     * @param name the name of the attribute
+     * @return the attribute nodes with this name (never <b>null</b>)
+     */
+    List getAttributes(String name);
+
+    /**
+     * Returns the number of attributes with the given name.
+     * @return the number of attributes with this name
+     */
+    int getAttributeCount(String name);
+
+    /**
+     * Returns the attribute node with the given index. If no such index exists,
+     * an exception will be thrown.
+     * @param index the index
+     * @return the attribute node with this index
+     */
+    ConfigurationNode getAttribute(int index);
+
+    /**
+     * Removes the specified attribute from this node.
+     *
+     * @param node the attribute to remove
+     * @return a flag if the node could be removed
+     */
+    boolean removeAttribute(ConfigurationNode node);
+
+    /**
+     * Removes all attributes with the given name.
+     *
+     * @param name the name of the attributes to be removed
+     * @return a flag if at least one attribute was removed
+     */
+    boolean removeAttribute(String name);
+
+    /**
+     * Removes all attributes of this node.
+     */
+    void removeAttributes();
+
+    /**
+     * Adds the specified attribute to this node
+     *
+     * @param attr the attribute node
+     */
+    void addAttribute(ConfigurationNode attr);
+
+    /**
+     * Returns a flag if this node is defined. This means that the node contains
+     * some data.
+     *
+     * @return a flag whether this node is defined
+     */
+    boolean isDefined();
+
+    /**
+     * Visits this node and all its sub nodes. This method provides a simple
+     * means for going through a hierarchical structure of configuration nodes.
+     *
+     * @see ConfigurationNodeVisitor
+     * @param visitor the visitor
+     */
+    void visit(ConfigurationNodeVisitor visitor);
+}

Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNode.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNode.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitor.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitor.java?rev=359620&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitor.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitor.java Wed Dec 28 12:20:17 2005
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2001-2005 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;
+
+/**
+ * <p>
+ * Definition of a <em>Visitor</em> interface for a configuration node
+ * structure.
+ * </p>
+ * <p>
+ * The <code>ConfigurationNode</code> interface defines a <code>visit()</code>,
+ * which simplifies traversal of a complex node hierarchy. A configuration node
+ * implementation must provide a way of visiting all nodes in the current
+ * hierarchy. This is a typical application of the GoF <em>Visitor</em>
+ * pattern.
+ * </p>
+ *
+ * @since 1.3
+ * @see ConfigurationNode
+ * @author Oliver Heger
+ */
+public interface ConfigurationNodeVisitor
+{
+    /**
+     * Visits the specified node. This method is called before eventually
+     * existing children of this node are processed.
+     *
+     * @param node the node to be visited
+     */
+    void visitBeforeChildren(ConfigurationNode node);
+
+    /**
+     * Visits the specified node. This method is called after eventually
+     * existing children of this node have been processed.
+     *
+     * @param node the node to be visited
+     */
+    void visitAfterChildren(ConfigurationNode node);
+
+    /**
+     * Returns a flag whether the actual visit process should be aborted. This
+     * method allows a visitor implementation to state that it does not need any
+     * further data. It may be used e.g. by visitors that search for a certain
+     * node in the hierarchy. After that node was found, there is no need to
+     * process the remaining nodes, too.
+     *
+     * @return a flag if the visit process should be stopped
+     */
+    boolean terminate();
+}

Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitor.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/DefaultConfigurationNode.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/DefaultConfigurationNode.java?rev=359620&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/DefaultConfigurationNode.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/DefaultConfigurationNode.java Wed Dec 28 12:20:17 2005
@@ -0,0 +1,698 @@
+/*
+ * Copyright 2001-2005 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.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;
+
+/**
+ * <p>
+ * A default implementation of the <code>ConfigurationNode</code> interface.
+ * </p>
+ *
+ * @since 1.3
+ * @author Oliver Heger
+ */
+public class DefaultConfigurationNode implements ConfigurationNode, Cloneable
+{
+    /** Stores the children of this node. */
+    private SubNodes children;
+
+    /** Stores the attributes of this node. */
+    private SubNodes attributes;
+
+    /** Stores a reference to this node's parent. */
+    private ConfigurationNode parent;
+
+    /** Stores the value of this node. */
+    private Object value;
+
+    /** Stores the reference. */
+    private Object reference;
+
+    /** Stores the name of this node. */
+    private String name;
+
+    /** Stores a flag if this is an attribute. */
+    private boolean attribute;
+
+    /**
+     * Creates a new uninitialized instance of
+     * <code>DefaultConfigurationNode</code>.
+     */
+    public DefaultConfigurationNode()
+    {
+        this(null);
+    }
+
+    /**
+     * Creates a new instance of <code>DefaultConfigurationNode</code> and
+     * initializes it with the node name.
+     *
+     * @param name the name of this node
+     */
+    public DefaultConfigurationNode(String name)
+    {
+        this(name, null);
+    }
+
+    /**
+     * Creates a new instance of <code>DefaultConfigurationNode</code> and
+     * initializes it with the name and a value.
+     *
+     * @param name the node's name
+     * @param value the node's value
+     */
+    public DefaultConfigurationNode(String name, Object value)
+    {
+        setName(name);
+        setValue(value);
+        initSubNodes();
+    }
+
+    /**
+     * Returns the name of this node.
+     *
+     * @return the name of this node
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+    /**
+     * Sets the name of this node.
+     *
+     * @param name the new name
+     */
+    public void setName(String name)
+    {
+        checkState();
+        this.name = name;
+    }
+
+    /**
+     * Returns the value of this node.
+     *
+     * @return the value of this node
+     */
+    public Object getValue()
+    {
+        return value;
+    }
+
+    /**
+     * Sets the value of this node.
+     *
+     * @param val the value of this node
+     */
+    public void setValue(Object val)
+    {
+        value = val;
+    }
+
+    /**
+     * Returns the reference.
+     *
+     * @return the reference
+     */
+    public Object getReference()
+    {
+        return reference;
+    }
+
+    /**
+     * Sets the reference.
+     *
+     * @param reference the reference object
+     */
+    public void setReference(Object reference)
+    {
+        this.reference = reference;
+    }
+
+    /**
+     * Returns a reference to this node's parent.
+     *
+     * @return the parent node or <b>null </b> if this is the root
+     */
+    public ConfigurationNode getParentNode()
+    {
+        return parent;
+    }
+
+    /**
+     * Sets the parent of this node.
+     *
+     * @param parent the parent of this node
+     */
+    public void setParentNode(ConfigurationNode parent)
+    {
+        this.parent = parent;
+    }
+
+    /**
+     * Adds a new child to this node.
+     *
+     * @param child the new child
+     */
+    public void addChild(ConfigurationNode child)
+    {
+        children.addNode(child);
+        child.setAttribute(false);
+        child.setParentNode(this);
+    }
+
+    /**
+     * Returns a list with all children of this node.
+     *
+     * @return a list with all child nodes
+     */
+    public List getChildren()
+    {
+        return children.getSubNodes();
+    }
+
+    /**
+     * Returns the number of all children of this node.
+     *
+     * @return the number of all children
+     */
+    public int getChildrenCount()
+    {
+        return children.getSubNodes().size();
+    }
+
+    /**
+     * Returns a list of all children with the given name.
+     *
+     * @param name the name; can be <b>null </b>, then all children are returned
+     * @return a list of all children with the given name
+     */
+    public List getChildren(String name)
+    {
+        return children.getSubNodes(name);
+    }
+
+    /**
+     * Returns the number of children with the given name.
+     *
+     * @param name the name; can be <b>null </b>, then the number of all
+     * children is returned
+     * @return the number of child nodes with this name
+     */
+    public int getChildrenCount(String name)
+    {
+        return children.getSubNodes(name).size();
+    }
+
+    /**
+     * Returns the child node with the given index.
+     *
+     * @param index the index (0-based)
+     * @return the child with this index
+     */
+    public ConfigurationNode getChild(int index)
+    {
+        return children.getNode(index);
+    }
+
+    /**
+     * Removes the specified child node from this node.
+     *
+     * @param child the node to be removed
+     * @return a flag if a node was removed
+     */
+    public boolean removeChild(ConfigurationNode child)
+    {
+        return children.removeNode(child);
+    }
+
+    /**
+     * Removes all children with the given name.
+     *
+     * @param childName the name of the children to be removed
+     * @return a flag if at least one child node was removed
+     */
+    public boolean removeChild(String childName)
+    {
+        return children.removeNodes(childName);
+    }
+
+    /**
+     * Removes all child nodes of this node.
+     */
+    public void removeChildren()
+    {
+        children.clear();
+    }
+
+    /**
+     * Checks if this node is an attribute node.
+     *
+     * @return a flag if this is an attribute node
+     */
+    public boolean isAttribute()
+    {
+        return attribute;
+    }
+
+    /**
+     * Sets the attribute flag. Note: this method can only be called if the node
+     * is not already part of a node hierarchy.
+     *
+     * @param f the attribute flag
+     */
+    public void setAttribute(boolean f)
+    {
+        checkState();
+        attribute = f;
+    }
+
+    /**
+     * Adds the specified attribute to this node.
+     *
+     * @param attr the attribute to be added
+     */
+    public void addAttribute(ConfigurationNode attr)
+    {
+        attributes.addNode(attr);
+        attr.setAttribute(true);
+        attr.setParentNode(this);
+    }
+
+    /**
+     * Returns a list with the attributes of this node. This list contains
+     * <code>ConfigurationNode</code> objects, too.
+     *
+     * @return the attribute list, never <b>null </b>
+     */
+    public List getAttributes()
+    {
+        return attributes.getSubNodes();
+    }
+
+    /**
+     * Returns the number of attributes contained in this node.
+     *
+     * @return the number of attributes
+     */
+    public int getAttributeCount()
+    {
+        return attributes.getSubNodes().size();
+    }
+
+    /**
+     * Returns a list with all attributes of this node with the given name.
+     *
+     * @param name the attribute's name
+     * @return all attributes with this name
+     */
+    public List getAttributes(String name)
+    {
+        return attributes.getSubNodes(name);
+    }
+
+    /**
+     * Returns the number of attributes of this node with the given name.
+     *
+     * @param name the name
+     * @return the number of attributes with this name
+     */
+    public int getAttributeCount(String name)
+    {
+        return getAttributes(name).size();
+    }
+
+    /**
+     * Removes the specified attribute.
+     *
+     * @param node the attribute node to be removed
+     * @return a flag if the attribute could be removed
+     */
+    public boolean removeAttribute(ConfigurationNode node)
+    {
+        return attributes.removeNode(node);
+    }
+
+    /**
+     * Removes all attributes with the specified name.
+     *
+     * @param name the name
+     * @return a flag if at least one attribute was removed
+     */
+    public boolean removeAttribute(String name)
+    {
+        return attributes.removeNodes(name);
+    }
+
+    /**
+     * Returns the attribute with the given index.
+     *
+     * @param index the index (0-based)
+     * @return the attribute with this index
+     */
+    public ConfigurationNode getAttribute(int index)
+    {
+        return attributes.getNode(index);
+    }
+
+    /**
+     * Removes all attributes of this node.
+     */
+    public void removeAttributes()
+    {
+        attributes.clear();
+    }
+
+    /**
+     * Returns a flag if this node is defined. This means that the node contains
+     * some data.
+     *
+     * @return a flag whether this node is defined
+     */
+    public boolean isDefined()
+    {
+        return getValue() != null || getChildrenCount() > 0
+                || getAttributeCount() > 0;
+    }
+
+    /**
+     * Visits this node and all its sub nodes.
+     *
+     * @param visitor the visitor
+     */
+    public void visit(ConfigurationNodeVisitor visitor)
+    {
+        if (visitor == null)
+        {
+            throw new IllegalArgumentException("Visitor must not be null!");
+        }
+
+        if (!visitor.terminate())
+        {
+            visitor.visitBeforeChildren(this);
+            children.visit(visitor);
+            attributes.visit(visitor);
+            visitor.visitAfterChildren(this);
+        } /* if */
+    }
+
+    /**
+     * Creates a copy of this object. This is not a deep copy, the children are
+     * not cloned.
+     *
+     * @return a copy of this object
+     */
+    public Object clone()
+    {
+        try
+        {
+            DefaultConfigurationNode copy = (DefaultConfigurationNode) super
+                    .clone();
+            copy.initSubNodes();
+            return copy;
+        }
+        catch (CloneNotSupportedException cex)
+        {
+            return null; // should not happen
+        }
+    }
+
+    /**
+     * Checks if a modification of this node is allowed. Some properties of a
+     * node must not be changed when the node has a parent. This method checks
+     * this and throws a runtime exception if necessary.
+     */
+    protected void checkState()
+    {
+        if (getParentNode() != null)
+        {
+            throw new IllegalStateException(
+                    "Node cannot be modified when added to a parent!");
+        } /* if */
+    }
+
+    /**
+     * Creates a <code>SubNodes</code> instance that is used for storing
+     * either this node's children or attributes.
+     *
+     * @param attributes <b>true</b> if the returned instance is used for
+     * storing attributes, <b>false</b> for storing child nodes
+     * @return the <code>SubNodes</code> object to use
+     */
+    protected SubNodes createSubNodes(boolean attributes)
+    {
+        return new SubNodes();
+    }
+
+    /**
+     * Deals with the reference when a node is removed. This method is called
+     * for each removed child node or attribute. It can be overloaded in sub
+     * classes, for which the reference has a concrete meaning and remove
+     * operations need some update actions. This default implementation is
+     * empty.
+     */
+    protected void removeReference()
+    {
+    }
+
+    /**
+     * Helper method for initializing the sub nodes objects.
+     */
+    private void initSubNodes()
+    {
+        children = createSubNodes(false);
+        attributes = createSubNodes(true);
+    }
+
+    /**
+     * An internally used helper class for managing a collection of sub nodes.
+     */
+    protected static class SubNodes
+    {
+        /** Stores a list for the sub nodes. */
+        private List nodes;
+
+        /** Stores a map for accessing subnodes by name. */
+        private Map namedNodes;
+
+        /**
+         * Adds a new sub node.
+         *
+         * @param node the node to add
+         */
+        public void addNode(ConfigurationNode node)
+        {
+            if (node == null || node.getName() == null)
+            {
+                throw new IllegalArgumentException(
+                        "Node to add must have a defined name!");
+            }
+            node.setParentNode(null);  // reset, will later be set
+
+            if (nodes == null)
+            {
+                nodes = new ArrayList();
+                namedNodes = new HashMap();
+            }
+
+            nodes.add(node);
+            List lst = (List) namedNodes.get(node.getName());
+            if (lst == null)
+            {
+                lst = new LinkedList();
+                namedNodes.put(node.getName(), lst);
+            }
+            lst.add(node);
+        }
+
+        /**
+         * Removes a sub node.
+         *
+         * @param node the node to remove
+         * @return a flag if the node could be removed
+         */
+        public boolean removeNode(ConfigurationNode node)
+        {
+            if (nodes != null && node != null && nodes.contains(node))
+            {
+                detachNode(node);
+                nodes.remove(node);
+
+                List lst = (List) namedNodes.get(node.getName());
+                if (lst != null)
+                {
+                    lst.remove(node);
+                    if (lst.isEmpty())
+                    {
+                        namedNodes.remove(node.getName());
+                    }
+                }
+                return true;
+            }
+
+            else
+            {
+                return false;
+            }
+        }
+
+        /**
+         * Removes all sub nodes with the given name.
+         *
+         * @param name the name
+         * @return a flag if at least on sub node was removed
+         */
+        public boolean removeNodes(String name)
+        {
+            if (nodes != null && name != null)
+            {
+                List lst = (List) namedNodes.remove(name);
+                if (lst != null)
+                {
+                    detachNodes(lst);
+                    nodes.removeAll(lst);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Removes all sub nodes.
+         */
+        public void clear()
+        {
+            if (nodes != null)
+            {
+                detachNodes(nodes);
+                nodes = null;
+                namedNodes = null;
+            }
+        }
+
+        /**
+         * Returns the node with the given index. If this index cannot be found,
+         * an <code>IndexOutOfBoundException</code> exception will be thrown.
+         *
+         * @param index the index (0-based)
+         * @return the sub node at the specified index
+         */
+        public ConfigurationNode getNode(int index)
+        {
+            if (nodes == null)
+            {
+                throw new IndexOutOfBoundsException("No sub nodes available!");
+            }
+            return (ConfigurationNode) nodes.get(index);
+        }
+
+        /**
+         * Returns a list with all stored sub nodes. The return value is never
+         * <b>null</b>.
+         *
+         * @return a list with the sub nodes
+         */
+        public List getSubNodes()
+        {
+            return (nodes == null) ? Collections.EMPTY_LIST : Collections
+                    .unmodifiableList(nodes);
+        }
+
+        /**
+         * Returns a list of the sub nodes with the given name. The return value
+         * is never <b>null</b>.
+         *
+         * @param name the name; if <b>null</b> is passed, all sub nodes will
+         * be returned
+         * @return all sub nodes with this name
+         */
+        public List getSubNodes(String name)
+        {
+            if (name == null)
+            {
+                return getSubNodes();
+            }
+
+            List result;
+            if (nodes == null)
+            {
+                result = null;
+            }
+            else
+            {
+                result = (List) namedNodes.get(name);
+            }
+
+            return (result == null) ? Collections.EMPTY_LIST : Collections
+                    .unmodifiableList(result);
+        }
+
+        /**
+         * Let the passed in visitor visit all sub nodes.
+         *
+         * @param visitor the visitor
+         */
+        public void visit(ConfigurationNodeVisitor visitor)
+        {
+            if (nodes != null)
+            {
+                for (Iterator it = nodes.iterator(); it.hasNext()
+                        && !visitor.terminate();)
+                {
+                    ((ConfigurationNode) it.next()).visit(visitor);
+                }
+            }
+        }
+
+        /**
+         * This method is called whenever a sub node is removed from this
+         * object. It ensures that the removed node's parent is reset and its
+         * <code>removeReference()</code> method gets called.
+         *
+         * @param subNode the node to be removed
+         */
+        protected void detachNode(ConfigurationNode subNode)
+        {
+            subNode.setParentNode(null);
+            if (subNode instanceof DefaultConfigurationNode)
+            {
+                ((DefaultConfigurationNode) subNode).removeReference();
+            }
+        }
+
+        /**
+         * Detaches a list of sub nodes. This method calls
+         * <code>detachNode()</code> for each node contained in the list.
+         *
+         * @param subNodes the list with nodes to be detached
+         */
+        protected void detachNodes(Collection subNodes)
+        {
+            for (Iterator it = subNodes.iterator(); it.hasNext();)
+            {
+                detachNode((ConfigurationNode) it.next());
+            }
+        }
+    }
+}

Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/DefaultConfigurationNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/DefaultConfigurationNode.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/DefaultConfigurationNode.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/TestDefaultConfigurationNode.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/TestDefaultConfigurationNode.java?rev=359620&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/TestDefaultConfigurationNode.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/TestDefaultConfigurationNode.java Wed Dec 28 12:20:17 2005
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2001-2005 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.List;
+import java.util.StringTokenizer;
+
+import junit.framework.TestCase;
+
+/**
+ * Test class for DefaultConfigurationNode.
+ *
+ * @author Oliver Heger
+ */
+public class TestDefaultConfigurationNode extends TestCase
+{
+    /** Constant array for the field names. */
+    private static final String[] FIELD_NAMES =
+    { "UID", "NAME", "FIRSTNAME", "LASTLOGIN"};
+
+    /** Constant array for the field data types. */
+    private static final String[] FIELD_TYPES =
+    { "long", "string", "string", "date"};
+
+    /** Constant array for additional field attributes. */
+    private static final String[] FIELD_ATTRS =
+    { "primarykey,unique", "notnull", "notnull", null};
+
+    /** The node to be tested. */
+    DefaultConfigurationNode node;
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        node = new DefaultConfigurationNode();
+        node.setName("table");
+        node.setReference("TestReference");
+        node.addAttribute(new DefaultConfigurationNode("type", "system"));
+        node.addChild(new DefaultConfigurationNode("name", "users"));
+
+        // Add nodes for the table's fields
+        for (int i = 0; i < FIELD_NAMES.length; i++)
+        {
+            DefaultConfigurationNode field = new DefaultConfigurationNode(
+                    "field");
+            field
+                    .addChild(new DefaultConfigurationNode("name",
+                            FIELD_NAMES[i]));
+            field.addAttribute(new DefaultConfigurationNode("type",
+                    FIELD_TYPES[i]));
+            if (FIELD_ATTRS[i] != null)
+            {
+                StringTokenizer tok = new StringTokenizer(FIELD_ATTRS[i], ", ");
+                while (tok.hasMoreTokens())
+                {
+                    field.addAttribute(new DefaultConfigurationNode(
+                            "attribute", tok.nextToken()));
+                }
+            }
+            node.addChild(field);
+        }
+    }
+
+    /**
+     * Tests a newly created, uninitialized node.
+     */
+    public void testNewNode()
+    {
+        node = new DefaultConfigurationNode();
+        assertNull("name is not null", node.getName());
+        assertNull("value is not null", node.getValue());
+        assertNull("reference is not null", node.getReference());
+        assertTrue("Children are not empty", node.getChildren().isEmpty());
+        assertTrue("Named children are not empty", node.getChildren("test")
+                .isEmpty());
+        assertEquals("Children cound is not 0", 0, node.getChildrenCount());
+        assertEquals("Named children count is not 0", 0, node
+                .getChildrenCount("test"));
+        assertTrue("Attributes are not empty", node.getAttributes().isEmpty());
+        assertTrue("Named attributes are not empty", node.getAttributes("test")
+                .isEmpty());
+        assertNull("Node has a parent", node.getParentNode());
+        assertFalse("Node is defined", node.isDefined());
+        try
+        {
+            node.getAttribute(0);
+            fail("Could access non existing attribute!");
+        }
+        catch (IndexOutOfBoundsException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests accessing a node's reference.
+     */
+    public void testGetReference()
+    {
+        assertEquals("Reference was not stored", "TestReference", node
+                .getReference());
+    }
+
+    /**
+     * Tests accessing the node's children.
+     */
+    public void testGetChildren()
+    {
+        assertEquals("Number of children incorrect", FIELD_NAMES.length + 1,
+                node.getChildrenCount());
+        List children = node.getChildren();
+        Iterator it = children.iterator();
+        DefaultConfigurationNode child = (DefaultConfigurationNode) it.next();
+        assertEquals("Wrong node", "name", child.getName());
+        checkFieldNodes(it);
+    }
+
+    /**
+     * Tests accessing the node's children by name.
+     */
+    public void testGetChildrenByName()
+    {
+        List children = node.getChildren("field");
+        assertEquals("Incorrect number of child nodes", FIELD_NAMES.length,
+                children.size());
+        assertEquals("Incorrect result of getChildrenCount()",
+                FIELD_NAMES.length, node.getChildrenCount("field"));
+        checkFieldNodes(children.iterator());
+        assertTrue("Found non existing nodes", node.getChildren("test")
+                .isEmpty());
+        assertEquals("Wrong children list for null", node.getChildren(), node
+                .getChildren(null));
+    }
+
+    /**
+     * Tests adding a new child node.
+     */
+    public void testAddChild()
+    {
+        int cnt = node.getChildrenCount();
+        DefaultConfigurationNode ndNew = new DefaultConfigurationNode("test",
+                "xyz");
+        node.addChild(ndNew);
+        assertEquals("New node was not added", cnt + 1, node.getChildrenCount());
+        List children = node.getChildren();
+        assertEquals("Incorrect number of children", node.getChildrenCount(),
+                children.size());
+        assertSame("Node was not added to end", ndNew, children.get(cnt));
+        assertEquals("Incorrect number of named children", 1, node
+                .getChildrenCount(ndNew.getName()));
+        assertFalse("Child is an attribute", ndNew.isAttribute());
+        assertSame("Parent was not set", node, ndNew.getParentNode());
+    }
+
+    /**
+     * Tests adding invalid child nodes.
+     */
+    public void testAddUndefinedChild()
+    {
+        try
+        {
+            node.addChild(null);
+            fail("null node could be added!");
+        }
+        catch (IllegalArgumentException iex)
+        {
+            // ok
+        }
+
+        try
+        {
+            node.addChild(new DefaultConfigurationNode());
+            fail("Node without name could be added!");
+        }
+        catch (IllegalArgumentException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests removing a child node.
+     */
+    public void testRemoveChild()
+    {
+        DefaultConfigurationNode child = (DefaultConfigurationNode) node
+                .getChildren().get(3);
+        int cnt = node.getChildrenCount();
+        node.removeChild(child);
+        assertEquals("Child was not removed", cnt - 1, node.getChildrenCount());
+        for (Iterator it = node.getChildren().iterator(); it.hasNext();)
+        {
+            assertNotSame("Found removed node", child, it.next());
+        }
+        assertNull("Parent reference was not removed", child.getParentNode());
+    }
+
+    /**
+     * Tests removing a child node that does not belong to this node.
+     */
+    public void testRemoveNonExistingChild()
+    {
+        int cnt = node.getChildrenCount();
+        node.removeChild(new DefaultConfigurationNode("test"));
+        node.removeChild(new DefaultConfigurationNode());
+        node.removeChild((ConfigurationNode) null);
+        node.removeChild("non existing child node");
+        node.removeChild((String) null);
+        assertEquals("Children were changed", cnt, node.getChildrenCount());
+    }
+
+    /**
+     * Tests removing children by their name.
+     */
+    public void testRemoveChildByName()
+    {
+        int cnt = node.getChildrenCount();
+        node.removeChild("name");
+        assertEquals("Child was not removed", cnt - 1, node.getChildrenCount());
+        assertEquals("Still found name child", 0, node.getChildrenCount("name"));
+        node.removeChild("field");
+        assertEquals("Still remaining nodes", 0, node.getChildrenCount());
+    }
+
+    /**
+     * Tests removing all children at once.
+     */
+    public void testRemoveChildren()
+    {
+        node.removeChildren();
+        assertEquals("Children count is not 0", 0, node.getChildrenCount());
+        assertTrue("Children are not empty", node.getChildren().isEmpty());
+    }
+
+    /**
+     * Tests accessing a child by its index.
+     */
+    public void testGetChild()
+    {
+        ConfigurationNode child = node.getChild(2);
+        assertEquals("Wrong child returned", child, node.getChildren().get(2));
+    }
+
+    /**
+     * Tests accessing child nodes with invalid indices.
+     */
+    public void testGetChildInvalidIndex()
+    {
+        try
+        {
+            node.getChild(4724);
+            fail("Could access invalid index!");
+        }
+        catch (IndexOutOfBoundsException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests accessing the node's attributes.
+     */
+    public void testGetAttributes()
+    {
+        assertEquals("Number of attributes incorrect", 1, node
+                .getAttributeCount());
+        List attributes = node.getAttributes();
+        Iterator it = attributes.iterator();
+        DefaultConfigurationNode attr = (DefaultConfigurationNode) it.next();
+        assertEquals("Wrong node", "type", attr.getName());
+        assertFalse("More attributes", it.hasNext());
+    }
+
+    /**
+     * Tests accessing the node's attributes by name.
+     */
+    public void testGetAttributesByName()
+    {
+        assertEquals("Incorrect number of attributes", 1, node
+                .getAttributeCount("type"));
+        DefaultConfigurationNode field = (DefaultConfigurationNode) node
+                .getChildren().get(1);
+        assertEquals("Incorrect number of attributes", 2, field
+                .getAttributeCount("attribute"));
+        List attrs = field.getAttributes("attribute");
+        assertEquals("Wrong value", "primarykey",
+                ((DefaultConfigurationNode) attrs.get(0)).getValue());
+        assertEquals("Wrong value", "unique", ((DefaultConfigurationNode) attrs
+                .get(1)).getValue());
+    }
+
+    /**
+     * Tests adding a new attribute node.
+     */
+    public void testAddAttribute()
+    {
+        int cnt = node.getAttributeCount();
+        DefaultConfigurationNode ndNew = new DefaultConfigurationNode("test",
+                "xyz");
+        node.addAttribute(ndNew);
+        assertEquals("New node was not added", cnt + 1, node
+                .getAttributeCount());
+        List attrs = node.getAttributes();
+        assertEquals("Incorrect number of attributes",
+                node.getAttributeCount(), attrs.size());
+        assertSame("Node was not added to end", ndNew, attrs.get(cnt));
+        assertEquals("Incorrect number of named attributes", 1, node
+                .getAttributeCount(ndNew.getName()));
+        assertTrue("Child is no attribute", ndNew.isAttribute());
+        assertSame("Parent was not set", node, ndNew.getParentNode());
+    }
+
+    /**
+     * Tests removing an attribute node.
+     */
+    public void testRemoveAttribute()
+    {
+        DefaultConfigurationNode attr = (DefaultConfigurationNode) node
+                .getAttributes().get(0);
+        int cnt = node.getAttributeCount();
+        node.removeAttribute(attr);
+        assertEquals("Attribute was not removed", cnt - 1, node
+                .getAttributeCount());
+        for (Iterator it = node.getAttributes().iterator(); it.hasNext();)
+        {
+            assertNotSame("Found removed node", attr, it.next());
+        }
+        assertNull("Parent reference was not removed", attr.getParentNode());
+    }
+
+    /**
+     * Tests removing attributes by their names.
+     */
+    public void testRemoveAttributeByName()
+    {
+        ConfigurationNode field = node.getChild(1);
+        assertEquals("Incorrect number of attributes", 3, field
+                .getAttributeCount());
+        field.removeAttribute("attribute");
+        assertEquals("Not all nodes removed", 1, field.getAttributeCount());
+        assertTrue("Remaining attributes", field.getAttributes("attribute")
+                .isEmpty());
+        field.removeAttribute("type");
+        assertEquals("Remaining attributes", 0, field.getAttributeCount());
+    }
+
+    /**
+     * Tests removing all attributes.
+     */
+    public void testRemoveAttributes()
+    {
+        node.removeAttributes();
+        assertEquals("Not all attributes removed", 0, node.getAttributeCount());
+        assertTrue("Attributes not empty", node.getAttributes().isEmpty());
+    }
+
+    /**
+     * Tests changing a node's attribute state.
+     */
+    public void testChangeAttributeState()
+    {
+        ConfigurationNode attr = node.getAttribute(0);
+        try
+        {
+            attr.setAttribute(false);
+            fail("Could change node's attribute state!");
+        }
+        catch (IllegalStateException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests the visit() method using a simple visitor.
+     */
+    public void testVisit()
+    {
+        CountNodeVisitor visitor = new CountNodeVisitor();
+        node.visit(visitor);
+        assertEquals("Not all nodes visited", 19, visitor.beforeCalls);
+        assertEquals("Different number of before and after calls",
+                visitor.beforeCalls, visitor.afterCalls);
+    }
+
+    /**
+     * Tests the visit() method with a visitor that terminates the visit
+     * process.
+     */
+    public void testVisitWithTerminate()
+    {
+        CountNodeVisitor visitor = new CountNodeVisitor(10);
+        node.visit(visitor);
+        assertEquals("Incorrect number of nodes visited", visitor.maxCalls,
+                visitor.beforeCalls);
+        assertEquals("Different number of before and after calls",
+                visitor.beforeCalls, visitor.afterCalls);
+    }
+
+    /**
+     * Tests the visit() method when null is passed in. This should throw an
+     * exception.
+     */
+    public void testVisitWithNullVisitor()
+    {
+        try
+        {
+            node.visit(null);
+            fail("Could pass in null visitor!");
+        }
+        catch (IllegalArgumentException iex)
+        {
+            // ok
+        }
+    }
+
+    /**
+     * Tests cloning a node.
+     */
+    public void testClone()
+    {
+        node.setValue("TestValue");
+        DefaultConfigurationNode clone = (DefaultConfigurationNode) node.clone();
+        assertEquals("Value not cloned", "TestValue", clone.getValue());
+        assertEquals("Name not cloned", "table", clone.getName());
+        assertEquals("Reference not cloned", "TestReference", clone.getReference());
+        assertEquals("Children were cloned", 0, clone.getChildrenCount());
+        assertEquals("Attributes were cloned", 0, clone.getAttributeCount());
+    }
+
+    /**
+     * Helper method for checking the child nodes of type &quot;field&quot;.
+     *
+     * @param itFields the iterator with the child nodes
+     */
+    private void checkFieldNodes(Iterator itFields)
+    {
+        for (int i = 0; i < FIELD_NAMES.length; i++)
+        {
+            DefaultConfigurationNode child = (DefaultConfigurationNode) itFields
+                    .next();
+            assertEquals("Wrong node", "field", child.getName());
+            List nameNodes = child.getChildren("name");
+            assertEquals("Wrong number of name nodes", 1, nameNodes.size());
+            DefaultConfigurationNode nameNode = (DefaultConfigurationNode) nameNodes
+                    .get(0);
+            assertEquals("Wrong field name", FIELD_NAMES[i], nameNode
+                    .getValue());
+        }
+    }
+
+    /**
+     * A test visitor implementation that is able to count the number of visits.
+     * It also supports a maximum number of visits to be set; if this number is
+     * reached, the <code>terminate()</code> method returns <b>true</b>.
+     */
+    static class CountNodeVisitor implements ConfigurationNodeVisitor
+    {
+        public int beforeCalls;
+
+        public int afterCalls;
+
+        public int maxCalls;
+
+        public CountNodeVisitor()
+        {
+            this(Integer.MAX_VALUE);
+        }
+
+        public CountNodeVisitor(int maxNumberOfVisits)
+        {
+            maxCalls = maxNumberOfVisits;
+        }
+
+        public void visitBeforeChildren(ConfigurationNode node)
+        {
+            beforeCalls++;
+        }
+
+        public void visitAfterChildren(ConfigurationNode node)
+        {
+            afterCalls++;
+        }
+
+        public boolean terminate()
+        {
+            return beforeCalls >= maxCalls;
+        }
+    }
+}

Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/TestDefaultConfigurationNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/TestDefaultConfigurationNode.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/TestDefaultConfigurationNode.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


Mime
View raw message