diff --git a/constretto-api/src/main/java/org/constretto/model/CArray.java b/constretto-api/src/main/java/org/constretto/model/CArray.java
index e5e29016..2c8d75e0 100644
--- a/constretto-api/src/main/java/org/constretto/model/CArray.java
+++ b/constretto-api/src/main/java/org/constretto/model/CArray.java
@@ -1,8 +1,11 @@
package org.constretto.model;
-import org.apache.commons.lang.StringUtils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
-import java.util.*;
+import org.apache.commons.lang.StringUtils;
/**
* @author Kaare Nilsen
@@ -23,12 +26,13 @@ public List data() {
}
@Override
- public Set referencedKeys() {
- Set referencedKeys = new HashSet();
+ public Iterable referencedKeys() {
+ List> referencedKeys = new ArrayList>();
for (CValue value : data) {
- referencedKeys.addAll(value.referencedKeys());
+ referencedKeys.add(value.referencedKeys());
}
- return referencedKeys;
+ return new Iter(referencedKeys.toArray(new Iterable[0]));
+
}
@Override
diff --git a/constretto-api/src/main/java/org/constretto/model/CObject.java b/constretto-api/src/main/java/org/constretto/model/CObject.java
index 7ddfec36..5bf7a272 100644
--- a/constretto-api/src/main/java/org/constretto/model/CObject.java
+++ b/constretto-api/src/main/java/org/constretto/model/CObject.java
@@ -1,8 +1,9 @@
package org.constretto.model;
-import org.apache.commons.lang.StringUtils;
-
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
/**
* @author Kaare Nilsen
@@ -23,12 +24,12 @@ public Map data() {
}
@Override
- public Set referencedKeys() {
- Set referencedKeys = new HashSet();
+ public Iterable referencedKeys() {
+ List> referencedKeys = new ArrayList>();
for (CValue value : data.values()) {
- referencedKeys.addAll(value.referencedKeys());
+ referencedKeys.add(value.referencedKeys());
}
- return referencedKeys;
+ return new Iter(referencedKeys.toArray(new Iterable[0]));
}
@Override
diff --git a/constretto-api/src/main/java/org/constretto/model/CPrimitive.java b/constretto-api/src/main/java/org/constretto/model/CPrimitive.java
index 50e3e5ae..0a524d3f 100644
--- a/constretto-api/src/main/java/org/constretto/model/CPrimitive.java
+++ b/constretto-api/src/main/java/org/constretto/model/CPrimitive.java
@@ -1,15 +1,12 @@
package org.constretto.model;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.Iterator;
import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* @author Kaare Nilsen
*/
public class CPrimitive extends CValue {
- private static final Pattern VARIABLE_PATTERN = Pattern.compile("#\\{(.*?)}");
private String value;
public CPrimitive(String value) {
@@ -25,14 +22,53 @@ public String value() {
}
@Override
- public Set referencedKeys() {
- Set referencedKeys = new HashSet();
- Matcher matcher = VARIABLE_PATTERN.matcher(value);
- while (matcher.find()) {
- String group = matcher.group(1);
- referencedKeys.add(group);
- }
- return referencedKeys;
+ public Iterable referencedKeys() {
+
+ final Iterator iterator = new Iterator() {
+
+ Boolean hasNext;
+ String s;
+
+ @Override
+ public boolean hasNext() {
+ if (hasNext != null) {
+ return hasNext;
+ }
+
+ String prefix = "#{", postfix = "}";
+
+ int startIndex = value.lastIndexOf(prefix);
+ if (startIndex < 0) {
+ hasNext = false;
+ return false;
+ }
+ int endIndex = value.indexOf(postfix, startIndex);
+ if (endIndex < 0) {
+ hasNext = false;
+ return false;
+ }
+ s = value.substring(startIndex + prefix.length(), endIndex);
+
+ return true;
+ }
+
+ @Override
+ public String next() {
+ return s;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Remove not supported");
+ }
+ };
+
+ return new Iterable() {
+ @Override
+ public Iterator iterator() {
+ return iterator;
+ }
+ };
}
@Override
diff --git a/constretto-api/src/main/java/org/constretto/model/CValue.java b/constretto-api/src/main/java/org/constretto/model/CValue.java
index df4bf2ca..3ade6485 100644
--- a/constretto-api/src/main/java/org/constretto/model/CValue.java
+++ b/constretto-api/src/main/java/org/constretto/model/CValue.java
@@ -1,5 +1,6 @@
package org.constretto.model;
+import java.util.Iterator;
import java.util.Set;
/**
@@ -7,10 +8,10 @@
*/
public abstract class CValue {
- public abstract Set referencedKeys();
+ public abstract Iterable referencedKeys();
public boolean containsVariables() {
- return !referencedKeys().isEmpty();
+ return referencedKeys().iterator().hasNext();
}
public boolean isArray(){
diff --git a/constretto-api/src/main/java/org/constretto/model/Iter.java b/constretto-api/src/main/java/org/constretto/model/Iter.java
new file mode 100644
index 00000000..d3f24837
--- /dev/null
+++ b/constretto-api/src/main/java/org/constretto/model/Iter.java
@@ -0,0 +1,38 @@
+package org.constretto.model;
+
+import java.util.Iterator;
+
+public class Iter implements Iterable {
+
+ private Iterable[] input;
+
+ public Iter(Iterable... input) {
+ this.input = input;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+
+ int index = 0;
+
+ @Override
+ public boolean hasNext() {
+ if (index >= input.length) {
+ return false;
+ }
+ return input[index].iterator().hasNext();
+ }
+
+ @Override
+ public T next() {
+ return input[index++].iterator().next();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+}
diff --git a/constretto-api/src/test/java/org/constretto/model/CArrayTest.java b/constretto-api/src/test/java/org/constretto/model/CArrayTest.java
index f2e077da..5e7d538e 100644
--- a/constretto-api/src/test/java/org/constretto/model/CArrayTest.java
+++ b/constretto-api/src/test/java/org/constretto/model/CArrayTest.java
@@ -3,6 +3,7 @@
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
import java.util.Arrays;
import static org.junit.Assert.assertArrayEquals;
@@ -32,7 +33,7 @@ public void testData() throws Exception {
@Test
public void testReferencedKeys() throws Exception {
- assertEquals(0, cArray.referencedKeys().size());
+ assertEquals(false, cArray.referencedKeys().iterator().hasNext());
}
@Test(expected = NullPointerException.class)
@@ -44,7 +45,13 @@ public void testNull() throws Exception {
@Test
public void testReplace() throws Exception {
final CArray arrayWithKey = new CArray(Arrays.asList(new CPrimitive("#{key}")));
- assertEquals(1, arrayWithKey.referencedKeys().size());
+
+ ArrayList objects = new ArrayList();
+ for (String s : arrayWithKey.referencedKeys()) {
+ objects.add(s);
+ }
+
+ assertEquals(1, objects.size());
arrayWithKey.replace("key", VALUE_ONE);
assertArrayEquals(new CValue[]{PRIMITIVE_ONE}, arrayWithKey.data().toArray(new CValue[]{}));
diff --git a/constretto-core/src/test/java/org/constretto/internal/provider/AbstractConfigurationProviderLookupTest.java b/constretto-core/src/test/java/org/constretto/internal/provider/AbstractConfigurationProviderLookupTest.java
index bab90986..68db5dbf 100644
--- a/constretto-core/src/test/java/org/constretto/internal/provider/AbstractConfigurationProviderLookupTest.java
+++ b/constretto-core/src/test/java/org/constretto/internal/provider/AbstractConfigurationProviderLookupTest.java
@@ -118,6 +118,18 @@ public void simpleLookupForKeyContainingReferencesToOtherKeys() {
assertEquals("it works when its at the end", constrettoConfiguration.evaluateToString("at-end"));
}
+ @Test
+ public void simpleLookupForKeyContainingReferencesToOtherKeyRecurive() {
+ ConstrettoConfiguration constrettoConfiguration = prepareTests();
+ assertEquals("recursive works at end", constrettoConfiguration.evaluateToString("recursive"));
+ }
+
+ @Test
+ public void simpleLookupForKeyContainingReferencesToOtherKeyNested() {
+ ConstrettoConfiguration constrettoConfiguration = prepareTests();
+ assertEquals("testuser", constrettoConfiguration.evaluateToString("nested"));
+ }
+
@Test
public void taggedLookupForKeyContainingReferencesToOtherKeys() {
ConstrettoConfiguration constrettoConfiguration = prepareTests();
diff --git a/constretto-core/src/test/resources/org/constretto/internal/provider/helper/provider-test.ini b/constretto-core/src/test/resources/org/constretto/internal/provider/helper/provider-test.ini
index a97dbcea..f45969b1 100644
--- a/constretto-core/src/test/resources/org/constretto/internal/provider/helper/provider-test.ini
+++ b/constretto-core/src/test/resources/org/constretto/internal/provider/helper/provider-test.ini
@@ -13,6 +13,13 @@
transitive=It should not work for #{transitive-circular} either
transitive-circular=#{transitive}
+ recursive=recursive works at #{#{end-value}-value}
+
+ environment=test
+ db.test.username=testuser
+ nested=#{db.#{environment}.username}
+
+
webservices-base-url=http://webservice
webservice.customer=#{webservices-base-url}/customer
diff --git a/constretto-core/src/test/resources/org/constretto/internal/provider/helper/provider-test.properties b/constretto-core/src/test/resources/org/constretto/internal/provider/helper/provider-test.properties
index 0c840631..aac76ae0 100644
--- a/constretto-core/src/test/resources/org/constretto/internal/provider/helper/provider-test.properties
+++ b/constretto-core/src/test/resources/org/constretto/internal/provider/helper/provider-test.properties
@@ -25,6 +25,11 @@ multiple-replacements=#{start-value} at the beginning and in the #{middle-value}
circular=but when used in a #{circular}. It better throw an exception before giving a stack overflow :)
transitive=It should not work for #{transitive-circular} either
transitive-circular=#{transitive}
+recursive=recursive works at #{#{end-value}-value}
+
+environment=test
+db.test.username=testuser
+nested=#{db.#{environment}.username}
#
# Used for testing that variable resolving works well together