⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hierarchicalconfiguration.java

📁 java servlet著名论坛源代码
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
package net.myvietnam.mvncore.configuration;

/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowledgement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.apache.commons.collections.SequencedHashMap;
import org.apache.commons.lang.StringUtils;

/**
 * <p>A specialized configuration class that extends its base class by the
 * ability of keeping more structure in the stored properties.</p>
 * <p>There are some sources of configuration data that cannot be stored
 * very well in a <code>BaseConfiguration</code> object because then their
 * structure is lost. This is especially true for XML documents. This class
 * can deal with such structured configuration sources by storing the
 * properties in a tree-like organization.</p>
 * <p>The internal used storage form allows for a more sophisticated access to
 * single properties. As an example consider the following XML document:</p>
 * <p><pre>
 * &lt;database&gt;
 *   &lt;tables&gt;
 *     &lt;table&gt;
 *       &lt;name&gt;users&lt;/name&gt;
 *       &lt;fields&gt;
 *         &lt;field&gt;
 *           &lt;name&gt;lid&lt;/name&gt;
 *           &lt;type&gt;long&lt;/name&gt;
 *         &lt;/field&gt;
 *         &lt;field&gt;
 *           &lt;name&gt;usrName&lt;/name&gt;
 *           &lt;type&gt;java.lang.String&lt;/type&gt;
 *         &lt;/field&gt;
 *        ...
 *       &lt;/fields&gt;
 *     &lt;/table&gt;
 *     &lt;table&gt;
 *       &lt;name&gt;documents&lt;/name&gt;
 *       &lt;fields&gt;
 *         &lt;field&gt;
 *           &lt;name&gt;docid&lt;/name&gt;
 *           &lt;type&gt;long&lt;/type&gt;
 *         &lt;/field&gt;
 *         ...
 *       &lt;/fields&gt;
 *     &lt;/table&gt;
 *     ...
 *   &lt;/tables&gt;
 * &lt;/database&gt;
 * </pre></p>
 * <p>If this document is parsed and stored in a
 * <code>HierarchicalConfiguration</code> object (which can be done by one of
 * the sub classes), there are enhanced possibilities of accessing properties.
 * The keys for querying information can contain indices that select a certain
 * element if there are multiple hits.</p>
 * <p>For instance the key <code>tables.table(0).name</code> can be used to
 * find out the name of the first table. In opposite
 * <code>tables.table.name</code> would return a collection with the names of
 * all available tables. Similarily the key
 * <code>tables.table(1).fields.field.name</code> returns a collection with the
 * names of all fields of the second table. If another index is added after the
 * <code>field</code> element, a single field can be accessed:
 * <code>tables.table(1).fields.field(0).name</code>.</p>
 * <p>There is a <code>getMaxIndex()</code> method that returns the maximum
 * allowed index that can be added to a given property key. This method can be
 * used to iterate over all values defined for a certain property.</p>
 *
 * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
 * @version $Id: HierarchicalConfiguration.java,v 1.1 2003/12/09 08:25:30 huumai Exp $
 */
public class HierarchicalConfiguration extends AbstractConfiguration
{
    /** Constant for a new dummy key.*/
    private static final String NEW_KEY = "newKey";

    /** Stores the root node of this configuration.*/
    private Node root = new Node();

    /**
     * Creates a new instance of <code>HierarchicalConfiguration</code>.
     */
    public HierarchicalConfiguration()
    {
        super();
    }

    /**
     * Creates a new instance of <code>HierarchicalConfiguration</code>
     * and initializes it with default properties.
     * @param defaults default properties to be used
     */
    public HierarchicalConfiguration(Configuration defaults)
    {
        super(defaults);
    }

    /**
     * Returns the root node of this hierarchical configuration.
     * @return the root node
     */
    public Node getRoot()
    {
        return root;
    }

    /**
     * Sets the root node of this hierarchical configuration.
     * @param node the root node
     */
    public void setRoot(Node node)
    {
        if (node == null)
        {
            throw new IllegalArgumentException("Root node must not be null!");
        } /* if */
        root = node;
    }

    /**
     * Fetches the specified property. Performs a recursive lookup in the
     * tree with the configuration properties.
     * @param key the key to be looked up
     * @return the found value
     */
    protected Object getPropertyDirect(String key)
    {
        List nodes = fetchNodeList(key);

        if (nodes.size() == 0)
        {
            return null;
        } /* if */
        else
        {
            Container cont = new Container();
            for (Iterator it = nodes.iterator(); it.hasNext();)
            {
                Node nd = (Node) it.next();
                if (nd.getValue() != null)
                {
                    cont.add(nd.getValue());
                } /* if */
            } /* for */

            if (cont.size() < 1)
            {
                return null;
            } /* if */
            else
            {
                return (cont.size() == 1) ? cont.get(0) : cont;
            } /* else */
        } /* else */
    }

