/**
* Copyright 2006 by Know-Center, Graz, Austria
* PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a
* joint initiative of the Federal Chancellery Austria and Graz University of
* Technology.
*
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
* the European Commission - subsequent versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
* http://www.osor.eu/eupl/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the Licence is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and
* limitations under the Licence.
*
* This product combines work with different licenses. See the "NOTICE" text
* file for details on the various modules and licenses.
* The "NOTICE" text file is part of the distribution. Any derivative works
* that you distribute must include a readable copy of the "NOTICE" text file.
*
* $Id: PropertyTree.java,v 1.4 2006/10/31 08:06:28 wprinz Exp $
*/
package at.knowcenter.wag.egov.egiz.cfg;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
/**
* This class can be used to store a property config tree. The property key are separated by the
* {@link at.knowcenter.wag.egov.egiz.cfg.PropertyTree#SPLIT_STRING}. Therefore the keys an also
* the values of a configuration is stored in nested hashes. The keys in an area are stored in a
* HashMap. The values of a key are stored in a Vector to overload some keys. The property tree can
* be used to extract sub nodes and sub keys of different tree levels.
*
* @author wlackner
* @see java.util.HashMap
* @see java.util.Vector
*/
public class PropertyTree implements Serializable {
/**
* SVUID.
*/
private static final long serialVersionUID = -1686170519955886222L;
/**
* The key split string. A key can be a complex key. Sub keys are separated from each other with
* the split string. This string is used to devide the complex key.
*/
public static final String SPLIT_STRING = "\\.";
/**
* Stores the key references to the sub nodes
*/
private Map keys_ = new HashMap(3);
/**
* Stores all values of a node
*/
private Vector values_ = new Vector(3);
/**
* The default constructor od the class.
*/
public PropertyTree() {
}
/**
* This method takes a key value tupel and store them in the property tree. The key splitted into
* different levels (splitted by the string
* {@link at.knowcenter.wag.egov.egiz.cfg.PropertyTree#SPLIT_STRING}). All subnodes not stored in
* the tree will be created. The last part of the key (last splitted element) adds the value to
* there own value data structure (Vector).
* Example: setKeyValue("key.1_level.2_level","the value for k_1_2")
null if the key is not a subtree referece
*/
private PropertyTree getLastSubTree(String splitKey) {
String[] keys = splitKey.split(SPLIT_STRING);
PropertyTree curr_tree = this;
for (int key_idx = 0; key_idx < keys.length; key_idx++) {
String key = keys[key_idx];
if (!curr_tree.containsNode(key)) {
return null;
}
curr_tree = (PropertyTree) curr_tree.getSubNode(key);
}
return curr_tree;
}
/**
* This method return the subtree that corresponds to a particular key. The key does not split.
* Therefore the key must be a children of the current node. Search only in the key map of the
* current node.
*
* @param key the key that has to be a sub node
* @return a sub tree (PropertyTree) or null
if the key is not a children of the
* current node
*/
private PropertyTree getSubNode(String key) {
return (PropertyTree) keys_.get(key);
}
/**
* Returns the last value (keys can be overloaded) of a key. The key are splitted into subnodes
* and the last node of the key is the current value holder. If a key or subnode is not in the sub
* tree the return value is null.
*
* @param key the key that holds the value (can be a nested key like "key.1.2.3"
)
* @return the value of the key (last node of the key) or null
otherwise
*/
public String getLastValue(String key) {
PropertyTree curr_tree = getLastSubTree(key);
String result = null;
if (curr_tree != null && !curr_tree.values_.isEmpty()) {
result = (String) curr_tree.values_.lastElement();
}
// if (logger_.isDebugEnabled()) {
// logger_.debug("getLastValue:" + key + "=" + result);
// }
return result;
}
/**
* Returns the first value (keys can be overloaded) of a key. The key are splitted into subnodes
* and the last node of the key is the current value holder. If a key or subnode is not in the sub
* tree the return value is null
.
*
* @param key the key that holds the value (can be a nested key like "key.1.2.3"
)
* @return the value of the key (last node of the key) or null
otherwise
*/
public String getFirstValue(String key) {
PropertyTree curr_tree = getLastSubTree(key);
String result = null;
if (curr_tree != null && !curr_tree.values_.isEmpty()) {
result = (String) curr_tree.values_.firstElement();
}
// if (logger_.isDebugEnabled()) {
// logger_.debug("getFirstValue:" + key + "=" + result);
// }
return result;
}
/**
* This method return all values of the current node. The values are stored as String values.
*
* @return the values (type String) of the current node
* @see Vector
*/
public Vector getValues() {
return values_;
}
/**
* This method return all keys (sub tree references) of the current node as a Map. The keys are
* stored as String values.
*
* @return the keys (type String) of the current node
* @see Map
*/
public Map getKeyEntries() {
return keys_;
}
/**
* This method return all keys (sub tree references) of the current node as an ArrayList. The keys
* are stored as String values.
*
* @return the keys (type String) of the current node
* @see ArrayList
*/
public ArrayList getKeys() {
if (!keys_.isEmpty()) {
Object[] objs = keys_.keySet().toArray();
ArrayList keys = new ArrayList(objs.length);
for (int idx = 0; idx < objs.length; idx++) {
keys.add((String) objs[idx]);
}
return keys;
}
return null;
}
/**
*
* This method return all sub tree references of a key as an ArrayList. The keys are stored as
* String values.
*
* @param key (can be a nested key like "key.1.2.3"
)
* @return the keys (type String) of the current node
* @see ArrayList
*/
public ArrayList getKeys(String key) {
PropertyTree curr_tree = getLastSubTree(key);
if (curr_tree != null) {
return curr_tree.getKeys();
}
return null;
}
/**
* This method return all values of a key. The values are stored as String values.
*
* @param key (can be a nested key like "key.1.2.3"
)
* @return the values (type Vector) of the key or null
if the key is not in the sub
* tree of the current node
* @see Vector
*/
public Vector getValues(String key) {
PropertyTree curr_tree = getLastSubTree(key);
if (curr_tree != null) {
return curr_tree.values_;
}
return null;
}
/**
* Store a sub tree (type PropertyTree) in the current node. The key and it's sub tree are stored
* in a HashMap.
*
* @param key the reference of the sub tree
* @param tree the sub tree of the key
* @see HashMap
*/
private void setSubTree(String key, PropertyTree tree) {
if (tree == null) {
tree = new PropertyTree();
}
keys_.put(key, tree);
}
/**
* Extracts a sub tree of a nested key. The Method returns the last sub tree of the nested key.
* Example: if the key is like: key.1.2.3
the sub tree of the last
* node 3
is returned.
*
* @param key the reference of the sub tree
* @return a sub tree of the key or null
if the key can not be found
*/
public PropertyTree getSubTree(String key) {
return getLastSubTree(key);
}
/**
* This method checks if a key is a reference to a sub tree in the current node.
*
* @param key a simple key that is a parent reference of a sub tree
* @return true if the key is found, false otherwise
*/
public boolean containsNode(String key) {
return keys_.containsKey(key);
}
/**
* The default toString method. It starts with the current node recursively downwards and return
* the String representation of the node.
*
* @return the string representation of the node
*/
public String toString() {
return toString("", this);
}
/**
* This is a helper function to define the prefix for different levels in the toString method, not
* realy nice ;-).
* It replaces all "." chars with " ".
*
* @param key
* @return a replaces prefix string
*/
private static String getEmptyString(String key) {
return key.replaceAll(".", " ");
}
/**
* This method concatenates all values of the current node and return them as a combinded string.
*
* @param prefix
* @param tree
* @return the string representation of the node values
*/
private static String printValues(String prefix, PropertyTree tree) {
String os = "";
Iterator values = tree.getValues().iterator();
while (values.hasNext()) {
String value = (String) values.next();
os += prefix + "=" + value;
}
return os;
}
/**
* The toString method. It starts with a special level prefix, sub tree and recursively adds all
* sub trees.
*
* @param prefix the prefix for this node
* @param tree the current node
* @return the string representation of the node
*/
public static String toString(String prefix, PropertyTree tree) {
String os = "";
Iterator entries = tree.getKeyEntries().entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry) entries.next();
String key = (String) entry.getKey();
PropertyTree sub = (PropertyTree) entry.getValue();
String os_key = "\n" + prefix + "." + key;
os += printValues(os_key, sub);
String subs = toString(prefix + getEmptyString(key) + " |", sub);
if (subs.length() > 0) {
os += os_key + "|" + subs;
}
}
return os;
}
public void removeEntry(String key) {
this.keys_.remove(key);
}
}