-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #80 from cfg4j/adapter-classpath
Classpath source
- Loading branch information
Showing
12 changed files
with
466 additions
and
18 deletions.
There are no files selected for viewing
127 changes: 127 additions & 0 deletions
127
src/main/java/org/cfg4j/source/classpath/ClasspathConfigurationSource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/* | ||
* Copyright 2015 Norbert Potocki (norbert.potocki@nort.pl) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.cfg4j.source.classpath; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
import org.cfg4j.source.ConfigurationSource; | ||
import org.cfg4j.source.context.DefaultEnvironment; | ||
import org.cfg4j.source.context.Environment; | ||
import org.cfg4j.source.context.MissingEnvironmentException; | ||
import org.cfg4j.source.git.ConfigFilesProvider; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.net.URL; | ||
import java.util.List; | ||
import java.util.Properties; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.StreamSupport; | ||
|
||
/** | ||
* {@link ConfigurationSource} reading configuration from classpath files. | ||
*/ | ||
public class ClasspathConfigurationSource implements ConfigurationSource { | ||
|
||
private final ConfigFilesProvider configFilesProvider; | ||
|
||
/** | ||
* Construct {@link ConfigurationSource} backed by classpath files. File list should by provided by | ||
* {@link ConfigFilesProvider} and will be treated as relative paths to the environment provided in | ||
* {@link #getConfiguration()} and {@link #getConfiguration(Environment)} calls (see corresponding javadocs | ||
* for detail). | ||
* | ||
* @param configFilesProvider {@link ConfigFilesProvider} supplying a list of configuration files to use | ||
*/ | ||
public ClasspathConfigurationSource(ConfigFilesProvider configFilesProvider) { | ||
this.configFilesProvider = requireNonNull(configFilesProvider); | ||
} | ||
|
||
/** | ||
* <b>DEPRECATED: Use {@link #getConfiguration(Environment)} with {@link DefaultEnvironment} instead.</b> | ||
* <p> | ||
* Get configuration set from this source in a form of {@link Properties}. Uses default environment which means | ||
* treating paths from {@link ConfigFilesProvider} as absolute paths. | ||
* | ||
* @return configuration set for default environment | ||
* @throws IllegalStateException when unable to fetch configuration | ||
*/ | ||
@Override | ||
public Properties getConfiguration() { | ||
return getConfiguration(new DefaultEnvironment()); | ||
} | ||
|
||
/** | ||
* Get configuration set for a given {@code environment} from this source in a form of {@link Properties}. | ||
* Path provided by {@code environment} is prepended to all file paths from {@link ConfigFilesProvider} used | ||
* at construction time. | ||
* | ||
* @param environment environment to use | ||
* @return configuration set for {@code environment} | ||
* @throws MissingEnvironmentException when requested environment couldn't be found | ||
* @throws IllegalStateException when unable to fetch configuration | ||
*/ | ||
@Override | ||
public Properties getConfiguration(Environment environment) { | ||
Properties properties = new Properties(); | ||
|
||
String pathPrefix = getPrefixFor(environment); | ||
|
||
URL url = ClassLoader.getSystemResource(pathPrefix); | ||
if (url == null) { | ||
throw new MissingEnvironmentException("Directory doesn't exist: " + environment.getName()); | ||
} | ||
|
||
List<File> files = StreamSupport.stream(configFilesProvider.getConfigFiles().spliterator(), false) | ||
.map(file -> new File(pathPrefix + file.getPath())) | ||
.collect(Collectors.toList()); | ||
|
||
for (File file : files) { | ||
try (InputStream input = ClassLoader.getSystemResourceAsStream(file.getPath())) { | ||
|
||
if (input == null) { | ||
throw new IllegalStateException("Unable to load properties from classpath: " + file.getPath()); | ||
} | ||
|
||
properties.load(input); | ||
} catch (IOException | IllegalArgumentException e) { | ||
throw new IllegalStateException("Unable to load properties from classpath: " + file.getPath(), e); | ||
} | ||
} | ||
|
||
return properties; | ||
} | ||
|
||
@Override | ||
public void refresh() { | ||
// NOP | ||
} | ||
|
||
private String getPrefixFor(Environment environment) { | ||
String path = environment.getName(); | ||
|
||
if (!path.trim().isEmpty() && !path.endsWith("/")) { | ||
path += "/"; | ||
} | ||
|
||
if (path.startsWith("/")) { | ||
path = path.substring(1); | ||
} | ||
|
||
return path; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
169 changes: 169 additions & 0 deletions
169
src/test/java/org/cfg4j/source/classpath/ClasspathConfigurationSourceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
/* | ||
* Copyright 2015 Norbert Potocki (norbert.potocki@nort.pl) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.cfg4j.source.classpath; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import org.assertj.core.data.MapEntry; | ||
import org.cfg4j.source.context.DefaultEnvironment; | ||
import org.cfg4j.source.context.Environment; | ||
import org.cfg4j.source.context.ImmutableEnvironment; | ||
import org.cfg4j.source.context.MissingEnvironmentException; | ||
import org.cfg4j.source.git.ConfigFilesProvider; | ||
import org.junit.Before; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.rules.ExpectedException; | ||
import org.junit.runner.RunWith; | ||
import org.mockito.runners.MockitoJUnitRunner; | ||
|
||
import java.io.File; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
|
||
|
||
@RunWith(MockitoJUnitRunner.class) | ||
public class ClasspathConfigurationSourceTest { | ||
|
||
@Rule | ||
public ExpectedException expectedException = ExpectedException.none(); | ||
|
||
private TempConfigurationClasspathRepo classpathRepo; | ||
private ConfigFilesProvider configFilesProvider; | ||
private ClasspathConfigurationSource source; | ||
|
||
@Before | ||
public void setUp() throws Exception { | ||
classpathRepo = new TempConfigurationClasspathRepo(); | ||
|
||
configFilesProvider = () -> Collections.singletonList( | ||
new File("application.properties") | ||
); | ||
|
||
source = new ClasspathConfigurationSource(configFilesProvider); | ||
} | ||
|
||
@Test | ||
public void getConfigurationShouldReadConfigFromAbsolutePaths() throws Exception { | ||
assertThat(source.getConfiguration()).containsOnlyKeys("some.setting"); | ||
} | ||
|
||
@Test | ||
public void getConfigurationShouldThrowOnMissingConfigFile() throws Exception { | ||
configFilesProvider = () -> Collections.singletonList( | ||
new File("nonexistent.properties") | ||
); | ||
|
||
source = new ClasspathConfigurationSource(configFilesProvider); | ||
|
||
expectedException.expect(IllegalStateException.class); | ||
source.getConfiguration(); | ||
} | ||
|
||
@Test | ||
public void getConfigurationShouldThrowOnMalformedConfigFile() throws Exception { | ||
configFilesProvider = () -> Collections.singletonList( | ||
new File("malformed.properties") | ||
); | ||
|
||
source = new ClasspathConfigurationSource(configFilesProvider); | ||
|
||
expectedException.expect(IllegalStateException.class); | ||
source.getConfiguration(); | ||
} | ||
|
||
@Test | ||
public void getConfigurationShouldReadFromGivenFiles() throws Exception { | ||
configFilesProvider = () -> Arrays.asList( | ||
new File("application.properties"), | ||
new File("otherConfig.properties") | ||
); | ||
|
||
source = new ClasspathConfigurationSource(configFilesProvider); | ||
|
||
assertThat(source.getConfiguration()).containsOnlyKeys("some.setting", "otherConfig.setting"); | ||
} | ||
|
||
@Test | ||
public void getConfiguration2ShouldReadFromGivenPath() throws Exception { | ||
configFilesProvider = () -> Collections.singletonList( | ||
new File("application.properties") | ||
); | ||
|
||
source = new ClasspathConfigurationSource(configFilesProvider); | ||
|
||
Environment environment = new ImmutableEnvironment("/otherApplicationConfigs/"); | ||
|
||
assertThat(source.getConfiguration(environment)).containsOnly(MapEntry.entry("some.setting", "otherAppSetting")); | ||
} | ||
|
||
@Test | ||
public void getConfiguration2ShouldReadFromGivenFiles() throws Exception { | ||
configFilesProvider = () -> Arrays.asList( | ||
new File("application.properties"), | ||
new File("otherConfig.properties") | ||
); | ||
|
||
source = new ClasspathConfigurationSource(configFilesProvider); | ||
assertThat(source.getConfiguration(new DefaultEnvironment())).containsOnlyKeys("some.setting", "otherConfig.setting"); | ||
} | ||
|
||
@Test | ||
public void getConfiguration2ShouldThrowOnMissingEnvironment() throws Exception { | ||
expectedException.expect(MissingEnvironmentException.class); | ||
source.getConfiguration(new ImmutableEnvironment("awlerijawoetinawwerlkjn")); | ||
} | ||
|
||
@Test | ||
public void getConfiguration2ShouldThrowOnMissingConfigFile() throws Exception { | ||
configFilesProvider = () -> Collections.singletonList( | ||
new File("nonexistent.properties") | ||
); | ||
|
||
source = new ClasspathConfigurationSource(configFilesProvider); | ||
|
||
expectedException.expect(IllegalStateException.class); | ||
source.getConfiguration(new DefaultEnvironment()); | ||
} | ||
|
||
@Test | ||
public void getConfiguration2ShouldThrowOnMalformedConfigFile() throws Exception { | ||
configFilesProvider = () -> Collections.singletonList( | ||
new File("malformed.properties") | ||
); | ||
|
||
source = new ClasspathConfigurationSource(configFilesProvider); | ||
|
||
expectedException.expect(IllegalStateException.class); | ||
source.getConfiguration(new DefaultEnvironment()); | ||
} | ||
|
||
@Test | ||
public void refreshShouldUpdateGetConfigurationResults() throws Exception { | ||
classpathRepo.changeProperty("application.properties", "some.setting", "changedValue"); | ||
source.refresh(); | ||
|
||
assertThat(source.getConfiguration()).containsOnly(MapEntry.entry("some.setting", "changedValue")); | ||
} | ||
|
||
@Test | ||
public void refreshShouldUpdateGetConfiguration2OnDefaultBranch() throws Exception { | ||
classpathRepo.changeProperty("application.properties", "some.setting", "changedValue"); | ||
source.refresh(); | ||
|
||
assertThat(source.getConfiguration(new DefaultEnvironment())).containsOnly(MapEntry.entry("some.setting", "changedValue")); | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
src/test/java/org/cfg4j/source/classpath/TempConfigurationClasspathRepo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* Copyright 2015 Norbert Potocki (norbert.potocki@nort.pl) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.cfg4j.source.classpath; | ||
|
||
import java.io.FileOutputStream; | ||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.net.URL; | ||
import java.util.Properties; | ||
|
||
/** | ||
* Classpath files repository. | ||
*/ | ||
public class TempConfigurationClasspathRepo { | ||
|
||
/** | ||
* Create repository allowing access to classpath files. | ||
*/ | ||
public TempConfigurationClasspathRepo() { | ||
} | ||
|
||
/** | ||
* Change the {@code key} property to {@code value} and store it in a {@code propFilePath} properties file. | ||
* | ||
* @param propFilePath relative path to the properties file in this repository | ||
* @param key property key | ||
* @param value property value | ||
* @throws IOException when unable to modify properties file | ||
*/ | ||
public void changeProperty(String propFilePath, String key, String value) throws IOException { | ||
writePropertyToFile(propFilePath, key, value); | ||
} | ||
|
||
private void writePropertyToFile(String propFilePath, String key, String value) throws IOException { | ||
URL systemResource = ClassLoader.getSystemResource(propFilePath); | ||
OutputStream out = new FileOutputStream(systemResource.getPath()); | ||
out.write((key + "=" + value).getBytes()); | ||
out.close(); | ||
} | ||
} |
Oops, something went wrong.