    /**
     * <p>Adds the property with the specified key.</p>
     * <p>To be able to deal with the structure supported by this configuration
     * implementation the passed in key is of importance, especially the
     * indices it might contain. The following example should clearify this:
     * Suppose the actual configuration contains the following elements:</p>
     * <p><pre>
     * tables
     *    +-- table
     *            +-- name = user
     *            +-- fields
     *                    +-- field
     *                            +-- name = uid
     *                    +-- field
     *                            +-- name = firstName
     *                    ...
     *    +-- table
     *            +-- name = documents
     *            +-- fields
     *                   ...
     * </pre></p>
     * <p>In this example a database structure is defined, e.g. all fields of
     * the first table could be accessed using the key
     * <code>tables.table(0).fields.field.name</code>. If now properties are
     * to be added, it must be exactly specified at which position in the
     * hierarchy the new property is to be inserted. So to add a new field name
     * to a table it is not enough to say just</p>
     * <p><pre>
     * config.addProperty("tables.table.fields.field.name", "newField");
     * </pre></p>
     * <p>The statement given above contains some ambiguity. For instance
     * it is not clear, to which table the new field should be added. If this
     * method finds such an ambiguity, it is resolved by following the last
     * valid path. Here this would be the last table. The same is true for the
     * <code>field</code>; because there are multiple fields and no explicit
     * index is provided, a new <code>name</code> property would be
     * added to the last field - which is propably not what was desired.</p>
     * <p>To make things clear explicit indices should be provided whenever
     * possible. In the example above the exact table could be specified by
     * providing an index for the <code>table</code> element as in
     * <code>tables.table(1).fields</code>. By specifying an index it can also
     * be expressed that at a given position in the configuration tree a new
     * branch should be added. In the example above we did not want to add
     * an additional <code>name</code> element to the last field of the table,
     * but we want a complete new <code>field</code> element. This can be
     * achieved by specifying an invalid index (like -1) after the element
     * where a new branch should be created. Given this our example would run:
     * </p><p><pre>
     * config.addProperty("tables.table(1).fields.field(-1).name", "newField");
     * </pre></p>
     * <p>With this notation it is possible to add new branches everywhere.
     * We could for instance create a new <code>table</code> element by
     * specifying</p>
     * <p><pre>
     * config.addProperty("tables.table(-1).fields.field.name", "newField2");
     * </pre></p>
     * <p>(Note that because after the <code>table</code> element a new
     * branch is created indices in following elements are not relevant; the
     * branch is new so there cannot be any ambiguities.)</p>
     * @param key the key of the new property
     * @param obj the value of the new property
     */
    protected void addPropertyDirect(String key, Object obj)
    {
        ConfigurationKey.KeyIterator it = new ConfigurationKey(key).iterator();
        Node parent = fetchAddNode(it, getRoot());

        Node child = new Node(it.currentKey(true));
        child.setValue(obj);
        parent.addChild(child);
    }

    /**
     * Adds a collection of nodes at the specified position of the
     * configuration tree. This method works similar to
     * <code>addProperty()</code>, but instead of a single property a whole
     * collection of nodes can be added - and thus complete configuration
     * sub trees. E.g. with this method it is possible to add parts of
     * another <code>HierarchicalConfiguration</code> object to this object.
     * @param key the key where the nodes are to be added; can be <b>null</b>,
     * then they are added to the root node
     * @param nodes a collection with the <code>Node</code> objects to be
     * added
     */
    public void addNodes(String key, Collection nodes)
    {
        if (nodes == null || nodes.isEmpty())
        {
            return;
        } /* if */

        Node parent;
        if (StringUtils.isEmpty(key))
        {
            parent = getRoot();
        } /* if */
        else
        {
            ConfigurationKey.KeyIterator kit =
                new ConfigurationKey(key).iterator();
            parent = fetchAddNode(kit, getRoot());

            // fetchAddNode() does not really fetch the last component,
            // but one before. So we must perform an additional step.
            ConfigurationKey keyNew =
                new ConfigurationKey(kit.currentKey(true));
            keyNew.append(NEW_KEY);
            parent = fetchAddNode(keyNew.iterator(), parent);
        } /* else */

        for (Iterator it = nodes.iterator(); it.hasNext();)
        {
            parent.addChild((Node) it.next());
        } /* for */
    }

    /**
     * Checks if this configuration is empty. Empty means that there are
     * no keys with any values, though there can be some (empty) nodes.
     * @return a flag if this configuration is empty
     */
    public boolean isEmpty()
    {
        return !nodeDefined(getRoot());
    }

    /**
     * Checks if the specified key is contained in this configuration.
     * Note that for this configuration the term &quot;contained&quot; means
     * that the key has an associated value. If there is a node for this key
     * that has no value but children (either defined or undefined), this
     * method will still return <b>false</b>.
     * @param key the key to be chekced
     * @return a flag if this key is contained in this configuration
     */
    public boolean containsKey(String key)
    {
        return getPropertyDirect(key) != null;
    }

    /**
     * Removes all values of the property with the given name.
     * @param key the key of the property to be removed
     */
    public void clearProperty(String key)
    {
        List nodes = fetchNodeList(key);

        for (Iterator it = nodes.iterator(); it.hasNext();)
        {
            removeNode((Node) it.next());
        } /* for */
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -