Skip to content
Open
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
12 changes: 3 additions & 9 deletions fig-core/src/main/java/twigkit/fig/Fig.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import twigkit.fig.annotation.InjectionConfigurator;
import twigkit.fig.loader.Loader;
import twigkit.fig.util.ConfigUtils;
import twigkit.fig.visitor.ConfigFinder;

import java.util.Arrays;
Expand Down Expand Up @@ -112,16 +113,9 @@ public Fig add(Config config, String... path) {
if (!configs.containsKey(path[0])) {
add(new Config(path[0], config.loader));
}

Config parent = configs.get(path[0]);
for (int i = 1; i < path.length - 1; i++) {
Config c = parent.extension(path[i]);
if (c == null && i < path.length) {
c = new Config(path[i]);
parent.extend_with(c);
}
parent = c;
}
parent.extend_with(config);
ConfigUtils.addToParent(config, parent, path);
}

return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.slf4j.LoggerFactory;
import twigkit.fig.Config;
import twigkit.fig.Fig;
import twigkit.fig.util.ConfigUtils;
import twigkit.fig.util.FigUtils;
import twigkit.fig.util.FileUtils;

Expand All @@ -23,15 +24,19 @@ public class MergedPropertiesLoader implements Loader {

private String pathToPrimaryFig;
private String pathToSecondaryFig;
private String configsToMerge;

public MergedPropertiesLoader(String pathToPrimaryFig, String pathToSecondaryFig) {
this.pathToPrimaryFig = pathToPrimaryFig;
this.pathToSecondaryFig = pathToSecondaryFig;
}

/**
* This method loads the given primary {@link Fig} and a second {@link Fig} then merges the second {@link Fig}
* with the primary {@link Fig}.
* This method first loads the given primary {@link Fig} and a second {@link Fig} then merges the
* second {@link Fig} with the primary {@link Fig}.
*
* Any additional configurations set on the {@link Loader} that are not part of the secondary {@link Fig}
* will also be merged with the primary {@link Fig} once the secondary {@link Fig} has been merged.
*
* @param fig The primary {@link Fig}
*/
Expand Down Expand Up @@ -66,6 +71,10 @@ public void load(Fig fig) {
logger.error("Both the path to the primary fig: \"{}\" and the path to the secondary fig: \"{}\" are invalid. Unable to load configurations.", pathToPrimaryFig, pathToSecondaryFig);
}
}

if (configsToMerge != null) {
FigUtils.mergeConfigs(fig, ConfigUtils.asList(configsToMerge, this));
}
}

public void write(Config config) throws IOException {
Expand All @@ -75,4 +84,21 @@ public void write(Config config) throws IOException {
public void delete(Config config) throws IOException {
throw new IOException("Delete operation not supported.");
}

/**
* Set a config or sequence of configs that should be merged with the primary {@link Fig} after merging the
* secondary {@link Fig}. A config should be given in the following form:
*
* parent.child[property:value
*
* If more than one config is to be merged, subsequent configs should be separated with an ampersand, for
* example:
*
* parent.child[property:value&parent[property:value
*
* @param configsToMerge The config or sequence of configs to be merged with the primary {@link Fig}.
*/
public void setConfigsToMerge(String configsToMerge) {
this.configsToMerge = configsToMerge;
}
}
101 changes: 101 additions & 0 deletions fig-core/src/main/java/twigkit/fig/util/ConfigUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package twigkit.fig.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import twigkit.fig.Config;
import twigkit.fig.Value;
import twigkit.fig.loader.Loader;

import java.util.ArrayList;
import java.util.List;

/**
* Utility class to perform operations on a {@link Config} or set of {@link Config}s.
*
* @author scottbrown
*/
public class ConfigUtils {

private static final Logger logger = LoggerFactory.getLogger(ConfigUtils.class);

/**
* Convert the given config or sequence of configs into a {@link List} of {@link Config}s.
*
* A config should be given in the following form:
*
* parent.child[property:value
*
* If more than one config is to be merged, subsequent configs should be separated with an ampersand, for
* example:
*
* parent.child[property:value&parent[property:value
*
* @param configurations The config or sequence of configs to be converted into a {@link List} of {@link Config}s.
* @param loader The {@link Loader} that backs each instance of the {@link Config}.
* @return A {@link List} of {@link Config}s.
*/
public static List<Config> asList(String configurations, Loader loader) {
List<Config> configs = null;

if (configurations != null) {
configs = new ArrayList<Config>();

for (String c : configurations.split("&")) {

String[] configDetails = c.split(":");

String property = configDetails[0].substring(configDetails[0].indexOf("[") + 1, configDetails[0].length());
String[] path = configDetails[0].substring(0, configDetails[0].indexOf("[")).split("\\.");

Config config = null;
if (path.length == 1) {
config = new Config(path[0], loader);
} else if (path.length > 1) {
config = new Config(path[path.length - 1], loader);
} else {
logger.warn("No configuration given for property {}. This property will be ignored", property);
}

if (config != null) {
config.set(new Value<Object>(property, configDetails[1], false));

if (path.length == 1) {
configs.add(config);
} else {
Config parent = new Config(path[0], loader);
addToParent(config, parent, path);
configs.add(config.parents().get(0));
}
}
}
}

return configs;
}

/**
* Add the given {@link Config} to the given parent {@link Config}.
*
* @param config The {@link Config} to be added as a child of the given parent {@link Config}.
* @param parent The {@link Config} that will be a parent of the given {@link Config}
* @param path The configuration path pointing from the parent down to the child.
*/
public static void addToParent(Config config, Config parent, String... path) {
if (parent != null) {
for (int i = 1; i < path.length - 1; i++) {
Config child = parent.extension(path[i]);

if (child == null && i < path.length) {
child = new Config(path[i]);
parent.extend_with(child);
}

parent = child;
}

if (config != null) {
parent.extend_with(config);
}
}
}
}
11 changes: 11 additions & 0 deletions fig-core/src/main/java/twigkit/fig/util/FigUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ public static void merge(Fig primary, Fig secondary) {
}
}

