Package org.apache.jorphan.collections

Source Code of org.apache.jorphan.collections.HashTree$Test

// $Header: /home/cvs/jakarta-jmeter/src/jorphan/org/apache/jorphan/collections/HashTree.java,v 1.14.2.1 2004/04/16 13:06:36 mstover1 Exp $
/*
* Copyright 2001-2004 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.jorphan.collections;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import junit.framework.TestCase;

import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;

/**
* This class is used to create a tree structure of objects.  Each element in
* the tree is also a key to the next node down in the tree.  It provides many
* ways to add objects and branches, as well as many ways to retrieve.
* <p>
* HashTree implements the Map interface for convenience reasons.  The main
* difference between a Map and a HashTree is that the HashTree organizes the
* data into a recursive tree structure, and provides the means to manipulate
* that structure.
* <p>
* Of special interest is the {@link #traverse(HashTreeTraverser)} method,
* which provides an expedient way to traverse any HashTree by implementing the
* {@link HashTreeTraverser} interface in order to perform some operation on
* the tree, or to extract information from the tree.
*
* @author Michael Stover (mstover1 at apache.org)
* @see HashTreeTraverser
* @see SearchByClass
* @version $Revision: 1.14.2.1 $ Updated on: $Date: 2004/04/16 13:06:36 $
*/
public class HashTree implements Serializable, Map
{
// GetLoggerForClass() uses ClassContext, which
// causes a Security violation in RemoteJMeterImpl
// Currently log is only used by test code, so moved there.
// N.B. Can still add logging, but would beed to use getLoggerFor() instead
//    private static Logger log =
//        LoggingManager.getLoggerForClass();

    /**
     * Creates an empty new HashTree.
     */
    public HashTree()
    {
        data = new HashMap();
    }
   
    /**
     * Creates a new HashTree and adds the given object as a top-level node.
     * @param key
     */
    public HashTree(Object key)
    {
        data = new HashMap();
        data.put(key, new HashTree());
    }
   
    /**
     * The Map given must also be a HashTree, otherwise an
     * UnsupportedOperationException is thrown.  If it is a HashTree, this is
     * like calling the add(HashTree) method.
     * @see #add(HashTree)
     * @see java.util.Map#putAll(Map)
     */
    public void putAll(Map map)
    {
        if (map instanceof HashTree)
        {
            this.add((HashTree) map);
        }
        else
        {
            throw new UnsupportedOperationException(
                    "can only putAll other HashTree objects");
        }
    }

    /**
     * Exists to satisfy the Map interface. 
     * @see java.util.Map#entrySet()
     */
    public Set entrySet()
    {
        return data.entrySet();
    }

    /**
     * Implemented as required by the Map interface, but is not very useful
     * here. All 'values' in a HashTree are HashTree's themselves.
     * 
     * @param value Object to be tested as a value.
     * @return True if the HashTree contains the value, false otherwise.
     * @see java.util.Map#containsValue(Object)
     */
    public boolean containsValue(Object value)
    {
        return data.containsValue(value);
    }

    /**
     * This is the same as calling HashTree.add(key,value).
     * @param key to use
     * @param value to store against key
     * @see java.util.Map#put(Object, Object)
     */
    public Object put(Object key, Object value)
    {
        Object previous = data.get(key);
        add(key, value);
        return previous;
    }

    /**
     * Clears the HashTree of all contents.
     * @see java.util.Map#clear()
     */
    public void clear()
    {
        data.clear();
    }

    /**
     * Returns a collection of all the sub-trees of the current tree.
     * @see java.util.Map#values()
     */
    public Collection values()
    {
        return data.values();
    }

    /**
     * Adds a key as a node at the current level and then adds the given
     * HashTree to that new node.
     *
     * @param key      key to create in this tree
     * @param subTree  sub tree to add to the node created for the first
     *                 argument.
     */
    public void add(Object key, HashTree subTree)
    {
        add(key);
        getTree(key).add(subTree);
    }

