mirror of
https://github.com/lightbend/config.git
synced 2025-01-15 23:01:05 +08:00
Merge pull request #407 from FeiWongReed/master
issue #405 fixed: config loading strategy implemented
This commit is contained in:
commit
3639c645cf
@ -3,17 +3,16 @@
|
|||||||
*/
|
*/
|
||||||
package com.typesafe.config;
|
package com.typesafe.config;
|
||||||
|
|
||||||
|
import com.typesafe.config.impl.ConfigImpl;
|
||||||
|
import com.typesafe.config.impl.Parseable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import com.typesafe.config.impl.ConfigImpl;
|
|
||||||
import com.typesafe.config.impl.Parseable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains static methods for creating {@link Config} instances.
|
* Contains static methods for creating {@link Config} instances.
|
||||||
*
|
*
|
||||||
@ -36,6 +35,8 @@ import com.typesafe.config.impl.Parseable;
|
|||||||
* examples.
|
* examples.
|
||||||
*/
|
*/
|
||||||
public final class ConfigFactory {
|
public final class ConfigFactory {
|
||||||
|
private static final String STRATEGY_PROPERTY_NAME = "config.strategy";
|
||||||
|
|
||||||
private ConfigFactory() {
|
private ConfigFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,54 +214,7 @@ public final class ConfigFactory {
|
|||||||
.resolve(resolveOptions);
|
.resolve(resolveOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Config parseApplicationConfig(ConfigParseOptions parseOptions) {
|
|
||||||
ClassLoader loader = parseOptions.getClassLoader();
|
|
||||||
if (loader == null)
|
|
||||||
throw new ConfigException.BugOrBroken(
|
|
||||||
"ClassLoader should have been set here; bug in ConfigFactory. "
|
|
||||||
+ "(You can probably work around this bug by passing in a class loader or calling currentThread().setContextClassLoader() though.)");
|
|
||||||
|
|
||||||
int specified = 0;
|
|
||||||
|
|
||||||
// override application.conf with config.file, config.resource,
|
|
||||||
// config.url if requested.
|
|
||||||
String resource = System.getProperty("config.resource");
|
|
||||||
if (resource != null)
|
|
||||||
specified += 1;
|
|
||||||
String file = System.getProperty("config.file");
|
|
||||||
if (file != null)
|
|
||||||
specified += 1;
|
|
||||||
String url = System.getProperty("config.url");
|
|
||||||
if (url != null)
|
|
||||||
specified += 1;
|
|
||||||
|
|
||||||
if (specified == 0) {
|
|
||||||
return ConfigFactory.parseResourcesAnySyntax("application", parseOptions);
|
|
||||||
} else if (specified > 1) {
|
|
||||||
throw new ConfigException.Generic("You set more than one of config.file='" + file
|
|
||||||
+ "', config.url='" + url + "', config.resource='" + resource
|
|
||||||
+ "'; don't know which one to use!");
|
|
||||||
} else {
|
|
||||||
// the override file/url/resource MUST be present or it's an error
|
|
||||||
ConfigParseOptions overrideOptions = parseOptions.setAllowMissing(false);
|
|
||||||
if (resource != null) {
|
|
||||||
if (resource.startsWith("/"))
|
|
||||||
resource = resource.substring(1);
|
|
||||||
// this deliberately does not parseResourcesAnySyntax; if
|
|
||||||
// people want that they can use an include statement.
|
|
||||||
return parseResources(loader, resource, overrideOptions);
|
|
||||||
} else if (file != null) {
|
|
||||||
return parseFile(new File(file), overrideOptions);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return parseURL(new URL(url), overrideOptions);
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
throw new ConfigException.Generic("Bad URL in config.url system property: '"
|
|
||||||
+ url + "': " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a default configuration, equivalent to {@link #load(Config)
|
* Loads a default configuration, equivalent to {@link #load(Config)
|
||||||
@ -516,7 +470,7 @@ public final class ConfigFactory {
|
|||||||
* @return the default application configuration
|
* @return the default application configuration
|
||||||
*/
|
*/
|
||||||
public static Config defaultApplication(ConfigParseOptions options) {
|
public static Config defaultApplication(ConfigParseOptions options) {
|
||||||
return parseApplicationConfig(ensureClassLoader(options, "defaultApplication"));
|
return getConfigLoadingStrategy().parseApplicationConfig(ensureClassLoader(options, "defaultApplication"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1094,4 +1048,18 @@ public final class ConfigFactory {
|
|||||||
public static Config parseMap(Map<String, ? extends Object> values) {
|
public static Config parseMap(Map<String, ? extends Object> values) {
|
||||||
return parseMap(values, null);
|
return parseMap(values, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ConfigLoadingStrategy getConfigLoadingStrategy() {
|
||||||
|
String className = System.getProperties().getProperty(STRATEGY_PROPERTY_NAME);
|
||||||
|
|
||||||
|
if (className != null) {
|
||||||
|
try {
|
||||||
|
return ConfigLoadingStrategy.class.cast(Class.forName(className).newInstance());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new ConfigException.BugOrBroken("Failed to load strategy: " + className, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new DefaultConfigLoadingStrategy();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.typesafe.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method allows you to alter default config loading strategy for all the code which
|
||||||
|
* calls {@link ConfigFactory#load}.
|
||||||
|
*
|
||||||
|
* Usually you don't have to implement this interface but it may be required
|
||||||
|
* when you fixing a improperly implemented library with unavailable source code.
|
||||||
|
*
|
||||||
|
* You have to define VM property {@code config.strategy} to replace default strategy with your own.
|
||||||
|
*/
|
||||||
|
public interface ConfigLoadingStrategy {
|
||||||
|
/**
|
||||||
|
* This method must load and parse application config.
|
||||||
|
*
|
||||||
|
* @param parseOptions {@link ConfigParseOptions} to use
|
||||||
|
* @return loaded config
|
||||||
|
*/
|
||||||
|
Config parseApplicationConfig(ConfigParseOptions parseOptions);
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package com.typesafe.config;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default config loading strategy. Able to load resource, file or URL.
|
||||||
|
* Behavior may be altered by defining one of VM properties
|
||||||
|
* {@code config.resource}, {@code config.file} or {@code config.url}
|
||||||
|
*/
|
||||||
|
public class DefaultConfigLoadingStrategy implements ConfigLoadingStrategy {
|
||||||
|
@Override
|
||||||
|
public Config parseApplicationConfig(ConfigParseOptions parseOptions) {
|
||||||
|
ClassLoader loader = parseOptions.getClassLoader();
|
||||||
|
if (loader == null)
|
||||||
|
throw new ConfigException.BugOrBroken(
|
||||||
|
"ClassLoader should have been set here; bug in ConfigFactory. "
|
||||||
|
+ "(You can probably work around this bug by passing in a class loader or calling currentThread().setContextClassLoader() though.)");
|
||||||
|
|
||||||
|
int specified = 0;
|
||||||
|
|
||||||
|
// override application.conf with config.file, config.resource,
|
||||||
|
// config.url if requested.
|
||||||
|
String resource = System.getProperty("config.resource");
|
||||||
|
if (resource != null)
|
||||||
|
specified += 1;
|
||||||
|
String file = System.getProperty("config.file");
|
||||||
|
if (file != null)
|
||||||
|
specified += 1;
|
||||||
|
String url = System.getProperty("config.url");
|
||||||
|
if (url != null)
|
||||||
|
specified += 1;
|
||||||
|
|
||||||
|
if (specified == 0) {
|
||||||
|
return ConfigFactory.parseResourcesAnySyntax("application", parseOptions);
|
||||||
|
} else if (specified > 1) {
|
||||||
|
throw new ConfigException.Generic("You set more than one of config.file='" + file
|
||||||
|
+ "', config.url='" + url + "', config.resource='" + resource
|
||||||
|
+ "'; don't know which one to use!");
|
||||||
|
} else {
|
||||||
|
// the override file/url/resource MUST be present or it's an error
|
||||||
|
ConfigParseOptions overrideOptions = parseOptions.setAllowMissing(false);
|
||||||
|
if (resource != null) {
|
||||||
|
if (resource.startsWith("/"))
|
||||||
|
resource = resource.substring(1);
|
||||||
|
// this deliberately does not parseResourcesAnySyntax; if
|
||||||
|
// people want that they can use an include statement.
|
||||||
|
return ConfigFactory.parseResources(loader, resource, overrideOptions);
|
||||||
|
} else if (file != null) {
|
||||||
|
return ConfigFactory.parseFile(new File(file), overrideOptions);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return ConfigFactory.parseURL(new URL(url), overrideOptions);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new ConfigException.Generic("Bad URL in config.url system property: '"
|
||||||
|
+ url + "': " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -624,6 +624,27 @@ class PublicApiTest extends TestUtils {
|
|||||||
assertFalse("no b", configPlain.hasPath("b"))
|
assertFalse("no b", configPlain.hasPath("b"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
def supportsConfigLoadingStrategyAlteration(): Unit = {
|
||||||
|
assertEquals("config.strategy is not set", null, System.getProperty("config.strategy"))
|
||||||
|
System.setProperty("config.strategy", classOf[TestStrategy].getCanonicalName)
|
||||||
|
|
||||||
|
try {
|
||||||
|
val incovationsBeforeTest = TestStrategy.getIncovations()
|
||||||
|
val loaderA1 = new TestClassLoader(this.getClass().getClassLoader(),
|
||||||
|
Map("reference.conf" -> resourceFile("a_1.conf").toURI.toURL()))
|
||||||
|
|
||||||
|
val configA1 = withContextClassLoader(loaderA1) {
|
||||||
|
ConfigFactory.load()
|
||||||
|
}
|
||||||
|
ConfigFactory.load()
|
||||||
|
assertEquals(1, configA1.getInt("a"))
|
||||||
|
assertEquals(2, TestStrategy.getIncovations() - incovationsBeforeTest)
|
||||||
|
} finally {
|
||||||
|
System.clearProperty("config.strategy")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def usesContextClassLoaderForApplicationConf() {
|
def usesContextClassLoaderForApplicationConf() {
|
||||||
val loaderA1 = new TestClassLoader(this.getClass().getClassLoader(),
|
val loaderA1 = new TestClassLoader(this.getClass().getClassLoader(),
|
||||||
@ -1104,3 +1125,16 @@ include "onclasspath"
|
|||||||
intercept[ConfigException.Missing] { conf.getIsNull("x.c.y") }
|
intercept[ConfigException.Missing] { conf.getIsNull("x.c.y") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestStrategy extends DefaultConfigLoadingStrategy {
|
||||||
|
override def parseApplicationConfig(parseOptions: ConfigParseOptions): Config = {
|
||||||
|
TestStrategy.increment()
|
||||||
|
super.parseApplicationConfig(parseOptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object TestStrategy {
|
||||||
|
private var invocations = 0
|
||||||
|
def getIncovations() = invocations
|
||||||
|
def increment() = invocations += 1
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user