I don't have much experience sending patches, so please let me know if I could have
sent this in a better way.
This patch does two things:
1) fixes configuration so it builds w/ maven
2) adds support for multiple levels of interpolation
1)a) maven.xml had a bad variable reference that caused test.properties to be copied
to the wrong place which caused TestClassPropertiesConfiguration to fail
1)b) project.xml had a bad unit test excludes that didn't exclude an abstract TestCase
class
2)a) BaseConfiguration.java now supports multiple levels of interpolation. for
example:
base.prop = /base
first.prop = ${base.prop}/first
second.prop = ${first.prop}/second
second.prop now interpolates "/base/first/second" whereas before it interpolated to
"${base.prop}/first/second".
Checks are also in place to catch the case of looping references, e.g.
prop.a=${prop.b}
prop.b=${prop.a}
2)b) TestBaseConfiguration.java has tests to check for proper behavior
2)c) BasePropertiesConfiguration.java now has class javadocs that note support for
interpolation
+jeff
Index: maven.xml
===================================================================
RCS file: /home/cvspublic/jakarta-commons-sandbox/configuration/maven.xml,v
retrieving revision 1.2
diff -u -r1.2 maven.xml
--- maven.xml 14 Dec 2002 11:43:32 -0000 1.2
+++ maven.xml 24 Jan 2003 01:59:03 -0000
@@ -9,7 +9,7 @@
<project default="java:jar">
<postGoal name="test:compile">
- <copy todir="${maven.test.dest}/org/apache/commons/configuration">
+ <copy todir="${maven.build.dest}/org/apache/commons/configuration">
<fileset dir="${maven.conf.dir}" includes="*.properties"/>
</copy>
</postGoal>
Index: project.xml
===================================================================
RCS file: /home/cvspublic/jakarta-commons-sandbox/configuration/project.xml,v
retrieving revision 1.20
diff -u -r1.20 project.xml
--- project.xml 14 Jan 2003 03:53:12 -0000 1.20
+++ project.xml 24 Jan 2003 01:59:03 -0000
@@ -144,8 +144,10 @@
<unitTest>
<includes>
<include>**/*Test*.java</include>
- <exclude>**/TestBasePropertiesConfiguration.java</exclude>
</includes>
+ <excludes>
+ <exclude>**/TestBasePropertiesConfiguration.java</exclude>
+ </excludes>
<resources>
<resource>
<directory>conf</directory>
Index: src/java/org/apache/commons/configuration/BaseConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons-sandbox/configuration/src/java/org/apache/commons/configuration/BaseConfiguration.java,v
retrieving revision 1.9
diff -u -r1.9 BaseConfiguration.java
--- src/java/org/apache/commons/configuration/BaseConfiguration.java 22 Jan 2003
03:00:21 -0000 1.9
+++ src/java/org/apache/commons/configuration/BaseConfiguration.java 24 Jan 2003
+01:59:03 -0000
@@ -256,16 +256,41 @@
store.put(key, obj);
}
+ /**
+ * interpolate key names to handle ${key} stuff
+ */
+ protected String interpolate(String base )
+ {
+ return( interpolateHelper( base, null ) );
+ }
+
/**
- * interpolate key names to handle ${key} stuff
+ *
+ * Recursive handler for multple levels of interpolation.
+ *
+ * When called the first time, priorVariables should be null.
+ *
+ * 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.
+ *
*/
- protected String interpolate(String base)
+ 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();
@@ -278,9 +303,43 @@
{
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 );
+ }
+
if (store.get(variable) != null)
{
- result.append(store.get(variable));
+ result.append(interpolateHelper( store.get(variable).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)
{
Index: src/java/org/apache/commons/configuration/BasePropertiesConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons-sandbox/configuration/src/java/org/apache/commons/configuration/BasePropertiesConfiguration.java,v
retrieving revision 1.4
diff -u -r1.4 BasePropertiesConfiguration.java
--- src/java/org/apache/commons/configuration/BasePropertiesConfiguration.java 13 Jan
2003 19:29:38 -0000 1.4
+++ src/java/org/apache/commons/configuration/BasePropertiesConfiguration.java 24 Jan
+2003 01:59:03 -0000
@@ -138,6 +138,11 @@
*
* # commas may be escaped in tokens
* commas.excaped = Hi\, what'up?
+ *
+ * # properties can reference other properties
+ * base.prop = /base
+ * first.prop = ${base.prop}/first
+ * second.prop = ${first.prop}/second
* </pre>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Stefano Mazzocchi</a>
Index: src/test/org/apache/commons/configuration/TestBaseConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons-sandbox/configuration/src/test/org/apache/commons/configuration/TestBaseConfiguration.java,v
retrieving revision 1.4
diff -u -r1.4 TestBaseConfiguration.java
--- src/test/org/apache/commons/configuration/TestBaseConfiguration.java 13 Jan
2003 23:08:13 -0000 1.4
+++ src/test/org/apache/commons/configuration/TestBaseConfiguration.java 24 Jan
+2003 01:59:03 -0000
@@ -267,4 +267,34 @@
"/home/applicationRoot/1",
arrayInt[0]);
}
+
+ public void testMultipleInterpolation() throws Exception
+ {
+ eprop.setProperty( "test.base-level", "/base-level" );
+ eprop.setProperty( "test.first-level", "${test.base-level}/first-level" );
+ eprop.setProperty( "test.second-level", "${test.first-level}/second-level" );
+ eprop.setProperty( "test.third-level", "${test.second-level}/third-level" );
+
+ String expectedValue = "/base-level/first-level/second-level/third-level";
+
+ assertEquals( eprop.getString( "test.third-level" ), expectedValue );
+ }
+
+ public void testInterpolationLoop() throws Exception
+ {
+ eprop.setProperty( "test.a", "${test.b}" );
+ eprop.setProperty( "test.b", "${test.a}" );
+
+ try {
+ eprop.getString( "test.a" );
+ }
+ catch( IllegalStateException e ) {
+ e.printStackTrace();
+ return;
+ }
+
+ fail( "IllegalStateException should have been thrown for looped property
+references" );
+ }
+
+
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>