    /**
     * Adds all the nodes and branches of the given tree to this tree.  Is like
     * merging two trees.  Duplicates are ignored.
     * @param newTree
     */
    public void add(HashTree newTree)
    {
        Iterator iter = newTree.list().iterator();
        while (iter.hasNext())
        {
            Object item = iter.next();
            add(item);
            getTree(item).add(newTree.getTree(item));
        }
    }
   
    /**
     * Creates a new HashTree and adds all the objects in the given collection
     * as top-level nodes in the tree.
     *
     * @param keys a collection of objects to be added to the created HashTree.
     */
    public HashTree(Collection keys)
    {
        data = new HashMap();
        Iterator it = keys.iterator();
        while (it.hasNext())
        {
            data.put(it.next(), new HashTree());
        }
    }
   
    /**
     * Creates a new HashTree and adds all the objects in the given array as
     * top-level nodes in the tree.
     */
    public HashTree(Object[] keys)
    {
        data = new HashMap();
        for (int x = 0; x < keys.length; x++)
        {
            data.put(keys[x], new HashTree());
        }
    }

    /**
     * If the HashTree contains the given object as a key at the top level,
     * then a true result is returned, otherwise false.
     *
     * @param o Object to be tested as a key.
     * @return True if the HashTree contains the key, false otherwise.
     * @see java.util.Map#containsKey(Object)
     */
    public boolean containsKey(Object o)
    {
        return data.containsKey(o);
    }
   
    /**
     * If the HashTree is empty, true is returned, false otherwise.
     * @return True if HashTree is empty, false otherwise.
     */
    public boolean isEmpty()
    {
        return data.isEmpty();
    }
   
    /**
     * Sets a key and it's value in the HashTree.  It actually sets up a key,
     * and then creates a node for the key and sets the value to the new node,
     * as a key.  Any previous nodes that existed under the given key are lost.
     *
     * @param key   key to be set up
     * @param value value to be set up as a key in the secondary node
     */
    public void set(Object key, Object value)
    {
        data.put(key, createNewTree(value));
    }
   
    /**
     * Sets a key into the current tree and assigns it a HashTree as its
     * subtree.  Any previous entries under the given key are removed.
     *
     * @param key  key to be set up
     * @param t HashTree that the key maps to
     */
    public void set(Object key, HashTree t)
    {
        data.put(key, t);
    }
   
    /**
     * Sets a key and it's values in the HashTree.  It sets up a key in the
     * current node, and then creates a node for that key, and sets all the
     * values in the array as keys in the new node.  Any keys previously held
     * under the given key are lost.
     *
     * @param key Key to be set up
     * @param values Array of objects to be added as keys in the secondary node
     */
    public void set(Object key, Object[] values)
    {
        data.put(key, createNewTree(Arrays.asList(values)));
    }
   
    /**
     * Sets a key and its values in the HashTree.  It sets up a key in the
     * current node, and then creates a node for that key, and set all the
     * values in the array as keys in the new node.  Any keys previously held
     * under the given key are removed.
     *
     * @param key    key to be set up
     * @param values Collection of objects to be added as keys in the secondary
     *               node
     */
    public void set(Object key, Collection values)
    {
        data.put(key, createNewTree(values));
    }
   
    /**
     * Sets a series of keys into the HashTree.  It sets up the first object in
     * the key array as a key in the current node, recurses into the next
     * HashTree node through that key and adds the second object in the array.
     * Continues recursing in this manner until the end of the first array is
     * reached, at which point all the values of the second array are set as
     * keys to the bottom-most node.  All previous keys of that bottom-most
     * node are removed.
     *
     * @param treePath array of keys to put into HashTree
     * @param values   array of values to be added as keys to bottom-most node
     */
    public void set(Object[] treePath, Object[] values)
    {
        if (treePath != null && values != null)
        {
            set(Arrays.asList(treePath), Arrays.asList(values));
        }
    }
   
