Author: oheger Date: Wed Feb 22 11:43:20 2006 New Revision: 379859 URL: http://svn.apache.org/viewcvs?rev=379859&view=rev Log: Moved implementation of interpolation features from AbstractConfiguration to PropertiesConverter, so that it can be accessed from other objects, too (namely bean declaration classes)
Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertyConverter.java jakarta/commons/proper/configuration/trunk/xdocs/changes.xml Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java?rev=379859&r1=379858&r2=379859&view=diff ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java (original) +++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/AbstractConfiguration.java Wed Feb 22 11:43:20 2006 @@ -219,7 +219,8 @@ */ protected String interpolate(String base) { - return interpolateHelper(base, null); + Object result = interpolate((Object) base); + return (result == null) ? null : result.toString(); } /** @@ -231,14 +232,7 @@ */ protected Object interpolate(Object value) { - if (value instanceof String) - { - return interpolate((String) value); - } - else - { - return value; - } + return PropertyConverter.interpolate(value, this); } /** @@ -253,82 +247,13 @@ * subsequent interpolated variables are added afterward. * * @return the string with the interpolation taken care of + * @deprecated Interpolation is now handled by + * <code>[EMAIL PROTECTED] PropertyConverter}</code>; this method will no longer be + * called */ protected String interpolateHelper(String base, List priorVariables) { - 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(); - 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)); - String 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); - } - - Object value = resolveContainerStore(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 - { - //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(); + return base; // just a dummy implementation } /** Modified: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java?rev=379859&r1=379858&r2=379859&view=diff ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java (original) +++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertyConverter.java Wed Feb 22 11:43:20 2006 @@ -1,5 +1,5 @@ /* - * Copyright 2004-2005 The Apache Software Foundation. + * Copyright 2004-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License. @@ -714,5 +714,127 @@ { return new SingletonIterator(value); } + } + + /** + * Performs interpolation of the specified value. This method checks if the + * given value contains variables of the form <code>${...}</code>. If + * this is the case, all occurrances will be substituted by their current + * values. + * + * @param value the value to be interpolated + * @param config the current configuration object + * @return the interpolated value + */ + public static Object interpolate(Object value, AbstractConfiguration config) + { + if (value instanceof String) + { + return interpolateHelper((String) value, null, config); + } + else + { + return value; + } + } + + /** + * Recursive handler for multple levels of interpolation. This will be + * replaced when Commons Lang provides an interpolation feature. 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. + * @param config the current configuration + * @return the string with the interpolation taken care of + */ + private static String interpolateHelper(String base, List priorVariables, + AbstractConfiguration config) + { + 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 - AbstractConfiguration.END_TOKEN.length(); + StringBuffer result = new StringBuffer(); + + // FIXME: we should probably allow the escaping of the start token + while (((begin = base.indexOf(AbstractConfiguration.START_TOKEN, prec + + AbstractConfiguration.END_TOKEN.length())) > -1) + && ((end = base.indexOf(AbstractConfiguration.END_TOKEN, begin)) > -1)) + { + result.append(base.substring(prec + + AbstractConfiguration.END_TOKEN.length(), begin)); + String variable = base.substring(begin + + AbstractConfiguration.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); + } + + Object value = config.resolveContainerStore(variable); + if (value != null) + { + result.append(interpolateHelper(value.toString(), + priorVariables, config)); + + // 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 + { + // variable not defined - so put it back in the value + result.append(AbstractConfiguration.START_TOKEN); + result.append(variable); + result.append(AbstractConfiguration.END_TOKEN); + } + + prec = end; + } + result.append(base.substring(prec + + AbstractConfiguration.END_TOKEN.length(), base.length())); + return result.toString(); } } Modified: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertyConverter.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertyConverter.java?rev=379859&r1=379858&r2=379859&view=diff ============================================================================== --- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertyConverter.java (original) +++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestPropertyConverter.java Wed Feb 22 11:43:20 2006 @@ -1,3 +1,18 @@ +/* + * Copyright 2001-2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.apache.commons.configuration; import java.util.List; @@ -6,6 +21,8 @@ import junit.framework.TestCase; /** + * Test class for PropertyConverter. + * * @author Emmanuel Bourg * @version $Revision$, $Date$ */ @@ -71,4 +88,79 @@ assertEquals("3rd element", new Integer(3), it.next()); } + /** + * Tests the interpolation features. + */ + public void testInterpolateString() + { + PropertiesConfiguration config = new PropertiesConfiguration(); + config.addProperty("animal", "quick brown fox"); + config.addProperty("target", "lazy dog"); + assertEquals("Wrong interpolation", + "The quick brown fox jumps over the lazy dog.", + PropertyConverter.interpolate( + "The ${animal} jumps over the ${target}.", config)); + } + + /** + * Tests interpolation of an object. Here nothing should be substituted. + */ + public void testInterpolateObject() + { + assertEquals("Object was not correctly interpolated", new Integer(42), + PropertyConverter.interpolate(new Integer(42), + new PropertiesConfiguration())); + } + + /** + * Tests complex interpolation where the variables' values contain in turn + * other variables. + */ + public void testInterpolateRecursive() + { + PropertiesConfiguration config = new PropertiesConfiguration(); + config.addProperty("animal", "${animal_attr} fox"); + config.addProperty("target", "${target_attr} dog"); + config.addProperty("animal_attr", "quick brown"); + config.addProperty("target_attr", "lazy"); + assertEquals("Wrong complex interpolation", + "The quick brown fox jumps over the lazy dog.", + PropertyConverter.interpolate( + "The ${animal} jumps over the ${target}.", config)); + } + + /** + * Tests an interpolation that leads to a cycle. This should throw an + * exception. + */ + public void testCyclicInterpolation() + { + PropertiesConfiguration config = new PropertiesConfiguration(); + config.addProperty("animal", "${animal_attr} ${species}"); + config.addProperty("animal_attr", "quick brown"); + config.addProperty("species", "${animal}"); + try + { + PropertyConverter.interpolate("This is a ${animal}", config); + fail("Cyclic interpolation was not detected!"); + } + catch (IllegalStateException iex) + { + // ok + } + } + + /** + * Tests interpolation if a variable is unknown. Then the variable won't be + * substituted. + */ + public void testInterpolationUnknownVariable() + { + PropertiesConfiguration config = new PropertiesConfiguration(); + config.addProperty("animal", "quick brown fox"); + assertEquals("Wrong interpolation", + "The quick brown fox jumps over ${target}.", PropertyConverter + .interpolate("The ${animal} jumps over ${target}.", + config)); + } } Modified: jakarta/commons/proper/configuration/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/xdocs/changes.xml?rev=379859&r1=379858&r2=379859&view=diff ============================================================================== --- jakarta/commons/proper/configuration/trunk/xdocs/changes.xml (original) +++ jakarta/commons/proper/configuration/trunk/xdocs/changes.xml Wed Feb 22 11:43:20 2006 @@ -1,6 +1,6 @@ <?xml version="1.0"?> <!-- - Copyright 2004-2005 The Apache Software Foundation + Copyright 2004-2006 The Apache Software Foundation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,6 +23,12 @@ <body> <release version="1.3-SNAPSHOT" date="in SVN"> + <action dev="oheger" type="update"> + The implementation of the interpolation features have been extracted out + off AbstractConfiguration and moved to PropertyConverter. The + interpolateHelper() method of AbstractConfiguration is now deprectated + and will not be called any more during interpolation. + </action> <action dev="oheger" type="add" issue="38075"> A new method configurationsAdd() was added to HierarchicalConfiguration that provides a convenient way of iterating over complex list-like --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]