From e280a3d4e4b6177d94f7a1f0847f8f5ce45fc087 Mon Sep 17 00:00:00 2001 From: Richard Tingstad Date: Fri, 11 Dec 2015 16:28:51 +0100 Subject: [PATCH] Feature proposition: Nested properties It would be cool to have the possibility to nest features, like: This is just a quick example showing that it is possible to achieve. --- .../java/org/constretto/model/CArray.java | 16 +++-- .../java/org/constretto/model/CObject.java | 15 ++--- .../java/org/constretto/model/CPrimitive.java | 60 +++++++++++++++---- .../java/org/constretto/model/CValue.java | 5 +- .../main/java/org/constretto/model/Iter.java | 38 ++++++++++++ .../java/org/constretto/model/CArrayTest.java | 11 +++- ...stractConfigurationProviderLookupTest.java | 12 ++++ .../provider/helper/provider-test.ini | 7 +++ .../provider/helper/provider-test.properties | 5 ++ 9 files changed, 140 insertions(+), 29 deletions(-) create mode 100644 constretto-api/src/main/java/org/constretto/model/Iter.java 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