    /**
     * Sets a series of keys into the HashTree.  It sets up the first object in
     * the key array as a key in the current node, recurses into the next
     * HashTree node through that key and adds the second object in the array.
     * Continues recursing in this manner until the end of the first array is
     * reached, at which point all the values of the Collection of values are
     * set as keys to the bottom-most node.  Any keys previously held by the
     * bottom-most node are lost.
     *
     * @param treePath    array of keys to put into HashTree
     * @param values Collection of values to be added as keys to bottom-most
     *               node
     */
    public void set(Object[] treePath, Collection values)
    {
        if (treePath != null)
        {
            set(Arrays.asList(treePath), values);
        }
    }
   
    /**
     * Sets a series of keys into the HashTree.  It sets up the first object in
     * the key list as a key in the current node, recurses into the next
     * HashTree node through that key and adds the second object in the list.
     * Continues recursing in this manner until the end of the first list is
     * reached, at which point all the values of the array of values are set as
     * keys to the bottom-most node.  Any previously existing keys of that
     * bottom node are removed.
     *
     * @param treePath  collection of keys to put into HashTree
     * @param values    array of values to be added as keys to bottom-most node
     */
    public void set(Collection treePath, Object[] values)
    {
        HashTree tree = addTreePath(treePath);
        tree.set(Arrays.asList(values));
    }
   
    /**
     * Sets the nodes of the current tree to be the objects of the given
     * collection. Any nodes previously in the tree are removed.
     *
     * @param values  Collection of objects to set as nodes.
     */
    public void set(Collection values)
    {
        clear();
        this.add(values);
    }
   
    /**
     * Sets a series of keys into the HashTree.  It sets up the first object in
     * the key list as a key in the current node, recurses into the next
     * HashTree node through that key and adds the second object in the list.
     * Continues recursing in this manner until the end of the first list is
     * reached, at which point all the values of the Collection of values are
     * set as keys to the bottom-most node.  Any previously existing keys of
     * that bottom node are lost.
     *
     * @param treePath   list of keys to put into HashTree
     * @param values collection of values to be added as keys to bottom-most
     *               node
     */
    public void set(Collection treePath, Collection values)
    {
        HashTree tree = addTreePath(treePath);
        tree.set(values);
    }
   
    /**
     * Adds an key into the HashTree at the current level.
     *
     * @param key key to be added to HashTree
     */
    public HashTree add(Object key)
    {
        if (!data.containsKey(key))
        {
            HashTree newTree = createNewTree();
            data.put(key, newTree);
            return newTree;
        }
        else
        {
            return getTree(key);
        }
    }
   
    /**
     * Adds all the given objects as nodes at the current level.
     *
     * @param keys Array of Keys to be added to HashTree.
     */
    public void add(Object[] keys)
    {
        for (int x = 0; x < keys.length; x++)
        {
            add(keys[x]);
        }
    }
   
    /**
     * Adds a bunch of keys into the HashTree at the current level.
     *
     * @param keys Collection of Keys to be added to HashTree.
     */
    public void add(Collection keys)
    {
        Iterator it = keys.iterator();
        while (it.hasNext())
        {
            add(it.next());
        }
    }
   
    /**
     * Adds a key and it's value in the HashTree.  The first argument becomes a
     * node at the current level, and the second argument becomes a node of it.
     *
     * @param key   key to be added
     * @param value value to be added as a key in the secondary node
     */
    public HashTree add(Object key, Object value)
    {
        add(key);
        return getTree(key).add(value);
    }
   
    /**
     * Adds a key and it's values in the HashTree.  The first argument becomes
     * a node at the current level, and adds all the values in the array to
     * the new node.
     *
     * @param key    key to be added
     * @param values array of objects to be added as keys in the secondary node
     */
    public void add(Object key, Object[] values)
    {
        add(key);
        getTree(key).add(values);
    }
   
