/** * Mad-Advertisement * Copyright (C) 2011 Thorsten Marx <thmarx@gmx.net> * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package net.mad.ads.common.util; import java.util.Properties; /** * A subclass of Properties that allows recursive references for property * values. For example, * * <pre> * <code> * A=12345678 * B={A}90 * C={B} plus more * </code> * </pre> * * will result in <code>getProperty("C")</code> returning the value * "1234567890 plus more". * * @author: Chris Mair */ public class XProperties extends Properties { // The prefix and suffix for constant names // within property values private static final String START_CONST = "${"; private static final String END_CONST = "}"; // The maximum depth for recursive substitution // of constants within property values // (e.g., A={B} .. B={C} .. C={D} .. etc.) private static final int MAX_SUBST_DEPTH = 5; /** * Creates an empty property list with no default values. */ public XProperties() { super(); } /** * Creates an empty property list with the specified defaults. * * @param defaults * java.util.Properties */ public XProperties(Properties defaults) { super(defaults); } /** * Searches for the property with the specified key in this property list. * If the key is not found in this property list, the default property list, * and its defaults, recursively, are then checked. The method returns * <code>null</code> if the property is not found. * * @param key * the property key. * @return the value in this property list with the specified key value. */ public String getProperty(String key) { // Return the property value starting at level 0 return getProperty(key, 0); } /** * Searches for the property with the specified key in this property list. * If the key is not found in this property list, the default property list, * and its defaults, recursively, are then checked. The method returns * <code>null</code> if the property is not found. * * <p> * The level parameter specifies the current level of recursive constant * substitution. If the requested property value includes a constant, its * value is substituted in place through a recursive call to this method, * incrementing the level. Once level exceeds MAX_SUBST_DEPTH, no further * constant substitutions are performed within the current requested value. * * @param key * the property key. * @param level * the level of recursion so far * @return the value in this property list with the specified key value. */ private String getProperty(String key, int level) { String value = super.getProperty(key); if (value != null) { // Get the index of the first constant, if any int beginIndex = 0; int startName = value.indexOf(START_CONST, beginIndex); while (startName != -1) { if (level + 1 > MAX_SUBST_DEPTH) { // Exceeded MAX_SUBST_DEPTH // Return the value as is return value; } int endName = value.indexOf(END_CONST, startName); if (endName == -1) { // Terminating symbol not found // Return the value as is return value; } String constName = value.substring(startName + 2, endName); String constValue = getProperty(constName, level + 1); if (constValue == null) { if (System.getProperties().containsKey(constName)) { constValue = System.getProperty(constName); } else { // Property name not found // Return the value as is return value; } } // Insert the constant value into the // original property value String newValue = (startName > 0) ? value.substring(0, startName) : ""; newValue += constValue; // Start checking for constants at this index beginIndex = newValue.length(); // Append the remainder of the value newValue += value.substring(endName + 1); value = newValue; // Look for the next constant startName = value.indexOf(START_CONST, beginIndex); } } // Return the value as is return value; } }