From 319d6865abc7311ea5e98a76e863599d871c0ce2 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Tue, 22 Sep 2020 17:25:34 +0100 Subject: [PATCH] Fix #363 - Multiple Configuration Profiles. --- .../ProfileConfigSourceInterceptor.java | 42 ++++++-- .../ProfileConfigSourceInterceptorTest.java | 95 ++++++++++++++++--- 2 files changed, 117 insertions(+), 20 deletions(-) diff --git a/implementation/src/main/java/io/smallrye/config/ProfileConfigSourceInterceptor.java b/implementation/src/main/java/io/smallrye/config/ProfileConfigSourceInterceptor.java index 5494e2b53..108dc7ae3 100644 --- a/implementation/src/main/java/io/smallrye/config/ProfileConfigSourceInterceptor.java +++ b/implementation/src/main/java/io/smallrye/config/ProfileConfigSourceInterceptor.java @@ -1,8 +1,14 @@ package io.smallrye.config; +import static io.smallrye.config.Converters.getImplicitConverter; +import static io.smallrye.config.Converters.newCollectionConverter; + +import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.NoSuchElementException; import java.util.Optional; import java.util.Set; @@ -27,10 +33,17 @@ public class ProfileConfigSourceInterceptor implements ConfigSourceInterceptor { } }; - private final String profile; + private final String[] profiles; public ProfileConfigSourceInterceptor(final String profile) { - this.profile = profile; + if (profile != null) { + List convertedProfiles = newCollectionConverter(getImplicitConverter(String.class), ArrayList::new) + .convert(profile); + Collections.reverse(convertedProfiles); + this.profiles = convertedProfiles.toArray(new String[0]); + } else { + this.profiles = new String[0]; + } } public ProfileConfigSourceInterceptor(final ConfigSourceInterceptorContext context) { @@ -40,14 +53,14 @@ public ProfileConfigSourceInterceptor(final ConfigSourceInterceptorContext conte public ProfileConfigSourceInterceptor( final ConfigSourceInterceptorContext context, final String profileConfigName) { - this.profile = Optional.ofNullable(context.proceed(profileConfigName)).map(ConfigValue::getValue).orElse(null); + this(Optional.ofNullable(context.proceed(profileConfigName)).map(ConfigValue::getValue).orElse(null)); } @Override public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { - if (profile != null) { + if (profiles.length > 0) { final String normalizeName = normalizeName(name); - final ConfigValue profileValue = context.proceed("%" + profile + "." + normalizeName); + final ConfigValue profileValue = getProfileValue(context, normalizeName); if (profileValue != null) { try { final ConfigValue originalValue = context.proceed(normalizeName); @@ -64,6 +77,17 @@ public ConfigValue getValue(final ConfigSourceInterceptorContext context, final return context.proceed(name); } + public ConfigValue getProfileValue(final ConfigSourceInterceptorContext context, final String normalizeName) { + for (String profile : profiles) { + final ConfigValue profileValue = context.proceed("%" + profile + "." + normalizeName); + if (profileValue != null) { + return profileValue; + } + } + + return null; + } + @Override public Iterator iterateNames(final ConfigSourceInterceptorContext context) { final Set names = new HashSet<>(); @@ -79,6 +103,12 @@ public Iterator iterateValues(final ConfigSourceInterceptorContext } private String normalizeName(final String name) { - return name.startsWith("%" + profile + ".") ? name.substring(profile.length() + 2) : name; + for (String profile : profiles) { + if (name.startsWith("%" + profile + ".")) { + return name.substring(profile.length() + 2); + } + } + + return name; } } diff --git a/implementation/src/test/java/io/smallrye/config/ProfileConfigSourceInterceptorTest.java b/implementation/src/test/java/io/smallrye/config/ProfileConfigSourceInterceptorTest.java index efdd81862..1241c9b79 100644 --- a/implementation/src/test/java/io/smallrye/config/ProfileConfigSourceInterceptorTest.java +++ b/implementation/src/test/java/io/smallrye/config/ProfileConfigSourceInterceptorTest.java @@ -1,5 +1,6 @@ package io.smallrye.config; +import static io.smallrye.config.KeyValuesConfigSource.config; import static io.smallrye.config.ProfileConfigSourceInterceptor.SMALLRYE_PROFILE; import static java.util.stream.Collectors.toList; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -9,6 +10,7 @@ import java.util.HashMap; import java.util.List; +import java.util.NoSuchElementException; import java.util.stream.StreamSupport; import org.eclipse.microprofile.config.Config; @@ -19,18 +21,18 @@ public class ProfileConfigSourceInterceptorTest { @Test public void profile() { - final SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1", "%prof.my.prop", "2", SMALLRYE_PROFILE, - "prof"); + final SmallRyeConfig config = buildConfig("my.prop", "1", "%prof.my.prop", "2", SMALLRYE_PROFILE, "prof"); assertEquals("2", config.getValue("my.prop", String.class)); assertEquals("my.prop", config.getConfigValue("my.prop").getName()); assertEquals("my.prop", config.getConfigValue("%prof.my.prop").getName()); + assertEquals("2", config.getConfigValue("%prof.my.prop").getValue()); } @Test public void profileOnly() { - final Config config = buildConfig("my.prop", "1", "%prof.my.prop", "2", SMALLRYE_PROFILE, "prof"); + final Config config = buildConfig("%prof.my.prop", "2", SMALLRYE_PROFILE, "prof"); assertEquals("2", config.getValue("my.prop", String.class)); } @@ -59,13 +61,24 @@ public void profileExpressions() { assertEquals("2", config.getValue("my.prop", String.class)); } + @Test + void cannotExpand() { + final Config config = new SmallRyeConfigBuilder() + .addDefaultInterceptors() + .withSources(config("my.prop", "${another.prop}", SMALLRYE_PROFILE, "prof", "config_ordinal", "1000")) + .withSources(config("my.prop", "${another.prop}", "%prof.my.prop", "2", SMALLRYE_PROFILE, "prof")) + .build(); + + assertThrows(NoSuchElementException.class, () -> config.getValue("my.prop", String.class)); + } + @Test public void customConfigProfile() { final String[] configs = { "my.prop", "1", "%prof.my.prop", "2", "config.profile", "prof" }; final Config config = new SmallRyeConfigBuilder() .addDefaultSources() .addDiscoveredInterceptors() - .withSources(KeyValuesConfigSource.config(configs)) + .withSources(config(configs)) .build(); assertEquals("2", config.getValue("my.prop", String.class)); @@ -75,14 +88,11 @@ public void customConfigProfile() { public void noConfigProfile() { final String[] configs = { "my.prop", "1", "%prof.my.prop", "2" }; final Config config = new SmallRyeConfigBuilder() - .addDefaultSources() - .withSources(KeyValuesConfigSource.config(configs)) - .withInterceptors( - new ProfileConfigSourceInterceptor("prof"), - new ExpressionConfigSourceInterceptor()) + .addDefaultInterceptors() + .withSources(config(configs)) .build(); - assertEquals("2", config.getValue("my.prop", String.class)); + assertEquals("1", config.getValue("my.prop", String.class)); } @Test @@ -166,7 +176,7 @@ public void priorityProfileOverOriginal() { @Test public void propertyNames() { - final SmallRyeConfig config = (SmallRyeConfig) buildConfig("my.prop", "1", "%prof.my.prop", "2", "%prof.prof.only", "1", + final SmallRyeConfig config = buildConfig("my.prop", "1", "%prof.my.prop", "2", "%prof.prof.only", "1", SMALLRYE_PROFILE, "prof"); assertEquals("2", config.getConfigValue("my.prop").getValue()); @@ -178,19 +188,76 @@ public void propertyNames() { assertTrue(properties.contains("prof.only")); } + @Test + void excludePropertiesFromInactiveProfiles() { + final SmallRyeConfig config = buildConfig("%prof.my.prop", "1", "%foo.another", "2"); + + final List properties = StreamSupport.stream(config.getPropertyNames().spliterator(), false).collect(toList()); + assertTrue(properties.contains("my.prop")); + assertFalse(properties.contains("another")); + } + @Test public void profileName() { final SmallRyeConfig config = new SmallRyeConfigBuilder() - .withSources(KeyValuesConfigSource.config("my.prop", "1", "%prof.my.prop", "2")) + .withSources(config("my.prop", "1", "%prof.my.prop", "2")) .withProfile("prof") .build(); assertEquals("2", config.getConfigValue("my.prop").getValue()); } - private static Config buildConfig(String... keyValues) { + @Test + void multipleProfiles() { + SmallRyeConfig config = new SmallRyeConfigBuilder() + .withSources(config(SMALLRYE_PROFILE, "common,prof", "config_ordinal", "1000")) + .withSources(config("%common.common.prop", "1234", "%prof.my.prop", "5678")) + .addDefaultInterceptors() + .build(); + + assertEquals("1234", config.getRawValue("common.prop")); + assertEquals("5678", config.getRawValue("my.prop")); + } + + @Test + void multipleProfilesSamePriority() { + SmallRyeConfig config = new SmallRyeConfigBuilder() + .withSources(config(SMALLRYE_PROFILE, "foo,bar", "config_ordinal", "1000")) + .withSources(config("%foo.common.prop", "1234", "%bar.common.prop", "5678")) + .addDefaultInterceptors() + .build(); + + assertEquals("5678", config.getRawValue("common.prop")); + } + + @Test + void multipleProfilesDifferentPriorities() { + SmallRyeConfig config = new SmallRyeConfigBuilder() + .withSources(config(SMALLRYE_PROFILE, "common,prof", "config_ordinal", "1000")) + .withSources(config("%prof.common.prop", "5678", "config_ordinal", "300")) + .withSources(config("%common.common.prop", "1234", "config_ordinal", "500")) + .addDefaultInterceptors() + .build(); + + assertEquals("5678", config.getRawValue("common.prop")); + } + + @Test + void multipleProfilesDifferentPrioritiesMain() { + SmallRyeConfig config = new SmallRyeConfigBuilder() + .withSources(config(SMALLRYE_PROFILE, "common,prof", "config_ordinal", "1000")) + .withSources(config("common.prop", "9", "config_ordinal", "900")) + .withSources(config("%prof.common.prop", "5678", "config_ordinal", "500")) + .withSources(config("%common.common.prop", "1234", "config_ordinal", "300")) + .addDefaultInterceptors() + .build(); + + assertEquals("9", config.getRawValue("common.prop")); + } + + private static SmallRyeConfig buildConfig(String... keyValues) { return new SmallRyeConfigBuilder() - .withSources(KeyValuesConfigSource.config(keyValues)) + .withSources(config(keyValues)) .withInterceptors( new ProfileConfigSourceInterceptor("prof"), new ExpressionConfigSourceInterceptor())