    /**
     * Adds a key as a node at the current level and then adds all the objects
     * in the second argument as nodes of the new node.
     * 
     * @param key    key to be added
     * @param values Collection of objects to be added as keys in the secondary
     *               node
     */
    public void add(Object key, Collection values)
    {
        add(key);
        getTree(key).add(values);
    }
   
    /**
     * Adds a series of nodes into the HashTree using the given path.  The
     * first argument is an array that represents a path to a specific node in
     * the tree.  If the path doesn't already exist, it is created (the objects
     * are added along the way).  At the path, all the objects in the second
     * argument are added as nodes.
     *
     * @param treePath an array of objects representing a path
     * @param values   array of values to be added as keys to bottom-most node
     */
    public void add(Object[] treePath, Object[] values)
    {
        if (treePath != null)
        {
            add(Arrays.asList(treePath), Arrays.asList(values));
        }
    }
   
    /**
     * Adds a series of nodes into the HashTree using the given path.  The
     * first argument is an array that represents a path to a specific node in
     * the tree.  If the path doesn't already exist, it is created (the objects
     * are added along the way).  At the path, all the objects in the second
     * argument are added as nodes.
     *
     * @param treePath an array of objects representing a path
     * @param values   collection of values to be added as keys to bottom-most
     *                 node
     */
    public void add(Object[] treePath, Collection values)
    {
        if (treePath != null)
        {
            add(Arrays.asList(treePath), values);
        }
    }
   
    public HashTree add(Object[] treePath,Object value)
    {
        return add(Arrays.asList(treePath),value);
    }
   
    /**
     * Adds a series of nodes into the HashTree using the given path.  The
     * first argument is a List that represents a path to a specific node in
     * the tree.  If the path doesn't already exist, it is created (the objects
     * are added along the way).  At the path, all the objects in the second
     * argument are added as nodes.
     *
     * @param treePath a list of objects representing a path
     * @param values   array of values to be added as keys to bottom-most node
     */
    public void add(Collection treePath, Object[] values)
    {
        HashTree tree = addTreePath(treePath);
        tree.add(Arrays.asList(values));
    }
   
    /**
     * Adds a series of nodes into the HashTree using the given path.  The
     * first argument is a List that represents a path to a specific node in
     * the tree.  If the path doesn't already exist, it is created (the objects
     * are added along the way).  At the path, the object in the second
     * argument is added as a node.
     *
     * @param treePath   a list of objects representing a path
     * @param value  Object to add as a node to bottom-most node
     */
    public HashTree add(Collection treePath, Object value)
    {
        HashTree tree = addTreePath(treePath);
        return tree.add(value);
    }
   
    /**
     * Adds a series of nodes into the HashTree using the given path.  The
     * first argument is a SortedSet that represents a path to a specific node
     * in the tree.  If the path doesn't already exist, it is created (the
     * objects are added along the way).  At the path, all the objects in the
     * second argument are added as nodes.
     *
     * @param treePath a SortedSet of objects representing a path
     * @param values   Collection of values to be added as keys to bottom-most
     *                 node
     */
    public void add(Collection treePath, Collection values)
    {
        HashTree tree = addTreePath(treePath);
        tree.add(values);
    }

    protected HashTree addTreePath(Collection treePath)
    {
        HashTree tree = this;
        Iterator iter = treePath.iterator();
        while (iter.hasNext())
        {
            Object temp = iter.next();
            tree.add(temp);
            tree = tree.getTree(temp);
        }
        return tree;
    }
   
    /**
     * Gets the HashTree mapped to the given key.
     * @param key Key used to find appropriate HashTree()
     */
    public HashTree getTree(Object key)
    {
        return (HashTree) data.get(key);
    }

    /**
     * Returns the HashTree object associated with the given key.  Same as
     * calling {@link #getTree(Object)}.
     *
     * @see java.util.Map#get(Object)
     */
    public Object get(Object key)
    {
        return getTree(key);
    }
   
