mirror of
https://github.com/lightbend/config.git
synced 2025-01-28 21:20:07 +08:00
pass an "includer" object down to the parser
This commit is contained in:
parent
9509876ced
commit
cdcde9eebc
@ -25,7 +25,11 @@ public class ConfigImpl {
|
||||
if (system != null)
|
||||
stack.add(system);
|
||||
|
||||
stack.add(Loader.load(configConfig.rootPath()));
|
||||
// this is a conceptual placeholder for a customizable
|
||||
// object that the app might be able to pass in.
|
||||
IncludeHandler includer = defaultIncluder();
|
||||
|
||||
stack.add(includer.include(configConfig.rootPath()));
|
||||
|
||||
ConfigTransformer transformer = withExtraTransformer(null);
|
||||
|
||||
@ -76,6 +80,21 @@ public class ConfigImpl {
|
||||
return defaultTransformer;
|
||||
}
|
||||
|
||||
private static IncludeHandler defaultIncluder = null;
|
||||
|
||||
synchronized static IncludeHandler defaultIncluder() {
|
||||
if (defaultIncluder == null) {
|
||||
defaultIncluder = new IncludeHandler() {
|
||||
|
||||
@Override
|
||||
public AbstractConfigObject include(String name) {
|
||||
return Loader.load(name, this);
|
||||
}
|
||||
};
|
||||
}
|
||||
return defaultIncluder;
|
||||
}
|
||||
|
||||
private static AbstractConfigObject systemProperties = null;
|
||||
|
||||
synchronized static AbstractConfigObject systemPropertiesConfig() {
|
||||
|
11
src/main/java/com/typesafe/config/impl/IncludeHandler.java
Normal file
11
src/main/java/com/typesafe/config/impl/IncludeHandler.java
Normal file
@ -0,0 +1,11 @@
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
/**
|
||||
* This is sort of a placeholder so that something per-config-load is passed in
|
||||
* to the parser to handle includes. The eventual idea is to let apps customize
|
||||
* how an included name gets searched for, which would involve some nicer
|
||||
* interface in the public API.
|
||||
*/
|
||||
interface IncludeHandler {
|
||||
AbstractConfigObject include(String name);
|
||||
}
|
@ -15,19 +15,19 @@ import com.typesafe.config.ConfigException;
|
||||
import com.typesafe.config.ConfigOrigin;
|
||||
|
||||
final class Loader {
|
||||
static AbstractConfigObject load(String name) {
|
||||
static AbstractConfigObject load(String name, IncludeHandler includer) {
|
||||
List<AbstractConfigObject> stack = new ArrayList<AbstractConfigObject>();
|
||||
|
||||
// if name has an extension, only use that; otherwise merge all three
|
||||
if (name.endsWith(".conf") || name.endsWith(".json")
|
||||
|| name.endsWith(".properties")) {
|
||||
addResource(name, stack);
|
||||
addResource(name, includer, stack);
|
||||
} else {
|
||||
// .conf wins over .json wins over .properties;
|
||||
// arbitrary, but deterministic
|
||||
addResource(name + ".conf", stack);
|
||||
addResource(name + ".json", stack);
|
||||
addResource(name + ".properties", stack);
|
||||
addResource(name + ".conf", includer, stack);
|
||||
addResource(name + ".json", includer, stack);
|
||||
addResource(name + ".properties", includer, stack);
|
||||
}
|
||||
|
||||
AbstractConfigObject merged = AbstractConfigObject.merge(
|
||||
@ -37,15 +37,15 @@ final class Loader {
|
||||
return merged;
|
||||
}
|
||||
|
||||
private static void addResource(String name,
|
||||
private static void addResource(String name, IncludeHandler includer,
|
||||
List<AbstractConfigObject> stack) {
|
||||
URL url = ConfigImpl.class.getResource("/" + name);
|
||||
if (url != null) {
|
||||
stack.add(loadURL(url));
|
||||
stack.add(loadURL(url, includer));
|
||||
}
|
||||
}
|
||||
|
||||
private static AbstractConfigObject loadURL(URL url) {
|
||||
private static AbstractConfigObject loadURL(URL url, IncludeHandler includer) {
|
||||
if (url.getPath().endsWith(".properties")) {
|
||||
ConfigOrigin origin = new SimpleConfigOrigin(url.toExternalForm());
|
||||
Properties props = new Properties();
|
||||
@ -65,7 +65,7 @@ final class Loader {
|
||||
}
|
||||
return fromProperties(url.toExternalForm(), props);
|
||||
} else {
|
||||
return forceParsedToObject(Parser.parse(url));
|
||||
return forceParsedToObject(Parser.parse(url, includer));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,9 +29,10 @@ final class Parser {
|
||||
* yourself.
|
||||
*/
|
||||
static AbstractConfigValue parse(SyntaxFlavor flavor, ConfigOrigin origin,
|
||||
InputStream input) {
|
||||
InputStream input, IncludeHandler includer) {
|
||||
try {
|
||||
return parse(flavor, origin, new InputStreamReader(input, "UTF-8"));
|
||||
return parse(flavor, origin, new InputStreamReader(input, "UTF-8"),
|
||||
includer);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new ConfigException.BugOrBroken(
|
||||
"Java runtime does not support UTF-8");
|
||||
@ -39,14 +40,14 @@ final class Parser {
|
||||
}
|
||||
|
||||
static AbstractConfigValue parse(SyntaxFlavor flavor, ConfigOrigin origin,
|
||||
Reader input) {
|
||||
Reader input, IncludeHandler includer) {
|
||||
Iterator<Token> tokens = Tokenizer.tokenize(origin, input);
|
||||
return parse(flavor, origin, tokens);
|
||||
return parse(flavor, origin, tokens, includer);
|
||||
}
|
||||
|
||||
static AbstractConfigValue parse(SyntaxFlavor flavor, ConfigOrigin origin,
|
||||
String input) {
|
||||
return parse(flavor, origin, new StringReader(input));
|
||||
String input, IncludeHandler includer) {
|
||||
return parse(flavor, origin, new StringReader(input), includer);
|
||||
}
|
||||
|
||||
private static SyntaxFlavor flavorFromExtension(String name,
|
||||
@ -59,38 +60,41 @@ final class Parser {
|
||||
throw new ConfigException.IO(origin, "Unknown filename extension");
|
||||
}
|
||||
|
||||
static AbstractConfigValue parse(File f) {
|
||||
return parse(null, f);
|
||||
static AbstractConfigValue parse(File f, IncludeHandler includer) {
|
||||
return parse(null, f, includer);
|
||||
}
|
||||
|
||||
static AbstractConfigValue parse(SyntaxFlavor flavor, File f) {
|
||||
static AbstractConfigValue parse(SyntaxFlavor flavor, File f,
|
||||
IncludeHandler includer) {
|
||||
ConfigOrigin origin = new SimpleConfigOrigin(f.getPath());
|
||||
try {
|
||||
return parse(flavor, origin, f.toURI().toURL());
|
||||
return parse(flavor, origin, f.toURI().toURL(), includer);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new ConfigException.IO(origin,
|
||||
"failed to create url from file path", e);
|
||||
}
|
||||
}
|
||||
|
||||
static AbstractConfigValue parse(URL url) {
|
||||
return parse(null, url);
|
||||
static AbstractConfigValue parse(URL url, IncludeHandler includer) {
|
||||
return parse(null, url, includer);
|
||||
}
|
||||
|
||||
static AbstractConfigValue parse(SyntaxFlavor flavor, URL url) {
|
||||
static AbstractConfigValue parse(SyntaxFlavor flavor, URL url,
|
||||
IncludeHandler includer) {
|
||||
ConfigOrigin origin = new SimpleConfigOrigin(url.toExternalForm());
|
||||
return parse(flavor, origin, url);
|
||||
return parse(flavor, origin, url, includer);
|
||||
}
|
||||
|
||||
static AbstractConfigValue parse(SyntaxFlavor flavor, ConfigOrigin origin,
|
||||
URL url) {
|
||||
URL url, IncludeHandler includer) {
|
||||
AbstractConfigValue result = null;
|
||||
try {
|
||||
InputStream stream = new BufferedInputStream(url.openStream());
|
||||
try {
|
||||
result = parse(
|
||||
flavor != null ? flavor : flavorFromExtension(
|
||||
url.getPath(), origin), origin, stream);
|
||||
url.getPath(), origin), origin, stream,
|
||||
includer);
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
@ -104,16 +108,18 @@ final class Parser {
|
||||
private int lineNumber;
|
||||
private Stack<Token> buffer;
|
||||
private Iterator<Token> tokens;
|
||||
private IncludeHandler includer;
|
||||
private SyntaxFlavor flavor;
|
||||
private ConfigOrigin baseOrigin;
|
||||
|
||||
ParseContext(SyntaxFlavor flavor, ConfigOrigin origin,
|
||||
Iterator<Token> tokens) {
|
||||
Iterator<Token> tokens, IncludeHandler includer) {
|
||||
lineNumber = 0;
|
||||
buffer = new Stack<Token>();
|
||||
this.tokens = tokens;
|
||||
this.flavor = flavor;
|
||||
this.baseOrigin = origin;
|
||||
this.includer = includer;
|
||||
}
|
||||
|
||||
private Token nextToken() {
|
||||
@ -395,9 +401,9 @@ final class Parser {
|
||||
}
|
||||
|
||||
private static AbstractConfigValue parse(SyntaxFlavor flavor,
|
||||
ConfigOrigin origin,
|
||||
Iterator<Token> tokens) {
|
||||
ParseContext context = new ParseContext(flavor, origin, tokens);
|
||||
ConfigOrigin origin, Iterator<Token> tokens, IncludeHandler includer) {
|
||||
ParseContext context = new ParseContext(flavor, origin, tokens,
|
||||
includer);
|
||||
return context.parse();
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import java.util.HashMap
|
||||
class ConfParserTest extends TestUtils {
|
||||
|
||||
def parse(s: String): ConfigValue = {
|
||||
Parser.parse(SyntaxFlavor.CONF, new SimpleConfigOrigin("test conf string"), s)
|
||||
Parser.parse(SyntaxFlavor.CONF, new SimpleConfigOrigin("test conf string"), s, includer())
|
||||
}
|
||||
|
||||
private def addOffendingJsonToException[R](parserName: String, s: String)(body: => R) = {
|
||||
|
@ -41,11 +41,11 @@ class EquivalentsTest extends TestUtils {
|
||||
}
|
||||
|
||||
private def parse(flavor: SyntaxFlavor, f: File) = {
|
||||
postParse(Parser.parse(flavor, f))
|
||||
postParse(Parser.parse(flavor, f, includer()))
|
||||
}
|
||||
|
||||
private def parse(f: File) = {
|
||||
postParse(Parser.parse(f))
|
||||
postParse(Parser.parse(f, includer()))
|
||||
}
|
||||
|
||||
// would like each "equivNN" directory to be a suite and each file in the dir
|
||||
|
@ -12,11 +12,11 @@ import java.util.Collections
|
||||
class JsonTest extends TestUtils {
|
||||
|
||||
def parse(s: String): ConfigValue = {
|
||||
Parser.parse(SyntaxFlavor.JSON, new SimpleConfigOrigin("test json string"), s)
|
||||
Parser.parse(SyntaxFlavor.JSON, new SimpleConfigOrigin("test json string"), s, includer())
|
||||
}
|
||||
|
||||
def parseAsConf(s: String): ConfigValue = {
|
||||
Parser.parse(SyntaxFlavor.CONF, new SimpleConfigOrigin("test conf string"), s)
|
||||
Parser.parse(SyntaxFlavor.CONF, new SimpleConfigOrigin("test conf string"), s, includer())
|
||||
}
|
||||
|
||||
private[this] def toLift(value: ConfigValue): lift.JValue = {
|
||||
|
@ -75,6 +75,10 @@ abstract trait TestUtils {
|
||||
new SimpleConfigOrigin("fake origin")
|
||||
}
|
||||
|
||||
def includer() = {
|
||||
ConfigImpl.defaultIncluder();
|
||||
}
|
||||
|
||||
case class ParseTest(liftBehaviorUnexpected: Boolean, whitespaceMatters: Boolean, test: String)
|
||||
object ParseTest {
|
||||
def apply(liftBehaviorUnexpected: Boolean, test: String): ParseTest = {
|
||||
@ -209,7 +213,7 @@ abstract trait TestUtils {
|
||||
protected def doubleValue(d: Double) = new ConfigDouble(fakeOrigin(), d)
|
||||
|
||||
protected def parseObject(s: String) = {
|
||||
Parser.parse(SyntaxFlavor.CONF, new SimpleConfigOrigin("test string"), s).asInstanceOf[AbstractConfigObject]
|
||||
Parser.parse(SyntaxFlavor.CONF, new SimpleConfigOrigin("test string"), s, includer()).asInstanceOf[AbstractConfigObject]
|
||||
}
|
||||
|
||||
protected def subst(ref: String, style: SubstitutionStyle = SubstitutionStyle.PATH) = {
|
||||
|
Loading…
Reference in New Issue
Block a user