From cf075f88cb8e2d841ef2691a8f4acbb9050f75f9 Mon Sep 17 00:00:00 2001 From: "David M. Lloyd" Date: Tue, 12 Mar 2024 08:04:42 -0500 Subject: [PATCH] Allow interceptors to interpose between "regular" sources and default sources (#1128) We split the interceptors and sources into two groups: those with negative priority and those with positive priority. The positive interceptors come before positive sources, which come before negative interceptors, which come before negative sources. --- .../io/smallrye/config/SmallRyeConfig.java | 58 ++++++++++++++----- .../config/SmallRyeConfigBuilder.java | 12 ++++ .../config/SmallRyeConfigSources.java | 16 ++++- .../config/ConfigConfigSourceTest.java | 2 +- 4 files changed, 69 insertions(+), 19 deletions(-) diff --git a/implementation/src/main/java/io/smallrye/config/SmallRyeConfig.java b/implementation/src/main/java/io/smallrye/config/SmallRyeConfig.java index 72a58eb7c..428274e11 100644 --- a/implementation/src/main/java/io/smallrye/config/SmallRyeConfig.java +++ b/implementation/src/main/java/io/smallrye/config/SmallRyeConfig.java @@ -707,32 +707,49 @@ private static class ConfigSources implements Serializable { sources.add(defaultValues); // Add all interceptors - List interceptors = new ArrayList<>(); + List negativeInterceptors = new ArrayList<>(); + List positiveInterceptors = new ArrayList<>(); + SmallRyeConfigSources negativeSources = new SmallRyeConfigSources(mapSources(sources), true); + SmallRyeConfigSources positiveSources = new SmallRyeConfigSources(mapSources(sources), false); List interceptorWithPriorities = buildInterceptors(builder); // Create the initial chain with initial sources and all interceptors SmallRyeConfigSourceInterceptorContext current = new SmallRyeConfigSourceInterceptorContext(EMPTY, null, config); - current = new SmallRyeConfigSourceInterceptorContext(new SmallRyeConfigSources(mapSources(sources)), current, - config); + current = new SmallRyeConfigSourceInterceptorContext(negativeSources, current, config); for (InterceptorWithPriority interceptorWithPriority : interceptorWithPriorities) { - ConfigSourceInterceptor interceptor = interceptorWithPriority.getInterceptor(current); - interceptors.add(interceptor); - current = new SmallRyeConfigSourceInterceptorContext(interceptor, current, config); + if (interceptorWithPriority.getPriority() < 0) { + ConfigSourceInterceptor interceptor = interceptorWithPriority.getInterceptor(current); + negativeInterceptors.add(interceptor); + current = new SmallRyeConfigSourceInterceptorContext(interceptor, current, config); + } + } + current = new SmallRyeConfigSourceInterceptorContext(positiveSources, current, config); + for (InterceptorWithPriority interceptorWithPriority : interceptorWithPriorities) { + if (interceptorWithPriority.getPriority() >= 0) { + ConfigSourceInterceptor interceptor = interceptorWithPriority.getInterceptor(current); + positiveInterceptors.add(interceptor); + current = new SmallRyeConfigSourceInterceptorContext(interceptor, current, config); + } } // Init all late sources - List profiles = getProfiles(interceptors); - List sourcesWithPriorities = mapLateSources(sources, interceptors, current, profiles, - builder, config); + List profiles = getProfiles(positiveInterceptors); + List sourcesWithPriorities = mapLateSources(sources, negativeInterceptors, + positiveInterceptors, current, profiles, builder, config); List configSources = getSources(sourcesWithPriorities); // Rebuild the chain with the late sources and new instances of the interceptors // The new instance will ensure that we get rid of references to factories and other stuff and keep only // the resolved final source or interceptor to use. current = new SmallRyeConfigSourceInterceptorContext(EMPTY, null, config); - current = new SmallRyeConfigSourceInterceptorContext(new SmallRyeConfigSources(sourcesWithPriorities), current, - config); - for (ConfigSourceInterceptor interceptor : interceptors) { + current = new SmallRyeConfigSourceInterceptorContext(new SmallRyeConfigSources(sourcesWithPriorities, true), + current, config); + for (ConfigSourceInterceptor interceptor : negativeInterceptors) { + current = new SmallRyeConfigSourceInterceptorContext(interceptor, current, config); + } + current = new SmallRyeConfigSourceInterceptorContext(new SmallRyeConfigSources(sourcesWithPriorities, false), + current, config); + for (ConfigSourceInterceptor interceptor : positiveInterceptors) { current = new SmallRyeConfigSourceInterceptorContext(interceptor, current, config); } @@ -797,7 +814,8 @@ private static List getProfiles(final List inte private static List mapLateSources( final List sources, - final List interceptors, + final List negativeInterceptors, + final List positiveInterceptors, final ConfigSourceInterceptorContext current, final List profiles, final SmallRyeConfigBuilder builder, @@ -823,8 +841,14 @@ private static List mapLateSources( // Rebuild the chain with the profiles sources, so profiles values are also available in factories ConfigSourceInterceptorContext context = new SmallRyeConfigSourceInterceptorContext(EMPTY, null, config); - context = new SmallRyeConfigSourceInterceptorContext(new SmallRyeConfigSources(currentSources), context, config); - for (ConfigSourceInterceptor interceptor : interceptors) { + context = new SmallRyeConfigSourceInterceptorContext(new SmallRyeConfigSources(currentSources, true), context, + config); + for (ConfigSourceInterceptor interceptor : negativeInterceptors) { + context = new SmallRyeConfigSourceInterceptorContext(interceptor, context, config); + } + context = new SmallRyeConfigSourceInterceptorContext(new SmallRyeConfigSources(currentSources, false), context, + config); + for (ConfigSourceInterceptor interceptor : positiveInterceptors) { context = new SmallRyeConfigSourceInterceptorContext(interceptor, context, config); } @@ -942,6 +966,10 @@ ConfigSource getSource() { return source; } + int priority() { + return priority; + } + @Override public int compareTo(final ConfigSourceWithPriority other) { int res = Integer.compare(this.priority, other.priority); diff --git a/implementation/src/main/java/io/smallrye/config/SmallRyeConfigBuilder.java b/implementation/src/main/java/io/smallrye/config/SmallRyeConfigBuilder.java index da3739306..438198d72 100644 --- a/implementation/src/main/java/io/smallrye/config/SmallRyeConfigBuilder.java +++ b/implementation/src/main/java/io/smallrye/config/SmallRyeConfigBuilder.java @@ -756,6 +756,18 @@ public OptionalInt getPriority() { this.priority = factory.getPriority().orElse(DEFAULT_PRIORITY); } + InterceptorWithPriority(ConfigSourceInterceptor interceptor, int priority) { + this(new ConfigSourceInterceptorFactory() { + public ConfigSourceInterceptor getInterceptor(final ConfigSourceInterceptorContext context) { + return interceptor; + } + + public OptionalInt getPriority() { + return OptionalInt.of(priority); + } + }); + } + ConfigSourceInterceptor getInterceptor(ConfigSourceInterceptorContext context) { return factory.getInterceptor(context); } diff --git a/implementation/src/main/java/io/smallrye/config/SmallRyeConfigSources.java b/implementation/src/main/java/io/smallrye/config/SmallRyeConfigSources.java index e3d949594..17deef2a2 100644 --- a/implementation/src/main/java/io/smallrye/config/SmallRyeConfigSources.java +++ b/implementation/src/main/java/io/smallrye/config/SmallRyeConfigSources.java @@ -16,11 +16,15 @@ class SmallRyeConfigSources implements ConfigSourceInterceptor { private static final long serialVersionUID = 7560201715403486552L; private final List configSources; + private final boolean negative; - SmallRyeConfigSources(final List configSourcesWithPriorities) { + SmallRyeConfigSources(final List configSourcesWithPriorities, boolean negative) { + this.negative = negative; List configSources = new ArrayList<>(); for (ConfigSourceWithPriority configSource : configSourcesWithPriorities) { - configSources.add(ConfigValueConfigSourceWrapper.wrap(configSource.getSource())); + if ((configSource.priority() < 0) == negative) { + configSources.add(ConfigValueConfigSourceWrapper.wrap(configSource.getSource())); + } } this.configSources = configSources; } @@ -34,7 +38,7 @@ public ConfigValue getValue(final ConfigSourceInterceptorContext context, final return configValue.from().withConfigSourcePosition(i).build(); } } - return null; + return context.proceed(name); } @Override @@ -46,9 +50,15 @@ public Iterator iterateNames(final ConfigSourceInterceptorContext contex names.addAll(propertyNames); } } + Iterator iter = context.iterateNames(); + iter.forEachRemaining(names::add); return names.iterator(); } + boolean negative() { + return negative; + } + static final class ConfigValueConfigSourceWrapper implements ConfigValueConfigSource, Serializable { private static final long serialVersionUID = -1109094614437147326L; diff --git a/implementation/src/test/java/io/smallrye/config/ConfigConfigSourceTest.java b/implementation/src/test/java/io/smallrye/config/ConfigConfigSourceTest.java index 2038f4277..209682834 100644 --- a/implementation/src/test/java/io/smallrye/config/ConfigConfigSourceTest.java +++ b/implementation/src/test/java/io/smallrye/config/ConfigConfigSourceTest.java @@ -200,7 +200,7 @@ public ConfigValue getValue(final ConfigSourceInterceptorContext context, final @Override public OptionalInt getPriority() { - return OptionalInt.of(Integer.MIN_VALUE); + return OptionalInt.of(0); } }) .withSources(new MapBackedConfigSource("test", new HashMap() {