    /**
     * Gets the HashTree object mapped to the last key in the array by
     * recursing through the HashTree structure one key at a time.
     *
     * @param treePath array of keys.
     * @return         HashTree at the end of the recursion.
     */
    public HashTree getTree(Object[] treePath)
    {
        if (treePath != null)
        {
            return getTree(Arrays.asList(treePath));
        }
        else
        {
            return this;
        }
    }

    /**
     * Create a clone of this HashTree.  This is not a deep clone (ie, the
     * contents of the tree are not cloned).
     * @see java.lang.Object#clone()
     */
    public Object clone()
    {
        HashTree newTree = new HashTree();
        cloneTree(newTree);
        return newTree;
    }
   
    protected void cloneTree(HashTree newTree)
    {
        Iterator iter = list().iterator();
        while (iter.hasNext())
        {
            Object key = iter.next();
            newTree.set(key, (HashTree) getTree(key).clone());
        }
    }

    /**
     * Creates a new tree.  This method exists to allow inheriting classes to
     * generate the appropriate types of nodes.  For instance, when a node is
     * added, it's value is a HashTree. Rather than directly calling the
     * HashTree() constructor, the createNewTree() method is called.
     * Inheriting classes should override these methods and create the
     * appropriate subclass of HashTree.
     *
     * @return HashTree
     */
    protected HashTree createNewTree()
    {
        return new HashTree();
    }

    /**
     * Creates a new tree.  This method exists to allow inheriting classes to
     * generate the appropriate types of nodes.  For instance, when a node is
     * added, it's value is a HashTree. Rather than directly calling the
     * HashTree() constructor, the createNewTree() method is called.
     * Inheriting classes should override these methods and create the
     * appropriate subclass of HashTree.
     *
     * @return HashTree
     */
    protected HashTree createNewTree(Object key)
    {
        return new HashTree(key);
    }

    /**
     * Creates a new tree.  This method exists to allow inheriting classes to
     * generate the appropriate types of nodes.  For instance, when a node is
     * added, it's value is a HashTree. Rather than directly calling the
     * HashTree() constructor, the createNewTree() method is called.
     * Inheriting classes should override these methods and create the
     * appropriate subclass of HashTree.
     *
     * @return HashTree
     */
    protected HashTree createNewTree(Collection values)
    {
        return new HashTree(values);
    }

    /**
     * Gets the HashTree object mapped to the last key in the SortedSet by
     * recursing through the HashTree structure one key at a time.
     *
     * @param treePath Collection of keys
     * @return         HashTree at the end of the recursion
     */
    public HashTree getTree(Collection treePath)
    {
        return getTreePath(treePath);
    }
   
    /**
     * Gets a Collection of all keys in the current HashTree node.  If the
     * HashTree represented a file system, this would be like getting a
     * collection of all the files in the current folder.
     *
     * @return Set of all keys in this HashTree
     */
    public Collection list()
    {
        return data.keySet();
    }
   
    /**
     * Gets a Set of all keys in the HashTree mapped to the given key of the
     * current HashTree object (in other words, one level down.  If the HashTree
     * represented a file system, this would like getting a list of all files in
     * a sub-directory (of the current directory) specified by the key argument.
     *
     * @param key  key used to find HashTree to get list of
     * @return     Set of all keys in found HashTree.
     */
    public Collection list(Object key)
    {
        HashTree temp = (HashTree) data.get(key);
        if (temp != null)
        {
            return temp.list();
        }
        else
        {
            return null;
        }
    }
   
