You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by bu...@apache.org on 2003/12/16 05:15:46 UTC

DO NOT REPLY [Bug 25553] New: - [Patch] [Collections] ExtendedProperties.interpolate does not do recursive substitution

DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=25553>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=25553

[Patch] [Collections] ExtendedProperties.interpolate does not do recursive substitution

           Summary: [Patch] [Collections] ExtendedProperties.interpolate
                    does not do recursive substitution
           Product: Commons
           Version: 2.1 Final
          Platform: Other
        OS/Version: Other
            Status: NEW
          Severity: Normal
          Priority: Other
         Component: Collections
        AssignedTo: commons-dev@jakarta.apache.org
        ReportedBy: whoschek@lbl.gov


[Patch] [Collections] ExtendedProperties.interpolate does not do recursive
substitution in commons-collections-2.1, but it probably should, when used with
getString(...).

Example:

firefish.home=/tmp/firefish
database.dir=${firefish.home}/samples/cfengine
database.file=${database.dir}/db.xml

extendedProps.getString("database.file")

I found out that this can be fixed with the patch below, which is simply a copy
and paste from the CVS of org.apache.commons.configuration.AbstractConfiguration.

	/**
	 * interpolate key names to handle ${key} stuff
	 *
	 * @param base string to interpolate
	 *
	 * @return returns the key name with the ${key} substituted
	 */
	protected String interpolate(String base)
	// copied from org.apache.commons.configuration.AbstractConfiguration
	{
		return (interpolateHelper(base, null));
	}

	/**
	 * Recursive handler for multple levels of interpolation.
	 *
	 * When called the first time, priorVariables should be null.
	 *
	 * @param base string with the ${key} variables
	 * @param priorVariables serves two purposes: to allow checking for
	 * loops, and creating a meaningful exception message should a loop
	 * occur.  It's 0'th element will be set to the value of base from
	 * the first call.  All subsequent interpolated variables are added
	 * afterward.
	 *
	 * @return the string with the interpolation taken care of
	 */
	protected String interpolateHelper(String base, List priorVariables)
	// copied from org.apache.commons.configuration.AbstractConfiguration
	{
		if (base == null)
		{
			return null;
		}

		// on the first call initialize priorVariables
		// and add base as the first element
		if (priorVariables == null)
		{
			priorVariables = new ArrayList();
			priorVariables.add(base);
		}

		int begin = -1;
		int end = -1;
		int prec = 0 - END_TOKEN.length();
		String variable = null;
		StringBuffer result = new StringBuffer();

		// FIXME: we should probably allow the escaping of the start token
		while (((begin = base.indexOf(START_TOKEN, prec + END_TOKEN.length()))
			> -1)
			&& ((end = base.indexOf(END_TOKEN, begin)) > -1))
		{
			result.append(base.substring(prec + END_TOKEN.length(), begin));
			variable = base.substring(begin + START_TOKEN.length(), end);

			// if we've got a loop, create a useful exception message and throw
			if (priorVariables.contains(variable))
			{
				String initialBase = priorVariables.remove(0).toString();
				priorVariables.add(variable);
				StringBuffer priorVariableSb = new StringBuffer();

				// create a nice trace of interpolated variables like so:
				// var1->var2->var3
				for (Iterator it = priorVariables.iterator(); it.hasNext();)
				{
					priorVariableSb.append(it.next());
					if (it.hasNext())
					{
						priorVariableSb.append("->");
					}
				}

				throw new IllegalStateException(
					"infinite loop in property interpolation of "
						+ initialBase
						+ ": "
						+ priorVariableSb.toString());
			}
			// otherwise, add this variable to the interpolation list.
			else
			{
				priorVariables.add(variable);
			}

			//QUESTION: getProperty or getPropertyDirect
			Object value = getProperty(variable);
			if (value != null)
			{
				result.append(interpolateHelper(value.toString(),
					priorVariables));

				// pop the interpolated variable off the stack
				// this maintains priorVariables correctness for
				// properties with multiple interpolations, e.g.
				// prop.name=${some.other.prop1}/blahblah/${some.other.prop2}
				priorVariables.remove(priorVariables.size() - 1);
			}
			else if (defaults != null && defaults.getString(variable,
				null) != null)
			{
				result.append(defaults.getString(variable));
			}
			else
			{
				//variable not defined - so put it back in the value
				result.append(START_TOKEN).append(variable).append(END_TOKEN);
			}
			prec = end;
		}
		result.append(base.substring(prec + END_TOKEN.length(), base.length()));

		return result.toString();
	}

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org