Skip to content

Commit 52c625f

Browse files
committed
Merge pull request #190 from restx/improve-config-loader
improve config loader (#186 #158)
2 parents c41aeda + 6722fe7 commit 52c625f

File tree

2 files changed

+153
-4
lines changed

2 files changed

+153
-4
lines changed

restx-factory-testing/src/test/java/restx/config/ConfigMachineTest.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package restx.config;
22

3+
import com.google.common.base.Charsets;
34
import com.google.common.base.Optional;
5+
import com.google.common.io.Files;
46
import org.junit.BeforeClass;
7+
import org.junit.Rule;
58
import org.junit.Test;
9+
import org.junit.rules.TemporaryFolder;
610
import restx.common.ConfigElement;
711
import restx.common.RestxConfig;
812
import restx.common.StdRestxConfig;
@@ -11,6 +15,8 @@
1115
import restx.config.ElementsFromConfigFactoryMachine;
1216
import restx.factory.*;
1317

18+
import java.io.File;
19+
1420
import static java.util.Arrays.asList;
1521
import static org.assertj.core.api.Assertions.assertThat;
1622

@@ -20,6 +26,9 @@
2026
* Time: 10:05 PM
2127
*/
2228
public class ConfigMachineTest {
29+
@Rule
30+
public TemporaryFolder folder = new TemporaryFolder();
31+
2332
@BeforeClass
2433
public static void deactivateElementsFromConfig() {
2534
System.setProperty("restx.activation::java.lang.String::mandatory.dep.result1", "false");
@@ -133,6 +142,44 @@ public void should_load_from_loader() throws Exception {
133142
"classpath:restx/common/config.properties", "Doc 1", "key1", "val1"));
134143
}
135144

145+
@Test
146+
public void should_loader_load_settings_from_file_setup_with_system_property() throws Exception {
147+
String key = "restx.common.config.location";
148+
try {
149+
File file = folder.newFile("config.properties");
150+
Files.append("key1=myval1", file, Charsets.UTF_8);
151+
System.setProperty(key, file.getAbsolutePath());
152+
153+
Factory factory = Factory.builder()
154+
.addFromServiceLoader()
155+
.build();
156+
157+
RestxConfig config = factory.getComponent(RestxConfig.class);
158+
159+
assertThat(config.getString("key1")).isEqualTo(Optional.of("myval1"));
160+
assertThat(config.getElement("key1").get())
161+
.isEqualToComparingFieldByField(ConfigElement.of(
162+
"file://" + file.getAbsolutePath(), "Doc 1", "key1", "myval1"));
163+
164+
} finally {
165+
System.clearProperty(key);
166+
}
167+
}
168+
169+
@Test
170+
public void should_loader_load_settings_from_file() throws Exception {
171+
File file = folder.newFile("config.properties");
172+
Files.append("key1=myval1", file, Charsets.UTF_8);
173+
174+
RestxConfig config = new ConfigLoader(Optional.<String>absent())
175+
.fromFile(file.getAbsolutePath()).get();
176+
177+
assertThat(config.getString("key1")).isEqualTo(Optional.of("myval1"));
178+
assertThat(config.getElement("key1").get())
179+
.isEqualToComparingFieldByField(ConfigElement.of(
180+
"file://" + file.getAbsolutePath(), "", "key1", "myval1"));
181+
}
182+
136183
private SingletonFactoryMachine<ConfigSupplier> configSupplierMachine(
137184
int priority, String name, final ConfigElement... config) {
138185
return new SingletonFactoryMachine<>(priority,

restx-factory/src/main/java/restx/config/ConfigLoader.java

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@
77
import org.slf4j.Logger;
88
import org.slf4j.LoggerFactory;
99

10+
import java.io.File;
1011
import java.io.IOException;
1112
import java.net.URL;
13+
import java.nio.file.Path;
14+
import java.nio.file.Paths;
1215
import java.util.ArrayList;
1316
import java.util.List;
1417
import restx.common.ConfigElement;
1518
import restx.common.RestxConfig;
1619
import restx.common.StdRestxConfig;
1720

21+
import static com.google.common.io.Files.asCharSource;
22+
1823
/**
1924
* User: xavierhanin
2025
* Date: 9/24/13
@@ -34,7 +39,11 @@ public ConfigLoader(Optional<String> env) {
3439
*
3540
* The name of the resource provided must not contain the extension, which must be .properties
3641
*
37-
* The loader will first try to load an env specific resource named [resource].[env].properties.
42+
* The loader will first try to load config from a file which location is provided by a system
43+
* property, the name of the property being the name returned by #locationKeyForResource.
44+
*
45+
* Then it will try to load an env specific resource named [resource].[env].properties.
46+
*
3847
* Then it will load a resource named [resource].properties.
3948
*
4049
* @param resource the path of the resource to load, without extension.
@@ -46,14 +55,107 @@ public ConfigSupplier fromResource(final String resource) {
4655
@Override
4756
public RestxConfig get() {
4857
List<ConfigElement> elements = new ArrayList<>();
49-
loadResourceInto(resource + "." + env + ".properties", elements);
50-
loadResourceInto(resource + ".properties", elements);
58+
59+
loadAllFromResource(elements, resource);
60+
61+
return StdRestxConfig.of(elements);
62+
}
63+
};
64+
}
65+
66+
/**
67+
* Provides a ConfigSupplier loading config from a file.
68+
*
69+
* The loader will first try to load an env specific file named [path].[env].properties.
70+
*
71+
* Then it will try to load a file named [path].properties.
72+
*
73+
* Then it will try to load a file named [path] (without extension).
74+
*
75+
* @param path the path of the file to load config from.
76+
*
77+
* @return a ConfigSupplier ready to load corresponding file.
78+
*/
79+
public ConfigSupplier fromFile(final String path) {
80+
return new ConfigSupplier() {
81+
@Override
82+
public RestxConfig get() {
83+
List<ConfigElement> elements = new ArrayList<>();
84+
85+
loadAllFromFile(elements, path);
86+
5187
return StdRestxConfig.of(elements);
5288
}
5389
};
5490
}
5591

56-
private void loadResourceInto(String name, List<ConfigElement> elements) {
92+
/**
93+
* Gives the name of the system property that can be used to provide a file location
94+
* to load to override settings for a particular resource.
95+
*
96+
* By defaut the name is equal to the resource name where slashes `/` are replaced by dots `.`,
97+
* with `.location` suffix.
98+
*
99+
* Eg.
100+
* `myapp/settings` becomes `myapp.settings.location`
101+
*
102+
* @param resource the resource for which the system property name should be provided.
103+
*
104+
* @return the system property name.
105+
*/
106+
public String locationKeyForResource(String resource) {
107+
return resource.replace('/', '.') + ".location";
108+
}
109+
110+
protected void loadAllFromResource(List<ConfigElement> elements, String resource) {
111+
String locationKey = locationKeyForResource(resource);
112+
String location = System.getProperty(locationKey);
113+
if (location != null) {
114+
Path path = Paths.get(location).toAbsolutePath();
115+
logger.info("loading {} settings from {}", resource, path);
116+
loadFileInto(path, elements);
117+
} else {
118+
logger.debug("system property `{}` is not set, no file to load to override settings from {}",
119+
locationKey, resource);
120+
}
121+
122+
loadResourceInto(resource + "." + env + ".properties", elements);
123+
loadResourceInto(resource + ".properties", elements);
124+
}
125+
126+
protected void loadAllFromFile(List<ConfigElement> elements, String path) {
127+
if (!path.endsWith(".properties")) {
128+
loadFileInto(Paths.get(path + "." + env + ".properties"), elements);
129+
loadFileInto(Paths.get(path + ".properties"), elements);
130+
}
131+
132+
loadFileInto(Paths.get(path), elements);
133+
}
134+
135+
protected void loadFileInto(Path path, List<ConfigElement> elements) {
136+
File file = path.toFile().getAbsoluteFile();
137+
if (!file.exists()) {
138+
logger.debug("no settings loaded from {}: file not available", file);
139+
return;
140+
}
141+
142+
if (!file.isFile()) {
143+
logger.warn("no settings loaded from {}: this is not a file", file);
144+
return;
145+
}
146+
147+
try {
148+
Iterable<ConfigElement> loadedElements = StdRestxConfig.parse("file://" + file,
149+
asCharSource(file, Charsets.UTF_8)).elements();
150+
Iterables.addAll(elements, loadedElements);
151+
logger.debug("loaded {} elements from {}", Iterables.size(loadedElements), file);
152+
} catch (IOException e) {
153+
logger.warn("can't load " + file + ": " + e.getMessage(), e);
154+
}
155+
156+
}
157+
158+
protected void loadResourceInto(String name, List<ConfigElement> elements) {
57159
URL r;
58160
r = Thread.currentThread().getContextClassLoader().getResource(name);
59161
if (r != null) {

0 commit comments

Comments
 (0)