    /**
     * Removes the entire branch specified by the given key.
     * @see java.util.Map#remove(Object)
     */
    public Object remove(Object key)
    {
        return data.remove(key);
    }
   
   
    /**
     * Recurses down into the HashTree stucture using each subsequent key in the
     * array of keys, and returns the Set of keys of the HashTree object at the
     * end of the recursion.  If the HashTree represented a file system, this
     * would be like getting a list of all the files in a directory specified by
     * the treePath, relative from the current directory.
     *
     * @param treePath Array of keys used to recurse into HashTree structure
     * @return Set of all keys found in end HashTree
     */
    public Collection list(Object[] treePath)
    {
        if (treePath != null)
        {
            return list(Arrays.asList(treePath));
        }
        else
        {
            return list();
        }
    }
   
    /**
     * Recurses down into the HashTree stucture using each subsequent key in
     * the List of keys, and returns the Set of keys of the HashTree object at
     * the end of the recursion.  If the HashTree represented a file system,
     * this would be like getting a list of all the files in a directory
     * specified by the treePath, relative from the current directory.
     *
     * @param treePath List of keys used to recurse into HashTree structure
     * @return Set of all keys found in end HashTree
     */
    public Collection list(Collection treePath)
    {
        return getTreePath(treePath).list();
    }
   
    /**
     * Finds the given current key, and replaces it with the given new key.
     * Any tree structure found under the original key is moved to the new key.
     */
    public void replace(Object currentKey, Object newKey)
    {
        HashTree tree = getTree(currentKey);
        data.remove(currentKey);
        data.put(newKey, tree);
    }
   
    /**
     * Gets an array of all keys in the current HashTree node.  If the HashTree
     * represented a file system, this would be like getting an array of all
     * the files in the current folder.
     *
     * @return array of all keys in this HashTree.
     */
    public Object[] getArray()
    {
        return data.keySet().toArray();
    }
   
    /**
     * Gets an array of all keys in the HashTree mapped to the given key of the
     * current HashTree object (in other words, one level down).  If the
     * HashTree represented a file system, this would like getting a list of
     * all files in a sub-directory (of the current directory) specified by the
     * key argument.
     *
     * @param key key used to find HashTree to get list of
     * @return    array of all keys in found HashTree
     */
    public Object[] getArray(Object key)
    {
        return getTree(key).getArray();
    }
   
    /**
     * Recurses down into the HashTree stucture using each subsequent key in
     * the array of keys, and returns an array of keys of the HashTree object
     * at the end of the recursion.  If the HashTree represented a file system,
     * this would be like getting a list of all the files in a directory
     * specified by the treePath, relative from the current directory.
     *
     * @param treePath array of keys used to recurse into HashTree structure
     * @return     array of all keys found in end HashTree
     */
    public Object[] getArray(Object[] treePath)
    {
        if (treePath != null)
        {
            return getArray(Arrays.asList(treePath));
        }
        else
        {
            return getArray();
        }
    }
   
    /**
     * Recurses down into the HashTree stucture using each subsequent key in
     * the treePath argument, and returns an array of keys of the HashTree
     * object at the end of the recursion.  If the HashTree represented a file
     * system, this would be like getting a list of all the files in a
     * directory specified by the treePath, relative from the current
     * directory.
     *
     * @param treePath list of keys used to recurse into HashTree structure
     * @return         array of all keys found in end HashTree
     */
    public Object[] getArray(Collection treePath)
    {
        HashTree tree = getTreePath(treePath);
        return tree.getArray();
    }
   
    protected HashTree getTreePath(Collection treePath)
    {
        HashTree tree = this;
        Iterator iter = treePath.iterator();
        while (iter.hasNext())
        {
            Object temp = iter.next();
            tree = tree.getTree(temp);
        }
        return tree;
    }
   
    /**
     * Returns a hashcode for this HashTree.
     * @see java.lang.Object#hashCode()
     */
    public int hashCode()
    {
        return data.hashCode() * 7;
    }
   
