Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamic typesafe config provider, with support for Duration/ConfigMemorySize #409

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 28 additions & 32 deletions archaius2-core/src/main/java/com/netflix/archaius/ConfigMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,18 @@
*/
package com.netflix.archaius;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.text.StrSubstitutor;

import com.netflix.archaius.api.Config;
import com.netflix.archaius.api.IoCContainer;
import com.netflix.archaius.api.annotations.Configuration;
import com.netflix.archaius.exceptions.MappingException;
import com.netflix.archaius.interpolate.ConfigStrLookup;
import org.apache.commons.lang3.text.StrSubstitutor;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

public class ConfigMapper {
private static final IoCContainer NULL_IOC_CONTAINER = new IoCContainer() {
Expand All @@ -43,7 +42,6 @@ public <T> T getInstance(String name, Class<T> type) {
*
* @param injectee
* @param config
* @param ioc
* @throws MappingException
*/
public <T> void mapConfig(T injectee, Config config) throws MappingException {
Expand Down Expand Up @@ -111,18 +109,8 @@ public <T> void mapConfig(T injectee, final Config config, IoCContainer ioc) thr

String name = field.getName();
Class<?> type = field.getType();
Object value = null;
if (type.isInterface()) {
// TODO: Do Class.newInstance() if objName is a classname
String objName = config.getString(prefix + name, null);
if (objName != null) {
value = ioc.getInstance(objName, type);
}
}
else {
value = config.get(type, prefix + name, null);
}

Object value = getValue(config, ioc, prefix, name, type);

if (value != null) {
try {
field.setAccessible(true);
Expand Down Expand Up @@ -160,17 +148,8 @@ else if (name.startsWith("with") && name.length() > 4) {

method.setAccessible(true);
Class<?> type = method.getParameterTypes()[0];
Object value = null;
if (type.isInterface()) {
String objName = config.getString(prefix + name, null);
if (objName != null) {
value = ioc.getInstance(objName, type);
}
}
else {
value = config.get(type, prefix + name, null);
}

Object value = getValue(config, ioc, prefix, name, type);

if (value != null) {
try {
method.invoke(injectee, value);
Expand All @@ -190,4 +169,21 @@ else if (name.startsWith("with") && name.length() > 4) {
}
}
}

private Object getValue(Config config, IoCContainer ioc, String prefix, String name, Class<?> type) {
if (type.isInterface()) {
Object rawProperty = config.getRawProperty(prefix + name);
if (rawProperty != null && type.isAssignableFrom(rawProperty.getClass())) {
return rawProperty;
}

// TODO: Do Class.newInstance() if objName is a classname
String objName = config.getString(prefix + name, null);
if (objName != null) {
return ioc.getInstance(objName, type);
}
}

return config.get(type, prefix + name, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ public class MapConfig extends AbstractConfig {
* @author elandau
*/
public static class Builder {
Map<String, String> map = new HashMap<String, String>();
Map<String, Object> map = new HashMap<String, Object>();

public <T> Builder put(String key, T value) {
map.put(key, value.toString());
map.put(key, value);
return this;
}

Expand All @@ -60,19 +60,18 @@ public static Builder builder() {
public static MapConfig from(Properties props) {
return new MapConfig(props);
}
public static MapConfig from(Map<String, String> props) {

public static MapConfig from(Map<String, Object> props) {
return new MapConfig(props);
}
private Map<String, String> props = new HashMap<String, String>();

private Map<String, Object> props = new HashMap<String, Object>();

/**
* Construct a MapConfig as a copy of the provided Map
* @param name
* @param props
*/
public MapConfig(Map<String, String> props) {
public MapConfig(Map<String, Object> props) {
this.props.putAll(props);
this.props = Collections.unmodifiableMap(this.props);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
public class PollingDynamicConfig extends AbstractConfig {
private static final Logger LOG = LoggerFactory.getLogger(PollingDynamicConfig.class);

private volatile Map<String, String> current = new HashMap<String, String>();
private volatile Map<String, Object> current = new HashMap<String, Object>();
private final AtomicBoolean busy = new AtomicBoolean();
private final Callable<PollingResponse> reader;
private final AtomicLong updateCounter = new AtomicLong();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
import java.util.Map;

public abstract class PollingResponse {
public static PollingResponse forSnapshot(final Map<String, String> values) {
public static PollingResponse forSnapshot(final Map<String, Object> values) {
return new PollingResponse() {
@Override
public Map<String, String> getToAdd() {
public Map<String, Object> getToAdd() {
return values;
}

Expand All @@ -28,7 +28,7 @@ public boolean hasData() {
public static PollingResponse noop() {
return new PollingResponse() {
@Override
public Map<String, String> getToAdd() {
public Map<String, Object> getToAdd() {
return Collections.emptyMap();
}

Expand All @@ -44,7 +44,7 @@ public boolean hasData() {
};
}

public abstract Map<String, String> getToAdd();
public abstract Map<String, Object> getToAdd();
public abstract Collection<String> getToRemove();
public abstract boolean hasData();
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ private void internalLoad(Properties props, Set<String> seenUrls, ClassLoader lo
try {
// Load properties into the single Properties object overriding any property
// that may already exist
Map<String, String> p = new URLConfigReader(url).call().getToAdd();
Map<String, Object> p = new URLConfigReader(url).call().getToAdd();
LOG.debug("Loaded : {}", url.toExternalForm());
props.putAll(p);

// Recursively load any files referenced by an @next property in the file
// Only one @next property is expected and the value may be a list of files
String next = p.get(INCLUDE_KEY);
String next = (String) p.get(INCLUDE_KEY);
if (next != null) {
p.remove(INCLUDE_KEY);
for (String urlString : next.split(",")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private static URL[] createUrls(String... urlStrings) {

@Override
public PollingResponse call() throws IOException {
final Map<String, String> map = new HashMap<String, String>();
final Map<String, Object> map = new HashMap<String, Object>();
for (URL url: configUrls) {
Properties props = new Properties();
InputStream fin = url.openStream();
Expand All @@ -95,7 +95,7 @@ public PollingResponse call() throws IOException {
}
return new PollingResponse() {
@Override
public Map<String, String> getToAdd() {
public Map<String, Object> getToAdd() {
return map;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void testBasicRead() throws Exception {
server.getServerPathURI("/prop1").toURL()
);

Map<String, String> result;
Map<String, Object> result;

prop1.setProperty("a", "a_value");
result = reader.call().getToAdd();
Expand All @@ -72,7 +72,7 @@ public void testCombineSources() throws Exception {
prop1.setProperty("a", "A");
prop2.setProperty("b", "B");

Map<String, String> result = reader.call().getToAdd();
Map<String, Object> result = reader.call().getToAdd();

Assert.assertEquals(2, result.size());
Assert.assertEquals("A", result.get("a"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,7 @@
*/
package com.netflix.archaius.guice;

import java.util.Properties;

import javax.inject.Inject;

import org.junit.Assert;
import org.junit.Test;

import com.google.common.collect.Lists;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
Expand All @@ -45,6 +39,13 @@
import com.netflix.archaius.config.MapConfig;
import com.netflix.archaius.exceptions.MappingException;
import com.netflix.archaius.visitor.PrintStreamVisitor;
import org.junit.Assert;
import org.junit.Test;

import javax.inject.Inject;
import java.util.Date;
import java.util.List;
import java.util.Properties;

public class ArchaiusModuleTest {

Expand All @@ -63,6 +64,8 @@ public static class MyServiceConfig {
private Boolean bool_value;
private Double double_value;
private Property<Integer> fast_int;
private List<Integer> int_list;
private Date date;
private Named named;

public void setStr_value(String value) {
Expand Down Expand Up @@ -342,4 +345,27 @@ public TestProxyConfig getProxyConfig(ConfigProxyFactory factory) {
Assert.assertArrayEquals(new String[]{"foo", "bar"}, configProxy.getStringArray());
Assert.assertArrayEquals(new Integer[]{1,2}, configProxy.getIntArray());
}

@Test
public void testObjectInjection() throws MappingException {
Date date = new Date(100);
final Config config = MapConfig.builder()
.put("env", "prod")
.put("prefix-prod.int_list", Lists.newArrayList(1, 2, 3))
.put("prefix-prod.date", date)
.build();

Injector injector = Guice.createInjector(
new ArchaiusModule() {
@Override
protected void configureArchaius() {
bindApplicationConfigurationOverride().toInstance(config);
}
});

MyServiceConfig serviceConfig = injector.getInstance(MyServiceConfig.class);
Assert.assertEquals(Lists.newArrayList(1, 2, 3), serviceConfig.int_list);
Assert.assertEquals(date, serviceConfig.date);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public PollingResponse call() throws Exception {
}

// Resolve to a single property value
final Map<String, String> result = new HashMap<String, String>();
final Map<String, Object> result = new HashMap<String, Object>();
for (Entry<String, List<ScopedValue>> entry : props.entrySet()) {
result.put(entry.getKey(), valueResolver.resolve(entry.getKey(), entry.getValue()));
}
Expand Down
7 changes: 6 additions & 1 deletion archaius2-typesafe/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ apply plugin: 'java'

dependencies {
compile project(':archaius2-core')
compile 'com.typesafe:config:1.2.1'
compile 'com.typesafe:config:1.3.0'

testCompile project(':archaius2-guice')
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

eclipse {
classpath {
downloadSources = true
Expand Down
Loading