Skip to content

Commit

Permalink
Merge pull request #35 from Gmugra/26_API_Loading_strategies_2
Browse files Browse the repository at this point in the history
#26 : API: Loading strategies, refactoring
  • Loading branch information
Gmugra committed Apr 23, 2021
2 parents cf299f7 + 1033571 commit 2ba79a3
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 43 deletions.
4 changes: 0 additions & 4 deletions core/src/main/java/net/cactusthorn/config/core/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,4 @@
import java.lang.annotation.Target;

@Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface Config {
enum LoadType {
MERGE,
FIRST
}
}
50 changes: 16 additions & 34 deletions core/src/main/java/net/cactusthorn/config/core/ConfigFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,23 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

import net.cactusthorn.config.core.loader.ClasspathPropertiesLoader;
import net.cactusthorn.config.core.loader.LoadStrategy;
import net.cactusthorn.config.core.loader.Loader;

public final class ConfigFactory {

private static final MethodType CONSTRUCTOR = MethodType.methodType(void.class, Map.class);
private static final ConcurrentHashMap<Class<?>, MethodHandle> BUILDERS = new ConcurrentHashMap<>();

private final Config.LoadType loadType;
private final LoadStrategy loadStrategy;
private final Map<String, String> props;
private final LinkedHashMap<URI, Loader> uriLoaders;

private ConfigFactory(Config.LoadType loadType, Map<String, String> properties, LinkedHashMap<URI, Loader> uriLoaders) {
this.loadType = loadType;
private ConfigFactory(LoadStrategy loadStrategy, Map<String, String> properties, LinkedHashMap<URI, Loader> uriLoaders) {
this.loadStrategy = loadStrategy;
this.props = properties;
this.uriLoaders = uriLoaders;
}
Expand All @@ -45,14 +47,14 @@ public static final class Builder {
private final LinkedHashSet<URI> uris = new LinkedHashSet<>();

private Map<String, String> props = Collections.emptyMap();
private Config.LoadType load = Config.LoadType.MERGE;
private LoadStrategy loadStrategy = LoadStrategy.MERGE;

private Builder() {
loaders.add(new ClasspathPropertiesLoader());
}

public Builder setLoadPolicy(Config.LoadType loadType) {
load = loadType;
public Builder setLoadStrategy(LoadStrategy strategy) {
loadStrategy = strategy;
return this;
}

Expand Down Expand Up @@ -94,7 +96,7 @@ public ConfigFactory build() {
.orElseThrow(() -> new UnsupportedOperationException(msg(LOADER_NOT_FOUND, uri)));
uriLoaders.put(uri, loader);
}
return new ConfigFactory(load, props, uriLoaders);
return new ConfigFactory(loadStrategy, props, uriLoaders);
}
}

Expand Down Expand Up @@ -127,33 +129,13 @@ private <T> Map<String, String> load(Class<T> sourceInterface) {
if (sourceInterface == null) {
throw new IllegalArgumentException(isNull(sourceInterface));
}
if (loadType == Config.LoadType.FIRST) {
return loadFirst(sourceInterface);
}
return loadMerge(sourceInterface);
}

private <T> Map<String, String> loadFirst(Class<T> sourceInterface) {
for (Map.Entry<URI, Loader> entry : uriLoaders.entrySet()) {
Loader loader = entry.getValue();
Map<String, String> properties = loader.load(entry.getKey(), sourceInterface.getClassLoader());
if (!properties.isEmpty()) {
return properties;
}
}
return Collections.emptyMap();
}

private <T> Map<String, String> loadMerge(Class<T> sourceInterface) {
Map<String, String> result = new HashMap<>();
ArrayList<URI> keys = new ArrayList<>(uriLoaders.keySet());
for (int i = keys.size() - 1; i >= 0; i--) {
URI key = keys.get(i);
Loader loader = uriLoaders.get(key);
Map<String, String> properties = loader.load(key, sourceInterface.getClassLoader());
result.putAll(properties);
}
return result;
//TODO caching for properties by URI
// @formatter:off
return loadStrategy.combine(
uriLoaders.entrySet().stream()
.map(e -> e.getValue().load(e.getKey(), sourceInterface.getClassLoader()))
.collect(Collectors.toList()));
// @formatter:on
}

private <T> MethodHandle findBuilderConstructor(Class<T> sourceInterface) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package net.cactusthorn.config.core.loader;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

public enum LoadStrategy {
// @formatter:off
FIRST(l -> l.stream().filter(m -> !m.isEmpty()).findFirst().orElse(Collections.emptyMap())),
MERGE(l -> {
Map<String, String> result = new HashMap<>();
for (int i = l.size() - 1; i >= 0; i--) {
result.putAll(l.get(i));
}
return result;
});
// @formatter:on

private Function<List<Map<String, String>>, Map<String, String>> strategy;

LoadStrategy(Function<List<Map<String, String>>, Map<String, String>> strategy) {
this.strategy = strategy;
}

public Map<String, String> combine(List<Map<String, String>> properties) {
return strategy.apply(properties);
}
}
26 changes: 21 additions & 5 deletions core/src/test/java/net/cactusthorn/config/core/LoadTypeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,35 @@

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import net.cactusthorn.config.core.loader.LoadStrategy;

public class LoadTypeTest {

@BeforeAll static void setUpLogger() {
Logger rootLogger = LogManager.getLogManager().getLogger("");
rootLogger.setLevel(Level.FINE);
// switch off default Handlers to do not get anything in console
for (Handler h : rootLogger.getHandlers()) {
h.setLevel(Level.OFF);
}
}

@Test public void merge() {
TestConfig testConfig = ConfigFactory.create(TestConfig.class, "classpath:config/testconfig.properties",
"classpath:config/testconfig2.properties");
assertEquals("SSSSSSSS", testConfig.dstr());
}

@Test public void first() {
TestConfig testConfig = ConfigFactory.builder().setLoadPolicy(Config.LoadType.FIRST)
TestConfig testConfig = ConfigFactory.builder().setLoadStrategy(LoadStrategy.FIRST)
.addSource("classpath:config/testconfig.properties", "classpath:config/testconfig2.properties").build()
.create(TestConfig.class);
assertEquals("A", testConfig.dstr());
Expand All @@ -26,7 +42,7 @@ public class LoadTypeTest {
@Test public void withMapMerge() {
Map<String, String> properties = new HashMap<>();
properties.put("test.dstr", "FROMMAP");
TestConfig testConfig = ConfigFactory.builder().setLoadPolicy(Config.LoadType.MERGE)
TestConfig testConfig = ConfigFactory.builder().setLoadStrategy(LoadStrategy.MERGE)
.addSource("classpath:config/testconfig.properties", "classpath:config/testconfig2.properties").setSource(properties)
.build().create(TestConfig.class);
assertEquals("FROMMAP", testConfig.dstr());
Expand All @@ -35,21 +51,21 @@ public class LoadTypeTest {
@Test public void withMapFirst() {
Map<String, String> properties = new HashMap<>();
properties.put("test.dstr", "FROMMAP");
TestConfig testConfig = ConfigFactory.builder().setLoadPolicy(Config.LoadType.FIRST)
TestConfig testConfig = ConfigFactory.builder().setLoadStrategy(LoadStrategy.FIRST)
.addSource("classpath:config/testconfig.properties", "classpath:config/testconfig2.properties").setSource(properties)
.build().create(TestConfig.class);
assertEquals("FROMMAP", testConfig.dstr());
}

@Test public void firstSkipEmpty() {
TestConfig testConfig = ConfigFactory.builder().setLoadPolicy(Config.LoadType.FIRST)
TestConfig testConfig = ConfigFactory.builder().setLoadStrategy(LoadStrategy.FIRST)
.addSource("classpath:config/notExists.properties", "classpath:config/testconfig.properties").build()
.create(TestConfig.class);
assertEquals("A", testConfig.dstr());
}

@Test public void firstNotExists() {
assertThrows(IllegalArgumentException.class, () -> ConfigFactory.builder().setLoadPolicy(Config.LoadType.FIRST)
assertThrows(IllegalArgumentException.class, () -> ConfigFactory.builder().setLoadStrategy(LoadStrategy.FIRST)
.addSource("classpath:config/notExists.properties").build().create(TestConfig.class));
}
}

0 comments on commit 2ba79a3

Please sign in to comment.