    /**
     * Compares all objects in the tree and verifies that the two trees contain
     * the same objects at the same tree levels.  Returns true if they do,
     * false otherwise.
     *
     * @param o Object to be compared against
     * @see java.lang.Object#equals(Object)
     */
    public boolean equals(Object o)
    {
       if (!(o instanceof HashTree)) return false;
       HashTree oo = (HashTree) o;
       if (oo.size() != this.size()) return false;
       return data.equals(oo.data);

//        boolean flag = true;
//        if (o instanceof HashTree)
//        {
//            HashTree oo = (HashTree) o;
//            Iterator it = data.keySet().iterator();
//            while (it.hasNext())
//            {
//                if (!oo.containsKey(it.next()))
//                {
//                    flag = false;
//                    break;
//                }
//            }
//            if (flag)
//            {
//                it = data.keySet().iterator();
//                while (it.hasNext())
//                {
//                    Object temp = it.next();
//                    flag = get(temp).equals(oo.get(temp));
//                    if (!flag)
//                    {
//                        break;
//                    }
//                }
//            }
//        }
//        else
//        {
//            flag = false;
//        }
//        return flag;
    }
   
    /**
     * Returns a Set of all the keys in the top-level of this HashTree.
     * @see java.util.Map#keySet()
     */
    public Set keySet()
    {
        return data.keySet();
    }
   
    /**
     * Searches the HashTree structure for the given key.  If it finds the key,
     * it returns the HashTree mapped to the key.  If it finds nothing, it
     * returns null.
     *
     * @param key Key to search for
     * @return    HashTree mapped to key, if found, otherwise <code>null</code>
     */
    public HashTree search(Object key)
    {
        HashTree result = getTree(key);
        if(result != null)
        {
            return result;
        }
        TreeSearcher searcher = new TreeSearcher(key);
        try
        {
            traverse(searcher);
        }
        catch(Exception e){
            //do nothing - means object is found
        }
        return searcher.getResult();
    }
    /**
     * Method readObject.
     */
    void readObject(ObjectInputStream ois)
        throws ClassNotFoundException, IOException
    {
        ois.defaultReadObject();
    }

    void writeObject(ObjectOutputStream oos) throws IOException
    {
        oos.defaultWriteObject();
    }

    /**
     * Returns the number of top-level entries in the HashTree.
     * @see java.util.Map#size()
     */
    public int size()
    {
        return data.size();
    }

    /**
     * Allows any implementation of the HashTreeTraverser interface to
     * easily traverse (depth-first) all the nodes of the HashTree.  The
     * Traverser implementation will be given notification of each node visited.
     *
     * @see HashTreeTraverser
     */
    public void traverse(HashTreeTraverser visitor)
    {
        Iterator iter = list().iterator();
        while (iter.hasNext())
        {
            Object item = iter.next();
            visitor.addNode(item, getTree(item));
            getTree(item).traverseInto(visitor);
        }
    }

    /**
     * The recursive method that accomplishes the tree-traversal and performs
     * the callbacks to the HashTreeTraverser.
     */
    private void traverseInto(HashTreeTraverser visitor)
    {

        if (list().size() == 0)
        {
            visitor.processPath();
        }
        else
        {
            Iterator iter = list().iterator();
          while (iter.hasNext())
          {
              Object item = iter.next();
              visitor.addNode(item, getTree(item));
              getTree(item).traverseInto(visitor);
          }
        }
        visitor.subtractNode();
    }

    public String toString()
    {
        ConvertToString converter = new ConvertToString();
        traverse(converter);
        return converter.toString();
    }

    protected Map data;
   
    private class TreeSearcher implements HashTreeTraverser
    {
        Object target;
        HashTree result;
       
        public TreeSearcher(Object t)
        {
            target = t;
        }
       
        public HashTree getResult()
        {
            return result;
        }
            /* (non-Javadoc)
         * @see org.apache.jorphan.collections.HashTreeTraverser#addNode(java.lang.Object, org.apache.jorphan.collections.HashTree)
         */
        public void addNode(Object node, HashTree subTree) {
            result = subTree.getTree(target);
            if(result != null)
            {
                throw new RuntimeException("found"); //short circuit traversal when found
            }
        }
        /* (non-Javadoc)
         * @see org.apache.jorphan.collections.HashTreeTraverser#processPath()
         */
        public void processPath() {
            // TODO Auto-generated method stub

        }
        /* (non-Javadoc)
         * @see org.apache.jorphan.collections.HashTreeTraverser#subtractNode()
         */
        public void subtractNode() {
            // TODO Auto-generated method stub

        }
}