/**
* Merge a collection of {@link Config}s into a primary {@link Fig}.
* @param primary The {@link Fig} to be updated.
* @param configs The {@link Config}s to be merged.
*/
public static void mergeConfigs(Fig primary, Collection<Config> configs) {
if (primary != null && configs != null) {
merge(primary, primary.configs(), configs);
}
}

/**
* Merge a collection of secondary {@link Config}s into a collection of primary {@link Config}s.
* @param fig The {@link Fig} to be updated.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
import org.junit.rules.ExpectedException;
import twigkit.fig.Config;
import twigkit.fig.Fig;
import twigkit.fig.util.ConfigUtils;
import twigkit.fig.util.FigUtils;
import twigkit.fig.visitor.ConfigTreeWriter;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
Expand Down Expand Up @@ -136,6 +139,22 @@ public void testExtensionsWithTheSameNameUnderDifferentParentConfigsAreHandledCo
new ConfigTreeWriter(fig.get("people"));
}

@Test
public void testMergedPropertiesLoaderMergesConfigList() {
MergedPropertiesLoader loader = new MergedPropertiesLoader("confs", "confs_dev");

String configsToMerge = "people.detail[enabled:true&sub.group.folder-extension[group-folder-extension-key:test";
loader.setConfigsToMerge(configsToMerge);

Fig fig = Fig.getInstance(loader);

assertEquals(2, fig.get("people", "detail").values().size());
assertEquals("true", fig.get("people", "detail").value("enabled").as_string());

assertEquals(2, fig.get("sub", "group", "folder-extension").values().size());
assertEquals("test", fig.get("sub", "group", "folder-extension").value("group-folder-extension-key").as_string());
}

@Test
public void testFallbackFigIsReturnedWhenTheOtherIsEmpty() {
Fig fig1 = Fig.getInstance(new PropertiesLoader("confs"));
Expand Down
37 changes: 37 additions & 0 deletions fig-core/src/test/java/twigkit.fig/util/ConfigUtilsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package twigkit.fig.util;

import org.junit.Test;
import twigkit.fig.Config;
import twigkit.fig.loader.PropertiesLoader;

import java.util.List;

import static org.junit.Assert.assertEquals;

/**
* @author scottbrown
*/
public class ConfigUtilsTest {

@Test
public void testConvertingSingleConfigStringToConfigList() {
String configsToMerge = "companies[host:test";
List<Config> configs = ConfigUtils.asList(configsToMerge, new PropertiesLoader("conf"));

assertEquals(1, configs.size());
assertEquals("companies", configs.get(0).name());
assertEquals("test", configs.get(0).value("host").as_string());
}

@Test
public void testConvertingMultipleConfigStringToConfigList() {
String configsToMerge = "people.detail[enabled:true&sub.group.folder-extension[group-folder-extension-key:test";
List<Config> configs = ConfigUtils.asList(configsToMerge, new PropertiesLoader("conf"));

assertEquals(2, configs.size());
assertEquals("people", configs.get(0).name());
assertEquals("true", configs.get(0).extension("detail").value("enabled").as_string());
assertEquals("sub", configs.get(1).name());
assertEquals("test", configs.get(1).extension("group").extension("folder-extension").value("group-folder-extension-key").as_string());
}
}
20 changes: 20 additions & 0 deletions fig-core/src/test/java/twigkit.fig/util/FigUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import org.junit.Test;
import twigkit.fig.Config;
import twigkit.fig.Fig;
import twigkit.fig.loader.MergedPropertiesLoader;
import twigkit.fig.loader.PropertiesLoader;

import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

Expand Down Expand Up @@ -111,4 +114,21 @@ public void testFigRemainsUnchangedWhenMergingNullFig() {
FigUtils.merge(fig, null);
assertEquals(5, fig.configs().size());
}

@Test
public void testMergingCollectionOfConfigsIntoFig() {
PropertiesLoader loader = new PropertiesLoader("confs");
Fig fig = Fig.getInstance(loader);

String configsToMerge = "people.detail[enabled:true&sub.group.folder-extension[group-folder-extension-key:test";
List<Config> configs = ConfigUtils.asList(configsToMerge, loader);

FigUtils.mergeConfigs(fig, configs);

assertEquals(2, fig.get("people", "detail").values().size());
assertEquals("true", fig.get("people", "detail").value("enabled").as_string());

assertEquals(2, fig.get("sub", "group", "folder-extension").values().size());
assertEquals("test", fig.get("sub", "group", "folder-extension").value("group-folder-extension-key").as_string());
}
}