Skip to content

Commit

Permalink
Fixes smallrye#274. Added interceptor to activate a Configuration Pro…
Browse files Browse the repository at this point in the history
…file.
  • Loading branch information
radcortez committed Apr 7, 2020
1 parent 9937dbc commit 3286692
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 3 deletions.
21 changes: 21 additions & 0 deletions doc/modules/ROOT/pages/interceptors/interceptors.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ interceptors are registered with the same priority, then their execution order m
SmallRye Config provides the following built-in Interceptors:

* <<expression-interceptor>>
* <<profile-interceptor>>

[[expression-interceptor]]
=== ExpressionConfigSourceInterceptor
Expand Down Expand Up @@ -68,3 +69,23 @@ If an expression cannot be expanded and no default is supplied a `NoSuchElementE

The `ExpressionConfigSourceInterceptor` is not registered by default. You need to register it via the ServiceLoader
mechanism with your application.

[[profile-interceptor]]
=== ProfileConfigSourceInterceptor

The `ProfileConfigSourceInterceptor` allows you to have multiple configurations with the same name and select them via
a profile property.

To be able to set properties with the same name, you need to prefix each property with `%` followed by the profile name
and a dot:

[source,properties]
----
my.prop=1234
%dev.my.prop=5678
----

Lookup is always done using the `my.prop` property name. If you want to use the profile `dev`, you need to set the
configuration `smallrye.config.profile=dev` into any valid ConfigSource.

Only one profile can be active in any given time.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.io.Serializable;

import org.eclipse.microprofile.config.Config;

/**
* The ConfigSourceInterceptor allows you to intercept the resolution of a configuration key name before the
* configuration value is resolved by the Config.
Expand All @@ -18,6 +20,15 @@
* order may be non deterministic.
*/
public interface ConfigSourceInterceptor extends Serializable {
/**
* This method initializes the interceptor, with access to the current Config object. This allows to
* configure the interceptor using configurations retrieved from the Config.
*
* @param config the current {@code Config} associated to the interceptor.
*/
default void initialize(Config config) {
}

/**
* Single method to intercept the resolution of a configuration key. Calling
* {@link ConfigSourceInterceptorContext#proceed(String)} will proceed executing the interceptor chain. The chain
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.smallrye.config;

import javax.annotation.Priority;

import org.eclipse.microprofile.config.Config;

@Priority(600)
public class ProfileConfigSourceInterceptor implements ConfigSourceInterceptor {
public static final String SMALLRYE_PROFILE = "smallrye.config.profile";

private String profile;

public ProfileConfigSourceInterceptor() {

}

public ProfileConfigSourceInterceptor(final String profile) {
this.profile = profile;
}

@Override
public void initialize(final Config config) {
if (profile == null) {
profile = config.getOptionalValue(SMALLRYE_PROFILE, String.class).orElse(null);
}
}

@Override
public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) {
if (profile != null) {
final ConfigValue profileValue = context.proceed("%" + profile + "." + name);
if (profileValue != null) {
return profileValue;
}
}

return context.proceed(name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,19 @@ public int compare(ConfigSource o1, ConfigSource o2) {

SmallRyeConfig(SmallRyeConfigBuilder builder) {
this.configSourcesRef = buildConfigSources(builder);
this.interceptorChain = buildInterceptorChain(builder);
this.converters = buildConverters(builder);

final List<ConfigSourceInterceptor> interceptors = buildInterceptors(builder);
this.interceptorChain = buildInterceptorChain(interceptors);
initInterceptors(interceptors);
}

@Deprecated
protected SmallRyeConfig(List<ConfigSource> configSources, Map<Type, Converter<?>> converters) {
this.configSourcesRef = new AtomicReference<>(Collections.unmodifiableList(configSources));
this.converters = new ConcurrentHashMap<>(Converters.ALL_CONVERTERS);
this.converters.putAll(converters);
this.interceptorChain = buildInterceptorChain(new SmallRyeConfigBuilder());
this.interceptorChain = buildInterceptorChain(new ArrayList<>());
}

private AtomicReference<List<ConfigSource>> buildConfigSources(final SmallRyeConfigBuilder builder) {
Expand Down Expand Up @@ -124,7 +127,7 @@ private Map<Type, Converter<?>> buildConverters(final SmallRyeConfigBuilder buil
return converters;
}

private ConfigSourceInterceptorContext buildInterceptorChain(final SmallRyeConfigBuilder builder) {
private List<ConfigSourceInterceptor> buildInterceptors(final SmallRyeConfigBuilder builder) {
final List<ConfigSourceInterceptor> interceptors = new ArrayList<>(builder.getInterceptors());
if (builder.isAddDiscoveredInterceptors()) {
interceptors.addAll(builder.discoverInterceptors());
Expand All @@ -139,6 +142,10 @@ private ConfigSourceInterceptorContext buildInterceptorChain(final SmallRyeConfi
return Integer.compare(p2, p1);
});

return interceptors;
}

private ConfigSourceInterceptorContext buildInterceptorChain(final List<ConfigSourceInterceptor> interceptors) {
SmallRyeConfigSourceInterceptorContext current = new SmallRyeConfigSourceInterceptorContext(
(ConfigSourceInterceptor) (context, name) -> {
for (ConfigSource configSource : getConfigSources()) {
Expand Down Expand Up @@ -170,6 +177,12 @@ private ConfigSourceInterceptorContext buildInterceptorChain(final SmallRyeConfi
return current;
}

private void initInterceptors(final List<ConfigSourceInterceptor> interceptors) {
for (ConfigSourceInterceptor interceptor : interceptors) {
interceptor.initialize(this);
}
}

// no @Override
public <T, C extends Collection<T>> C getValues(String name, Class<T> itemClass, IntFunction<C> collectionFactory) {
return getValues(name, getConverter(itemClass), collectionFactory);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.smallrye.config;

import static io.smallrye.config.ProfileConfigSourceInterceptor.SMALLRYE_PROFILE;
import static org.junit.Assert.assertEquals;

import org.eclipse.microprofile.config.Config;
import org.junit.Test;

public class ProfileConfigSourceInterceptorTest {
@Test
public void profile() {
final Config config = buildConfig("my.prop", "1", "%prof.my.prop", "2", SMALLRYE_PROFILE, "prof");

assertEquals("2", config.getValue("my.prop", String.class));
}

@Test
public void fallback() {
final Config config = buildConfig("my.prop", "1", SMALLRYE_PROFILE, "prof");

assertEquals("1", config.getValue("my.prop", String.class));
}

@Test
public void expressions() {
final Config config = buildConfig("my.prop", "1", "%prof.my.prop", "${my.prop}", SMALLRYE_PROFILE, "prof");

assertEquals("1", config.getValue("my.prop", String.class));
}

@Test
public void profileExpressions() {
final Config config = buildConfig("my.prop", "1",
"%prof.my.prop", "${%prof.my.prop.profile}",
"%prof.my.prop.profile", "2",
SMALLRYE_PROFILE, "prof");

assertEquals("2", config.getValue("my.prop", String.class));
}

private static Config buildConfig(String... keyValues) {
return new SmallRyeConfigBuilder()
.addDefaultSources()
.withSources(KeyValuesConfigSource.config(keyValues))
.withInterceptors(new ProfileConfigSourceInterceptor(), new ExpressionConfigSourceInterceptor())
.build();
}
}

0 comments on commit 3286692

Please sign in to comment.