    private class ConvertToString implements HashTreeTraverser
    {
        StringBuffer string = new StringBuffer(getClass().getName() + "{");
        StringBuffer spaces = new StringBuffer();
        int depth = 0;
        public void addNode(Object key, HashTree subTree)
        {
            depth++;
            string.append("\n" + getSpaces() + key + " {");
        }

        public void subtractNode()
        {
            string.append("\n" + getSpaces() + "}");
            depth--;
        }

        public void processPath()
        {
        }

        public String toString()
        {
            string.append("\n}");
            return string.toString();
        }

        private String getSpaces()
        {
            if (spaces.length() < depth * 2)
            {
                while (spaces.length() < depth * 2)
                {
                    spaces.append("  ");
                }
            }
            else if (spaces.length() > depth * 2)
            {
                spaces.setLength(depth * 2);
            }
            return spaces.toString();
        }
    }

    public static class Test extends TestCase
    {
        public Test(String name)
        {
            super(name);
        }

        public void testAdd1() throws Exception
        {
      Logger log =
        LoggingManager.getLoggerForClass();
            Collection treePath =
                Arrays.asList(new String[] { "1", "2", "3", "4" });
            HashTree tree = new HashTree();
            log.debug("treePath = " + treePath);
            tree.add(treePath, "value");
            log.debug("Now treePath = " + treePath);
            log.debug(tree.toString());
            assertEquals(1, tree.list(treePath).size());
            assertEquals("value", tree.getArray(treePath)[0]);
        }
       
    public void testEqualsAndHashCode() throws Exception
    {
      HashTree tree1 = new HashTree("abcd");
      HashTree tree2 = new HashTree("abcd");
      HashTree tree3 = new HashTree("abcde");
      HashTree tree4 = new HashTree("abcde");
     
      assertTrue(tree1.equals(tree1));
      assertTrue(tree1.equals(tree2));
      assertTrue(tree2.equals(tree1));
      assertTrue(tree2.equals(tree2));
      assertTrue(tree1.hashCode()==tree2.hashCode());

      assertTrue(tree3.equals(tree3));
      assertTrue(tree3.equals(tree4));
      assertTrue(tree4.equals(tree3));
      assertTrue(tree4.equals(tree4));
      assertTrue(tree3.hashCode()==tree4.hashCode());

      assertNotSame(tree1,tree2);
      assertNotSame(tree1,tree3);
      assertNotSame(tree1,tree4);
      assertNotSame(tree2,tree3);
      assertNotSame(tree2,tree4);
     
      assertFalse(tree1.equals(tree3));
      assertFalse(tree1.equals(tree4));
      assertFalse(tree2.equals(tree3));
      assertFalse(tree2.equals(tree4));
     
      assertFalse(tree1.equals(null));
      assertFalse(tree1.equals(null));
      assertFalse(tree2.equals(null));
      assertFalse(tree2.equals(null));

      tree1.add("abcd",tree3);
      assertFalse(tree1.equals(tree2));
      assertFalse(tree2.equals(tree1));// Check reflexive
      if (tree1.hashCode()==tree2.hashCode())
      {
        // This is not a requirement
        System.out.println("WARN: unequal HashTrees should not have equal hashCodes");
      }
      tree2.add("abcd",tree4);
      assertTrue(tree1.equals(tree2));
      assertTrue(tree2.equals(tree1));
      assertTrue(tree1.hashCode()==tree2.hashCode());
      }
    }
}
TOP

Related Classes of org.apache.jorphan.collections.HashTree$Test

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.