/* * <copyright> * Copyright (c) 2006 by Know-Center, Graz, Austria * </copyright> * * This software is the confidential and proprietary information of Know-Center, * Graz, Austria. You shall not disclose such Confidential Information and shall * use it only in accordance with the terms of the license agreement you entered * into with Know-Center. * * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING * THIS SOFTWARE OR ITS DERIVATIVES. * * $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). <br /> * <strong>Example: </strong> <code>setKeyValue("key.1_level.2_level","the value for k_1_2")</code * * @param splitKey the key that has to be store the value * @param value only String values can be stored */ public void setKeyValue(String splitKey, String value) { 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)) { curr_tree.setSubTree(key, null); } if (key_idx < keys.length - 0) curr_tree = (PropertyTree) curr_tree.getSubTree(key); } curr_tree.addValue(value); } /** * Adds a String value to the current key * * @param value */ private void addValue(String value) { values_.add(value); } /** * This method takes a key as input value, split them into subnodes and return the sub tree of the * last node of the key. If the key or a sub node not found, the method return null. This means * the key is not part of the sub property tree. * * @param splitKey the key that has to be found as sub node of the current node * @return the sub tree (PropertyTree) or <code>null</code> 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 <code>null</code> 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 <code>null.</code> * * @param key the key that holds the value (can be a nested key like <code>"key.1.2.3"</code>) * @return the value of the key (last node of the key) or <code>null</code> 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 <code>null</code>. * * @param key the key that holds the value (can be a nested key like <code>"key.1.2.3"</code>) * @return the value of the key (last node of the key) or <code>null</code> 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 <code>"key.1.2.3"</code>) * @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 <code>"key.1.2.3"</code>) * @return the values (type Vector) of the key or <code>null</code> 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. * <strong>Example: </strong>if the key is like: <code>key.1.2.3</code> the sub tree of the last * node <code>3</code> is returned. * * @param key the reference of the sub tree * @return a sub tree of the key or <code>null</code> 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; } }