From be87a06e361cb01fd795f1facf1d6b9a03ea1aa0 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Tue, 17 Mar 2020 17:26:12 +0000 Subject: [PATCH 1/3] #Fixed 198 - Add interceptor to expand expressions in Config Values. --- implementation/pom.xml | 5 ++ .../ExpressionConfigSourceInterceptor.java | 27 +++++++++ ...ExpressionConfigSourceInterceptorTest.java | 57 +++++++++++++++++++ pom.xml | 8 +++ 4 files changed, 97 insertions(+) create mode 100644 implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java create mode 100644 implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java diff --git a/implementation/pom.xml b/implementation/pom.xml index 011e9583d..6d5ac0c5e 100644 --- a/implementation/pom.xml +++ b/implementation/pom.xml @@ -49,6 +49,11 @@ io.smallrye.config smallrye-config-common + + io.smallrye.common + smallrye-common-expression + + org.jboss.logging jboss-logging diff --git a/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java b/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java new file mode 100644 index 000000000..fa95e021a --- /dev/null +++ b/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java @@ -0,0 +1,27 @@ +package io.smallrye.config; + +import static io.smallrye.common.expression.Expression.Flag.LENIENT_SYNTAX; +import static io.smallrye.common.expression.Expression.Flag.NO_TRIM; + +import javax.annotation.Priority; + +import io.smallrye.common.expression.Expression; + +@Priority(500) +public class ExpressionConfigSourceInterceptor implements ConfigSourceInterceptor { + @Override + public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { + final ConfigValue configValue = context.proceed(name); + final Expression expression = Expression.compile(configValue.getValue(), LENIENT_SYNTAX, NO_TRIM); + final String expanded = expression.evaluate((resolveContext, stringBuilder) -> { + final ConfigValue resolve = context.proceed(resolveContext.getKey()); + if (resolve != null) { + stringBuilder.append(resolve.getValue()); + } else if (resolveContext.hasDefault()) { + resolveContext.expandDefault(); + } + }); + + return configValue.withValue(expanded); + } +} diff --git a/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java b/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java new file mode 100644 index 000000000..42e6dd794 --- /dev/null +++ b/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java @@ -0,0 +1,57 @@ +package io.smallrye.config; + +import java.util.NoSuchElementException; + +import org.eclipse.microprofile.config.Config; +import org.junit.Assert; +import org.junit.Test; + +public class ExpressionConfigSourceInterceptorTest { + @Test + public void simpleExpression() { + SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1234", "expression", "${my.prop}"); + + final String value = config.getValue("expression", String.class); + Assert.assertEquals("1234", value); + } + + @Test + public void multipleExpressions() { + SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1234", "expression", "${my.prop}${my.prop}"); + + final String value = config.getValue("expression", String.class); + Assert.assertEquals("12341234", value); + } + + @Test + public void composedExpressions() { + SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1234", "expression", "${${compose}}", "compose", + "my.prop"); + + final String value = config.getValue("expression", String.class); + Assert.assertEquals("1234", value); + } + + @Test + public void defaultExpression() { + SmallRyeConfig config = (SmallRyeConfig) buildConfig("expression", "${my.prop:1234}"); + + final String value = config.getValue("expression", String.class); + Assert.assertEquals("1234", value); + } + + @Test(expected = NoSuchElementException.class) + public void noExpression() { + SmallRyeConfig config = (SmallRyeConfig) buildConfig("expression", "${my.prop}"); + + config.getValue("expression", String.class); + } + + private static Config buildConfig(String... keyValues) { + return new SmallRyeConfigBuilder() + .addDefaultSources() + .withSources(KeyValuesConfigSource.config(keyValues)) + .withInterceptors(new ExpressionConfigSourceInterceptor()) + .build(); + } +} diff --git a/pom.xml b/pom.xml index 87c6835ff..b828756b9 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,7 @@ 1.4 + 1.0.0 SmallRye Config @@ -106,6 +107,13 @@ + + + io.smallrye.common + smallrye-common-expression + ${version.smallrye.common} + + io.smallrye.config From 95b167a1d20588666dcb5ad9bbf849313d201034 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Fri, 20 Mar 2020 13:22:27 +0000 Subject: [PATCH 2/3] #Fixed 198 - Added API to disable Expression expansion. --- .../ExpressionConfigSourceInterceptor.java | 23 +++++++++++++ .../java/io/smallrye/config/Expressions.java | 18 +++++++++++ ...ExpressionConfigSourceInterceptorTest.java | 32 ++++++++++++++++--- 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 implementation/src/main/java/io/smallrye/config/Expressions.java diff --git a/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java b/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java index fa95e021a..077c8904a 100644 --- a/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java +++ b/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java @@ -9,9 +9,16 @@ @Priority(500) public class ExpressionConfigSourceInterceptor implements ConfigSourceInterceptor { + private static final ThreadLocal ENABLE = ThreadLocal.withInitial(() -> Boolean.TRUE); + @Override public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { final ConfigValue configValue = context.proceed(name); + + if (!ENABLE.get()) { + return configValue; + } + final Expression expression = Expression.compile(configValue.getValue(), LENIENT_SYNTAX, NO_TRIM); final String expanded = expression.evaluate((resolveContext, stringBuilder) -> { final ConfigValue resolve = context.proceed(resolveContext.getKey()); @@ -24,4 +31,20 @@ public ConfigValue getValue(final ConfigSourceInterceptorContext context, final return configValue.withValue(expanded); } + + static boolean enable() { + try { + return ENABLE.get() == Boolean.FALSE; + } finally { + ENABLE.set(Boolean.TRUE); + } + } + + static boolean disable() { + try { + return ENABLE.get() == Boolean.TRUE; + } finally { + ENABLE.set(Boolean.FALSE); + } + } } diff --git a/implementation/src/main/java/io/smallrye/config/Expressions.java b/implementation/src/main/java/io/smallrye/config/Expressions.java new file mode 100644 index 000000000..fdfa59b3d --- /dev/null +++ b/implementation/src/main/java/io/smallrye/config/Expressions.java @@ -0,0 +1,18 @@ +package io.smallrye.config; + +import static io.smallrye.config.ExpressionConfigSourceInterceptor.disable; +import static io.smallrye.config.ExpressionConfigSourceInterceptor.enable; + +public class Expressions { + public static void withoutExpansion(final Runnable action) { + if (disable()) { + try { + action.run(); + } finally { + enable(); + } + } else { + action.run(); + } + } +} diff --git a/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java b/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java index 42e6dd794..a2b0adcc8 100644 --- a/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java +++ b/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java @@ -1,9 +1,10 @@ package io.smallrye.config; +import static org.junit.Assert.assertEquals; + import java.util.NoSuchElementException; import org.eclipse.microprofile.config.Config; -import org.junit.Assert; import org.junit.Test; public class ExpressionConfigSourceInterceptorTest { @@ -12,7 +13,7 @@ public void simpleExpression() { SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1234", "expression", "${my.prop}"); final String value = config.getValue("expression", String.class); - Assert.assertEquals("1234", value); + assertEquals("1234", value); } @Test @@ -20,7 +21,7 @@ public void multipleExpressions() { SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1234", "expression", "${my.prop}${my.prop}"); final String value = config.getValue("expression", String.class); - Assert.assertEquals("12341234", value); + assertEquals("12341234", value); } @Test @@ -29,7 +30,7 @@ public void composedExpressions() { "my.prop"); final String value = config.getValue("expression", String.class); - Assert.assertEquals("1234", value); + assertEquals("1234", value); } @Test @@ -37,7 +38,15 @@ public void defaultExpression() { SmallRyeConfig config = (SmallRyeConfig) buildConfig("expression", "${my.prop:1234}"); final String value = config.getValue("expression", String.class); - Assert.assertEquals("1234", value); + assertEquals("1234", value); + } + + @Test + public void defaultComposedExpression() { + SmallRyeConfig config = (SmallRyeConfig) buildConfig("expression", "${my.prop:${compose}}", "compose", "1234"); + + final String value = config.getValue("expression", String.class); + assertEquals("1234", value); } @Test(expected = NoSuchElementException.class) @@ -47,6 +56,19 @@ public void noExpression() { config.getValue("expression", String.class); } + @Test + public void withoutExpansion() { + SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1234", "expression", "${my.prop}"); + + assertEquals("1234", config.getValue("expression", String.class)); + + Expressions.withoutExpansion(() -> assertEquals("${my.prop}", config.getValue("expression", String.class))); + Expressions.withoutExpansion(() -> assertEquals("${my.prop}", config.getValue("expression", String.class))); + Expressions.withoutExpansion(() -> assertEquals("${my.prop}", config.getValue("expression", String.class))); + + assertEquals("1234", config.getValue("expression", String.class)); + } + private static Config buildConfig(String... keyValues) { return new SmallRyeConfigBuilder() .addDefaultSources() From 7821aeeb20ff893d62e40b244161d5f338519820 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Fri, 20 Mar 2020 15:46:12 +0000 Subject: [PATCH 3/3] #Fixed 198 - Added tests for empty expressions and improved log when not able to resolve expansion. --- .../ExpressionConfigSourceInterceptor.java | 9 ++++ ...ExpressionConfigSourceInterceptorTest.java | 47 ++++++++++++++----- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java b/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java index 077c8904a..9ceb1d6f9 100644 --- a/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java +++ b/implementation/src/main/java/io/smallrye/config/ExpressionConfigSourceInterceptor.java @@ -3,6 +3,8 @@ import static io.smallrye.common.expression.Expression.Flag.LENIENT_SYNTAX; import static io.smallrye.common.expression.Expression.Flag.NO_TRIM; +import java.util.NoSuchElementException; + import javax.annotation.Priority; import io.smallrye.common.expression.Expression; @@ -19,6 +21,10 @@ public ConfigValue getValue(final ConfigSourceInterceptorContext context, final return configValue; } + if (configValue == null) { + return null; + } + final Expression expression = Expression.compile(configValue.getValue(), LENIENT_SYNTAX, NO_TRIM); final String expanded = expression.evaluate((resolveContext, stringBuilder) -> { final ConfigValue resolve = context.proceed(resolveContext.getKey()); @@ -26,6 +32,9 @@ public ConfigValue getValue(final ConfigSourceInterceptorContext context, final stringBuilder.append(resolve.getValue()); } else if (resolveContext.hasDefault()) { resolveContext.expandDefault(); + } else { + throw new NoSuchElementException( + "Could not expand value " + resolveContext.getKey() + " in property " + configValue.getName()); } }); diff --git a/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java b/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java index a2b0adcc8..ff5d93303 100644 --- a/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java +++ b/implementation/src/test/java/io/smallrye/config/ExpressionConfigSourceInterceptorTest.java @@ -1,6 +1,7 @@ package io.smallrye.config; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; import java.util.NoSuchElementException; @@ -12,16 +13,14 @@ public class ExpressionConfigSourceInterceptorTest { public void simpleExpression() { SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1234", "expression", "${my.prop}"); - final String value = config.getValue("expression", String.class); - assertEquals("1234", value); + assertEquals("1234", config.getValue("expression", String.class)); } @Test public void multipleExpressions() { SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1234", "expression", "${my.prop}${my.prop}"); - final String value = config.getValue("expression", String.class); - assertEquals("12341234", value); + assertEquals("12341234", config.getValue("expression", String.class)); } @Test @@ -29,31 +28,53 @@ public void composedExpressions() { SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1234", "expression", "${${compose}}", "compose", "my.prop"); - final String value = config.getValue("expression", String.class); - assertEquals("1234", value); + assertEquals("1234", config.getValue("expression", String.class)); } @Test public void defaultExpression() { SmallRyeConfig config = (SmallRyeConfig) buildConfig("expression", "${my.prop:1234}"); - final String value = config.getValue("expression", String.class); - assertEquals("1234", value); + assertEquals("1234", config.getValue("expression", String.class)); + } + + @Test + public void defaultExpressionEmpty() { + SmallRyeConfig config = (SmallRyeConfig) buildConfig("expression", "12${my.prop:}34"); + + assertEquals("1234", config.getValue("expression", String.class)); } @Test - public void defaultComposedExpression() { + public void defaultExpressionComposed() { SmallRyeConfig config = (SmallRyeConfig) buildConfig("expression", "${my.prop:${compose}}", "compose", "1234"); - final String value = config.getValue("expression", String.class); - assertEquals("1234", value); + assertEquals("1234", config.getValue("expression", String.class)); } - @Test(expected = NoSuchElementException.class) + @Test + public void defaultExpressionComposedEmpty() { + SmallRyeConfig config = (SmallRyeConfig) buildConfig("expression", "${my.prop:${compose:}}", "my.prop", "1234"); + + assertEquals("1234", config.getValue("expression", String.class)); + } + + @Test public void noExpression() { SmallRyeConfig config = (SmallRyeConfig) buildConfig("expression", "${my.prop}"); - config.getValue("expression", String.class); + final NoSuchElementException exception = assertThrows(NoSuchElementException.class, + () -> config.getValue("expression", String.class)); + assertEquals("Could not expand value my.prop in property expression", exception.getMessage()); + } + + @Test + public void noExpressionComposed() { + SmallRyeConfig config = (SmallRyeConfig) buildConfig("expression", "${my.prop${compose}}"); + + final NoSuchElementException exception = assertThrows(NoSuchElementException.class, + () -> config.getValue("expression", String.class)); + assertEquals("Could not expand value compose in property expression", exception.getMessage()); } @Test