Skip to content

Commit

Permalink
Merge pull request #190 from restx/improve-config-loader
Browse files Browse the repository at this point in the history
improve config loader (#186 #158)
  • Loading branch information
xhanin committed Apr 1, 2015
2 parents c41aeda + 6722fe7 commit 52c625f
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 4 deletions.
@@ -1,8 +1,12 @@
package restx.config;

import com.google.common.base.Charsets;
import com.google.common.base.Optional;
import com.google.common.io.Files;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import restx.common.ConfigElement;
import restx.common.RestxConfig;
import restx.common.StdRestxConfig;
Expand All @@ -11,6 +15,8 @@
import restx.config.ElementsFromConfigFactoryMachine;
import restx.factory.*;

import java.io.File;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;

Expand All @@ -20,6 +26,9 @@
* Time: 10:05 PM
*/
public class ConfigMachineTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();

@BeforeClass
public static void deactivateElementsFromConfig() {
System.setProperty("restx.activation::java.lang.String::mandatory.dep.result1", "false");
Expand Down Expand Up @@ -133,6 +142,44 @@ public void should_load_from_loader() throws Exception {
"classpath:restx/common/config.properties", "Doc 1", "key1", "val1"));
}

@Test
public void should_loader_load_settings_from_file_setup_with_system_property() throws Exception {
String key = "restx.common.config.location";
try {
File file = folder.newFile("config.properties");
Files.append("key1=myval1", file, Charsets.UTF_8);
System.setProperty(key, file.getAbsolutePath());

Factory factory = Factory.builder()
.addFromServiceLoader()
.build();

RestxConfig config = factory.getComponent(RestxConfig.class);

assertThat(config.getString("key1")).isEqualTo(Optional.of("myval1"));
assertThat(config.getElement("key1").get())
.isEqualToComparingFieldByField(ConfigElement.of(
"file://" + file.getAbsolutePath(), "Doc 1", "key1", "myval1"));

} finally {
System.clearProperty(key);
}
}

@Test
public void should_loader_load_settings_from_file() throws Exception {
File file = folder.newFile("config.properties");
Files.append("key1=myval1", file, Charsets.UTF_8);

RestxConfig config = new ConfigLoader(Optional.<String>absent())
.fromFile(file.getAbsolutePath()).get();

assertThat(config.getString("key1")).isEqualTo(Optional.of("myval1"));
assertThat(config.getElement("key1").get())
.isEqualToComparingFieldByField(ConfigElement.of(
"file://" + file.getAbsolutePath(), "", "key1", "myval1"));
}

private SingletonFactoryMachine<ConfigSupplier> configSupplierMachine(
int priority, String name, final ConfigElement... config) {
return new SingletonFactoryMachine<>(priority,
Expand Down
110 changes: 106 additions & 4 deletions restx-factory/src/main/java/restx/config/ConfigLoader.java
Expand Up @@ -7,14 +7,19 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import restx.common.ConfigElement;
import restx.common.RestxConfig;
import restx.common.StdRestxConfig;

import static com.google.common.io.Files.asCharSource;

/**
* User: xavierhanin
* Date: 9/24/13
Expand All @@ -34,7 +39,11 @@ public ConfigLoader(Optional<String> env) {
*
* The name of the resource provided must not contain the extension, which must be .properties
*
* The loader will first try to load an env specific resource named [resource].[env].properties.
* The loader will first try to load config from a file which location is provided by a system
* property, the name of the property being the name returned by #locationKeyForResource.
*
* Then it will try to load an env specific resource named [resource].[env].properties.
*
* Then it will load a resource named [resource].properties.
*
* @param resource the path of the resource to load, without extension.
Expand All @@ -46,14 +55,107 @@ public ConfigSupplier fromResource(final String resource) {
@Override
public RestxConfig get() {
List<ConfigElement> elements = new ArrayList<>();
loadResourceInto(resource + "." + env + ".properties", elements);
loadResourceInto(resource + ".properties", elements);

loadAllFromResource(elements, resource);

return StdRestxConfig.of(elements);
}
};
}

/**
* Provides a ConfigSupplier loading config from a file.
*
* The loader will first try to load an env specific file named [path].[env].properties.
*
* Then it will try to load a file named [path].properties.
*
* Then it will try to load a file named [path] (without extension).
*
* @param path the path of the file to load config from.
*
* @return a ConfigSupplier ready to load corresponding file.
*/
public ConfigSupplier fromFile(final String path) {
return new ConfigSupplier() {
@Override
public RestxConfig get() {
List<ConfigElement> elements = new ArrayList<>();

loadAllFromFile(elements, path);

return StdRestxConfig.of(elements);
}
};
}

private void loadResourceInto(String name, List<ConfigElement> elements) {
/**
* Gives the name of the system property that can be used to provide a file location
* to load to override settings for a particular resource.
*
* By defaut the name is equal to the resource name where slashes `/` are replaced by dots `.`,
* with `.location` suffix.
*
* Eg.
* `myapp/settings` becomes `myapp.settings.location`
*
* @param resource the resource for which the system property name should be provided.
*
* @return the system property name.
*/
public String locationKeyForResource(String resource) {
return resource.replace('/', '.') + ".location";
}

protected void loadAllFromResource(List<ConfigElement> elements, String resource) {
String locationKey = locationKeyForResource(resource);
String location = System.getProperty(locationKey);
if (location != null) {
Path path = Paths.get(location).toAbsolutePath();
logger.info("loading {} settings from {}", resource, path);
loadFileInto(path, elements);
} else {
logger.debug("system property `{}` is not set, no file to load to override settings from {}",
locationKey, resource);
}

loadResourceInto(resource + "." + env + ".properties", elements);
loadResourceInto(resource + ".properties", elements);
}

protected void loadAllFromFile(List<ConfigElement> elements, String path) {
if (!path.endsWith(".properties")) {
loadFileInto(Paths.get(path + "." + env + ".properties"), elements);
loadFileInto(Paths.get(path + ".properties"), elements);
}

loadFileInto(Paths.get(path), elements);
}

protected void loadFileInto(Path path, List<ConfigElement> elements) {
File file = path.toFile().getAbsoluteFile();
if (!file.exists()) {
logger.debug("no settings loaded from {}: file not available", file);
return;
}

if (!file.isFile()) {
logger.warn("no settings loaded from {}: this is not a file", file);
return;
}

try {
Iterable<ConfigElement> loadedElements = StdRestxConfig.parse("file://" + file,
asCharSource(file, Charsets.UTF_8)).elements();
Iterables.addAll(elements, loadedElements);
logger.debug("loaded {} elements from {}", Iterables.size(loadedElements), file);
} catch (IOException e) {
logger.warn("can't load " + file + ": " + e.getMessage(), e);
}

}

protected void loadResourceInto(String name, List<ConfigElement> elements) {
URL r;
r = Thread.currentThread().getContextClassLoader().getResource(name);
if (r != null) {
Expand Down

0 comments on commit 52c625f

Please sign in to comment.