?? hierarchicalconfiguration.java
字號:
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>
* <database>
* <tables>
* <table>
* <name>users</name>
* <fields>
* <field>
* <name>lid</name>
* <type>long</name>
* </field>
* <field>
* <name>usrName</name>
* <type>java.lang.String</type>
* </field>
* ...
* </fields>
* </table>
* <table>
* <name>documents</name>
* <fields>
* <field>
* <name>docid</name>
* <type>long</type>
* </field>
* ...
* </fields>
* </table>
* ...
* </tables>
* </database>
* </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 "contained" 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 + -