diff --git a/src/main/java/com/typesafe/config/impl/ConfigImpl.java b/src/main/java/com/typesafe/config/impl/ConfigImpl.java index ff61cde5..fdd3bf78 100644 --- a/src/main/java/com/typesafe/config/impl/ConfigImpl.java +++ b/src/main/java/com/typesafe/config/impl/ConfigImpl.java @@ -1,20 +1,13 @@ package com.typesafe.config.impl; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Properties; import com.typesafe.config.ConfigConfig; import com.typesafe.config.ConfigException; import com.typesafe.config.ConfigObject; -import com.typesafe.config.ConfigOrigin; /** This is public but is only supposed to be used by the "config" package */ public class ConfigImpl { @@ -32,10 +25,7 @@ public class ConfigImpl { if (system != null) stack.add(system); - // now try to load a resource for each extension - addResource(configConfig.rootPath() + ".conf", stack); - addResource(configConfig.rootPath() + ".json", stack); - addResource(configConfig.rootPath() + ".properties", stack); + stack.add(Loader.load(configConfig.rootPath())); ConfigTransformer transformer = withExtraTransformer(null); @@ -49,14 +39,6 @@ public class ConfigImpl { return (AbstractConfigObject) resolved; } - private static void addResource(String name, - List stack) { - URL url = ConfigImpl.class.getResource("/" + name); - if (url != null) { - stack.add(loadURL(url)); - } - } - static ConfigObject getEnvironmentAsConfig() { // This should not need to create a new config object // as long as the transformer is just the default transformer. @@ -71,39 +53,6 @@ public class ConfigImpl { withExtraTransformer(null)); } - static AbstractConfigObject loadURL(URL url) { - if (url.getPath().endsWith(".properties")) { - ConfigOrigin origin = new SimpleConfigOrigin(url.toExternalForm()); - Properties props = new Properties(); - InputStream stream = null; - try { - stream = url.openStream(); - props.load(stream); - } catch (IOException e) { - throw new ConfigException.IO(origin, "failed to open url", e); - } finally { - if (stream != null) { - try { - stream.close(); - } catch (IOException e) { - } - } - } - return fromProperties(url.toExternalForm(), props); - } else { - return forceParsedToObject(Parser.parse(url)); - } - } - - static AbstractConfigObject forceParsedToObject(AbstractConfigValue value) { - if (value instanceof AbstractConfigObject) { - return (AbstractConfigObject) value; - } else { - throw new ConfigException.WrongType(value.origin(), "", - "object at file root", value.valueType().name()); - } - } - private static ConfigTransformer withExtraTransformer( ConfigTransformer extraTransformer) { // idea is to avoid creating a new, unique transformer if there's no @@ -120,7 +69,7 @@ public class ConfigImpl { private static ConfigTransformer defaultTransformer = null; - private synchronized static ConfigTransformer defaultConfigTransformer() { + synchronized static ConfigTransformer defaultConfigTransformer() { if (defaultTransformer == null) { defaultTransformer = new DefaultTransformer(); } @@ -137,8 +86,7 @@ public class ConfigImpl { } private static AbstractConfigObject loadSystemProperties() { - return fromProperties("system property", System.getProperties()); - + return Loader.fromProperties("system property", System.getProperties()); } // this is a hack to let us set system props in the test suite @@ -146,75 +94,6 @@ public class ConfigImpl { systemProperties = null; } - private static AbstractConfigObject fromProperties(String originPrefix, - Properties props) { - Map> scopes = new HashMap>(); - Enumeration i = props.propertyNames(); - while (i.hasMoreElements()) { - Object o = i.nextElement(); - if (o instanceof String) { - try { - String path = (String) o; - String last = ConfigUtil.lastElement(path); - String exceptLast = ConfigUtil.exceptLastElement(path); - if (exceptLast == null) - exceptLast = ""; - Map scope = scopes - .get(exceptLast); - if (scope == null) { - scope = new HashMap(); - scopes.put(exceptLast, scope); - } - String value = props.getProperty(path); - scope.put(last, new ConfigString(new SimpleConfigOrigin( - originPrefix + " " + path), value)); - } catch (ConfigException.BadPath e) { - // just skip this one (log it?) - } - } - } - - // pull out the list of objects that go inside other objects - List childPaths = new ArrayList(); - for (String path : scopes.keySet()) { - if (path != "") - childPaths.add(path); - } - - // put everything in its parent, ensuring all parents exist - for (String path : childPaths) { - String parentPath = ConfigUtil.exceptLastElement(path); - if (parentPath == null) - parentPath = ""; - - Map parent = scopes.get(parentPath); - if (parent == null) { - parent = new HashMap(); - scopes.put(parentPath, parent); - } - // NOTE: we are evil and cheating, we mutate the map we - // provide to SimpleConfigObject, which is not allowed by - // its contract, but since we know nobody has a ref to this - // SimpleConfigObject yet we can get away with it. - AbstractConfigObject o = new SimpleConfigObject( - new SimpleConfigOrigin( - originPrefix + " " + path), null, scopes.get(path)); - String basename = ConfigUtil.lastElement(path); - parent.put(basename, o); - } - - Map root = scopes.get(""); - if (root == null) { - // this would happen only if you had no properties at all - // in "props" - root = Collections. emptyMap(); - } - - // return root config object - return new SimpleConfigObject(new SimpleConfigOrigin(originPrefix), - null, root); - } - private static AbstractConfigObject envVariables = null; synchronized static AbstractConfigObject envVariablesConfig() { diff --git a/src/main/java/com/typesafe/config/impl/Loader.java b/src/main/java/com/typesafe/config/impl/Loader.java new file mode 100644 index 00000000..006916ba --- /dev/null +++ b/src/main/java/com/typesafe/config/impl/Loader.java @@ -0,0 +1,150 @@ +package com.typesafe.config.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import com.typesafe.config.ConfigException; +import com.typesafe.config.ConfigOrigin; + +final class Loader { + static AbstractConfigObject load(String name) { + List stack = new ArrayList(); + + // 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); + } else { + // .conf wins over .json wins over .properties; + // arbitrary, but deterministic + addResource(name + ".conf", stack); + addResource(name + ".json", stack); + addResource(name + ".properties", stack); + } + + AbstractConfigObject merged = AbstractConfigObject.merge( + new SimpleConfigOrigin("config for " + name), stack, + ConfigImpl.defaultConfigTransformer()); + + return merged; + } + + private static void addResource(String name, + List stack) { + URL url = ConfigImpl.class.getResource("/" + name); + if (url != null) { + stack.add(loadURL(url)); + } + } + + private static AbstractConfigObject loadURL(URL url) { + if (url.getPath().endsWith(".properties")) { + ConfigOrigin origin = new SimpleConfigOrigin(url.toExternalForm()); + Properties props = new Properties(); + InputStream stream = null; + try { + stream = url.openStream(); + props.load(stream); + } catch (IOException e) { + throw new ConfigException.IO(origin, "failed to open url", e); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } + return fromProperties(url.toExternalForm(), props); + } else { + return forceParsedToObject(Parser.parse(url)); + } + } + + private static AbstractConfigObject forceParsedToObject( + AbstractConfigValue value) { + if (value instanceof AbstractConfigObject) { + return (AbstractConfigObject) value; + } else { + throw new ConfigException.WrongType(value.origin(), "", + "object at file root", value.valueType().name()); + } + } + + static AbstractConfigObject fromProperties(String originPrefix, + Properties props) { + Map> scopes = new HashMap>(); + Enumeration i = props.propertyNames(); + while (i.hasMoreElements()) { + Object o = i.nextElement(); + if (o instanceof String) { + try { + String path = (String) o; + String last = ConfigUtil.lastElement(path); + String exceptLast = ConfigUtil.exceptLastElement(path); + if (exceptLast == null) + exceptLast = ""; + Map scope = scopes + .get(exceptLast); + if (scope == null) { + scope = new HashMap(); + scopes.put(exceptLast, scope); + } + String value = props.getProperty(path); + scope.put(last, new ConfigString(new SimpleConfigOrigin( + originPrefix + " " + path), value)); + } catch (ConfigException.BadPath e) { + // just skip this one (log it?) + } + } + } + + // pull out the list of objects that go inside other objects + List childPaths = new ArrayList(); + for (String path : scopes.keySet()) { + if (path != "") + childPaths.add(path); + } + + // put everything in its parent, ensuring all parents exist + for (String path : childPaths) { + String parentPath = ConfigUtil.exceptLastElement(path); + if (parentPath == null) + parentPath = ""; + + Map parent = scopes.get(parentPath); + if (parent == null) { + parent = new HashMap(); + scopes.put(parentPath, parent); + } + // NOTE: we are evil and cheating, we mutate the map we + // provide to SimpleConfigObject, which is not allowed by + // its contract, but since we know nobody has a ref to this + // SimpleConfigObject yet we can get away with it. + AbstractConfigObject o = new SimpleConfigObject( + new SimpleConfigOrigin(originPrefix + " " + path), null, + scopes.get(path)); + String basename = ConfigUtil.lastElement(path); + parent.put(basename, o); + } + + Map root = scopes.get(""); + if (root == null) { + // this would happen only if you had no properties at all + // in "props" + root = Collections. emptyMap(); + } + + // return root config object + return new SimpleConfigObject(new SimpleConfigOrigin(originPrefix), + null, root); + } +}