Delete SubstitutionResolver, so it's all in ResolveContext now

This commit is contained in:
Havoc Pennington 2012-03-30 20:22:10 -04:00
parent 0101d9ef37
commit a22924de6d
15 changed files with 78 additions and 111 deletions

View File

@ -86,9 +86,8 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements Confi
* *
* @throws NotPossibleToResolve * @throws NotPossibleToResolve
*/ */
protected AbstractConfigValue peekPath(Path path, SubstitutionResolver resolver, protected AbstractConfigValue peekPath(Path path, ResolveContext context) throws NotPossibleToResolve {
ResolveContext context) throws NotPossibleToResolve { return peekPath(this, path, context);
return peekPath(this, path, resolver, context);
} }
/** /**
@ -97,7 +96,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements Confi
*/ */
AbstractConfigValue peekPathWithExternalExceptions(Path path) { AbstractConfigValue peekPathWithExternalExceptions(Path path) {
try { try {
return peekPath(this, path, null, null); return peekPath(this, path, null);
} catch (NotPossibleToResolve e) { } catch (NotPossibleToResolve e) {
throw e.exportException(origin(), path.render()); throw e.exportException(origin(), path.render());
} }
@ -107,24 +106,22 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements Confi
// child being peeked, but NOT the child itself. Caller has to resolve // child being peeked, but NOT the child itself. Caller has to resolve
// the child itself if needed. // the child itself if needed.
private static AbstractConfigValue peekPath(AbstractConfigObject self, Path path, private static AbstractConfigValue peekPath(AbstractConfigObject self, Path path,
SubstitutionResolver resolver, ResolveContext context) throws NotPossibleToResolve { ResolveContext context) throws NotPossibleToResolve {
try { try {
if (resolver != null) { if (context != null) {
// walk down through the path resolving only things along that // walk down through the path resolving only things along that
// path, // path, and then recursively call ourselves with no resolve
// and then recursively call ourselves with no resolver. // context.
AbstractConfigValue partiallyResolved = context.restrict(path).resolve(resolver, AbstractConfigValue partiallyResolved = context.restrict(path).resolve(self);
self);
if (partiallyResolved instanceof AbstractConfigObject) { if (partiallyResolved instanceof AbstractConfigObject) {
return peekPath((AbstractConfigObject) partiallyResolved, path, null, null); return peekPath((AbstractConfigObject) partiallyResolved, path, null);
} else { } else {
throw new ConfigException.BugOrBroken("resolved object to non-object " + self throw new ConfigException.BugOrBroken("resolved object to non-object " + self
+ " to " + partiallyResolved); + " to " + partiallyResolved);
} }
} else { } else {
// with no resolver, we'll fail if anything along the path can't // with no resolver, we'll fail if anything along the path can't
// be // be looked at without resolving.
// looked at without resolving.
Path next = path.remainder(); Path next = path.remainder();
AbstractConfigValue v = self.attemptPeekWithPartialResolve(path.first()); AbstractConfigValue v = self.attemptPeekWithPartialResolve(path.first());
@ -132,7 +129,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements Confi
return v; return v;
} else { } else {
if (v instanceof AbstractConfigObject) { if (v instanceof AbstractConfigObject) {
return peekPath((AbstractConfigObject) v, next, null, null); return peekPath((AbstractConfigObject) v, next, null);
} else { } else {
return null; return null;
} }
@ -217,8 +214,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements Confi
} }
@Override @Override
abstract AbstractConfigObject resolveSubstitutions(SubstitutionResolver resolver, abstract AbstractConfigObject resolveSubstitutions(ResolveContext context) throws NotPossibleToResolve;
ResolveContext context) throws NotPossibleToResolve;
@Override @Override
abstract AbstractConfigObject relativized(final Path prefix); abstract AbstractConfigObject relativized(final Path prefix);

View File

@ -84,18 +84,13 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue, Seria
} }
/** /**
* Called only by SubstitutionResolver object. The "restrict to child" * Called only by ResolveContext.resolve().
* parameter is to avoid unnecessary cycles as a side effect (any sibling of
* the object we want to follow could cause a cycle, not just the object we
* want to follow, otherwise).
* *
* @param resolver
* the resolver doing the resolving
* @param context * @param context
* state of the current resolve * state of the current resolve
* @return a new value if there were changes, or this if no changes * @return a new value if there were changes, or this if no changes
*/ */
AbstractConfigValue resolveSubstitutions(SubstitutionResolver resolver, ResolveContext context) AbstractConfigValue resolveSubstitutions(ResolveContext context)
throws NotPossibleToResolve { throws NotPossibleToResolve {
return this; return this;
} }

View File

@ -64,15 +64,14 @@ final class ConfigDelayedMerge extends AbstractConfigValue implements Unmergeabl
} }
@Override @Override
AbstractConfigValue resolveSubstitutions(SubstitutionResolver resolver, ResolveContext context) AbstractConfigValue resolveSubstitutions(ResolveContext context)
throws NotPossibleToResolve { throws NotPossibleToResolve {
return resolveSubstitutions(this, stack, resolver, context); return resolveSubstitutions(this, stack, context);
} }
// static method also used by ConfigDelayedMergeObject // static method also used by ConfigDelayedMergeObject
static AbstractConfigValue resolveSubstitutions(ReplaceableMergeStack replaceable, static AbstractConfigValue resolveSubstitutions(ReplaceableMergeStack replaceable,
List<AbstractConfigValue> stack, SubstitutionResolver resolver, ResolveContext context) List<AbstractConfigValue> stack, ResolveContext context) throws NotPossibleToResolve {
throws NotPossibleToResolve {
// to resolve substitutions, we need to recursively resolve // to resolve substitutions, we need to recursively resolve
// the stack of stuff to merge, and merge the stack so // the stack of stuff to merge, and merge the stack so
// we won't be a delayed merge anymore. If restrictToChildOrNull // we won't be a delayed merge anymore. If restrictToChildOrNull
@ -99,7 +98,7 @@ final class ConfigDelayedMerge extends AbstractConfigValue implements Unmergeabl
AbstractConfigValue resolved; AbstractConfigValue resolved;
try { try {
resolved = context.resolve(resolver, v); resolved = context.resolve(v);
} finally { } finally {
if (replaced) if (replaced)
context.unreplace((AbstractConfigValue) replaceable); context.unreplace((AbstractConfigValue) replaceable);

View File

@ -60,10 +60,9 @@ final class ConfigDelayedMergeObject extends AbstractConfigObject implements Unm
} }
@Override @Override
AbstractConfigObject resolveSubstitutions(SubstitutionResolver resolver, ResolveContext context) AbstractConfigObject resolveSubstitutions(ResolveContext context)
throws NotPossibleToResolve { throws NotPossibleToResolve {
AbstractConfigValue merged = ConfigDelayedMerge.resolveSubstitutions(this, stack, resolver, AbstractConfigValue merged = ConfigDelayedMerge.resolveSubstitutions(this, stack, context);
context);
if (merged instanceof AbstractConfigObject) { if (merged instanceof AbstractConfigObject) {
return (AbstractConfigObject) merged; return (AbstractConfigObject) merged;
} else { } else {

View File

@ -142,8 +142,8 @@ final class ConfigSubstitution extends AbstractConfigValue implements
} }
}; };
private AbstractConfigValue resolveValueConcat(SubstitutionResolver resolver, private AbstractConfigValue resolveValueConcat(ResolveContext context)
ResolveContext context) throws NotPossibleToResolve { throws NotPossibleToResolve {
// need to concat everything into a string // need to concat everything into a string
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (Object p : pieces) { for (Object p : pieces) {
@ -154,8 +154,8 @@ final class ConfigSubstitution extends AbstractConfigValue implements
// to concat into a string we have to do a full resolve, // to concat into a string we have to do a full resolve,
// so unrestrict the context // so unrestrict the context
AbstractConfigValue v = context.source().lookupSubst(resolver, AbstractConfigValue v = context.source().lookupSubst(context.unrestricted(), this,
context.unrestricted(), this, exp, prefixLength); exp, prefixLength);
if (v == null) { if (v == null) {
if (exp.optional()) { if (exp.optional()) {
@ -179,15 +179,15 @@ final class ConfigSubstitution extends AbstractConfigValue implements
return new ConfigString(origin(), sb.toString()); return new ConfigString(origin(), sb.toString());
} }
private AbstractConfigValue resolveSingleSubst(SubstitutionResolver resolver, private AbstractConfigValue resolveSingleSubst(ResolveContext context)
ResolveContext context) throws NotPossibleToResolve { throws NotPossibleToResolve {
if (!(pieces.get(0) instanceof SubstitutionExpression)) if (!(pieces.get(0) instanceof SubstitutionExpression))
throw new ConfigException.BugOrBroken( throw new ConfigException.BugOrBroken(
"ConfigSubstitution should never contain a single String piece"); "ConfigSubstitution should never contain a single String piece");
SubstitutionExpression exp = (SubstitutionExpression) pieces.get(0); SubstitutionExpression exp = (SubstitutionExpression) pieces.get(0);
AbstractConfigValue v = context.source().lookupSubst(resolver, context, this, exp, AbstractConfigValue v = context.source().lookupSubst(context, this, exp,
prefixLength); prefixLength);
if (v == null && !exp.optional()) { if (v == null && !exp.optional()) {
@ -197,7 +197,7 @@ final class ConfigSubstitution extends AbstractConfigValue implements
} }
@Override @Override
AbstractConfigValue resolveSubstitutions(SubstitutionResolver resolver, ResolveContext context) AbstractConfigValue resolveSubstitutions(ResolveContext context)
throws NotPossibleToResolve { throws NotPossibleToResolve {
AbstractConfigValue resolved; AbstractConfigValue resolved;
if (pieces.size() > 1) { if (pieces.size() > 1) {
@ -206,12 +206,12 @@ final class ConfigSubstitution extends AbstractConfigValue implements
// get undefined, rather than "bar" // get undefined, rather than "bar"
context.replace(this, undefinedReplacer); context.replace(this, undefinedReplacer);
try { try {
resolved = resolveValueConcat(resolver, context); resolved = resolveValueConcat(context);
} finally { } finally {
context.unreplace(this); context.unreplace(this);
} }
} else { } else {
resolved = resolveSingleSubst(resolver, context); resolved = resolveSingleSubst(context);
} }
return resolved; return resolved;
} }

View File

@ -31,7 +31,9 @@ final class ResolveContext {
final private LinkedList<Set<MemoKey>> traversedStack; final private LinkedList<Set<MemoKey>> traversedStack;
final private ConfigResolveOptions options; final private ConfigResolveOptions options;
// the current path restriction, used to ensure lazy // the current path restriction, used to ensure lazy
// resolution and avoid gratuitous cycles. // resolution and avoid gratuitous cycles. without this,
// any sibling of an object we're traversing could
// cause a cycle "by side effect"
// CAN BE NULL for a full resolve. // CAN BE NULL for a full resolve.
final private Path restrictToChild; final private Path restrictToChild;
// if we try to resolve something in here, use the // if we try to resolve something in here, use the
@ -164,7 +166,7 @@ final class ResolveContext {
return restrict(null); return restrict(null);
} }
AbstractConfigValue resolve(SubstitutionResolver resolver, AbstractConfigValue original) AbstractConfigValue resolve(AbstractConfigValue original)
throws NotPossibleToResolve { throws NotPossibleToResolve {
// a fully-resolved (no restrictToChild) object can satisfy a // a fully-resolved (no restrictToChild) object can satisfy a
@ -198,14 +200,14 @@ final class ResolveContext {
if (replacement != original) { if (replacement != original) {
// start over, checking if replacement was memoized // start over, checking if replacement was memoized
return resolve(resolver, replacement); return resolve(replacement);
} else { } else {
AbstractConfigValue resolved; AbstractConfigValue resolved;
if (forceUndefined) if (forceUndefined)
resolved = null; resolved = null;
else else
resolved = original.resolveSubstitutions(resolver, this); resolved = original.resolveSubstitutions(this);
if (resolved == null || resolved.resolveStatus() == ResolveStatus.RESOLVED) { if (resolved == null || resolved.resolveStatus() == ResolveStatus.RESOLVED) {
// if the resolved object is fully resolved by resolving // if the resolved object is fully resolved by resolving
@ -233,4 +235,22 @@ final class ResolveContext {
} }
} }
} }
static AbstractConfigValue resolve(AbstractConfigValue value, AbstractConfigObject root,
ConfigResolveOptions options, Path restrictToChildOrNull) throws NotPossibleToResolve {
ResolveContext context = new ResolveContext(root, options, restrictToChildOrNull);
return context.resolve(value);
}
static AbstractConfigValue resolveWithExternalExceptions(AbstractConfigValue value,
AbstractConfigObject root, ConfigResolveOptions options) {
ResolveContext context = new ResolveContext(root, options, null /* restrictToChild */);
try {
return context.resolve(value);
} catch (NotPossibleToResolve e) {
throw e.exportException(value.origin(), null);
}
}
} }

View File

@ -12,25 +12,22 @@ final class ResolveSource {
this.root = root; this.root = root;
} }
/** resolver is null if we should not have refs */
static private AbstractConfigValue findInObject(final AbstractConfigObject obj, static private AbstractConfigValue findInObject(final AbstractConfigObject obj,
final SubstitutionResolver resolver, final ResolveContext context, final ResolveContext context, ConfigSubstitution traversed,
ConfigSubstitution traversed, final SubstitutionExpression subst) final SubstitutionExpression subst) throws NotPossibleToResolve {
throws NotPossibleToResolve {
return context.traversing(traversed, subst, new ResolveContext.Resolver() { return context.traversing(traversed, subst, new ResolveContext.Resolver() {
@Override @Override
public AbstractConfigValue call() throws NotPossibleToResolve { public AbstractConfigValue call() throws NotPossibleToResolve {
return obj.peekPath(subst.path(), resolver, context); return obj.peekPath(subst.path(), context);
} }
}); });
} }
AbstractConfigValue lookupSubst(final SubstitutionResolver resolver, AbstractConfigValue lookupSubst(final ResolveContext context, ConfigSubstitution traversed,
final ResolveContext context, ConfigSubstitution traversed,
final SubstitutionExpression subst, int prefixLength) throws NotPossibleToResolve { final SubstitutionExpression subst, int prefixLength) throws NotPossibleToResolve {
// First we look up the full path, which means relative to the // First we look up the full path, which means relative to the
// included file if we were not a root file // included file if we were not a root file
AbstractConfigValue result = findInObject(root, resolver, context, traversed, subst); AbstractConfigValue result = findInObject(root, context, traversed, subst);
if (result == null) { if (result == null) {
// Then we want to check relative to the root file. We don't // Then we want to check relative to the root file. We don't
@ -40,12 +37,12 @@ final class ResolveSource {
.changePath(subst.path().subPath(prefixLength)); .changePath(subst.path().subPath(prefixLength));
if (result == null && prefixLength > 0) { if (result == null && prefixLength > 0) {
result = findInObject(root, resolver, context, traversed, unprefixed); result = findInObject(root, context, traversed, unprefixed);
} }
if (result == null && context.options().getUseSystemEnvironment()) { if (result == null && context.options().getUseSystemEnvironment()) {
result = findInObject(ConfigImpl.envVariablesAsConfigObject(), null, context, result = findInObject(ConfigImpl.envVariablesAsConfigObject(), context, traversed,
traversed, unprefixed); unprefixed);
} }
} }
@ -54,7 +51,7 @@ final class ResolveSource {
result = context.traversing(traversed, subst, new ResolveContext.Resolver() { result = context.traversing(traversed, subst, new ResolveContext.Resolver() {
@Override @Override
public AbstractConfigValue call() throws NotPossibleToResolve { public AbstractConfigValue call() throws NotPossibleToResolve {
return context.resolve(resolver, unresolved); return context.resolve(unresolved);
} }
}); });
} }

View File

@ -57,7 +57,7 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
@Override @Override
public SimpleConfig resolve(ConfigResolveOptions options) { public SimpleConfig resolve(ConfigResolveOptions options) {
AbstractConfigValue resolved = SubstitutionResolver.resolveWithExternalExceptions(object, AbstractConfigValue resolved = ResolveContext.resolveWithExternalExceptions(object,
object, options); object, options);
if (resolved == object) if (resolved == object)
@ -72,7 +72,7 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
Path path = Path.newPath(pathExpression); Path path = Path.newPath(pathExpression);
ConfigValue peeked; ConfigValue peeked;
try { try {
peeked = object.peekPath(path, null, null); peeked = object.peekPath(path, null);
} catch (NotPossibleToResolve e) { } catch (NotPossibleToResolve e) {
throw e.exportException(origin(), pathExpression); throw e.exportException(origin(), pathExpression);
} catch (ConfigException.NotResolved e) { } catch (ConfigException.NotResolved e) {

View File

@ -103,8 +103,7 @@ final class SimpleConfigList extends AbstractConfigValue implements ConfigList {
} }
@Override @Override
SimpleConfigList resolveSubstitutions(final SubstitutionResolver resolver, SimpleConfigList resolveSubstitutions(final ResolveContext context) throws NotPossibleToResolve {
final ResolveContext context) throws NotPossibleToResolve {
if (resolved) if (resolved)
return this; return this;
@ -118,7 +117,7 @@ final class SimpleConfigList extends AbstractConfigValue implements ConfigList {
@Override @Override
public AbstractConfigValue modifyChildMayThrow(String key, AbstractConfigValue v) public AbstractConfigValue modifyChildMayThrow(String key, AbstractConfigValue v)
throws NotPossibleToResolve { throws NotPossibleToResolve {
return context.resolve(resolver, v); return context.resolve(v);
} }
}, ResolveStatus.RESOLVED); }, ResolveStatus.RESOLVED);

View File

@ -259,8 +259,7 @@ final class SimpleConfigObject extends AbstractConfigObject {
} }
@Override @Override
AbstractConfigObject resolveSubstitutions(final SubstitutionResolver resolver, AbstractConfigObject resolveSubstitutions(final ResolveContext context) throws NotPossibleToResolve {
final ResolveContext context) throws NotPossibleToResolve {
if (resolveStatus() == ResolveStatus.RESOLVED) if (resolveStatus() == ResolveStatus.RESOLVED)
return this; return this;
@ -274,7 +273,7 @@ final class SimpleConfigObject extends AbstractConfigObject {
if (key.equals(context.restrictToChild().first())) { if (key.equals(context.restrictToChild().first())) {
Path remainder = context.restrictToChild().remainder(); Path remainder = context.restrictToChild().remainder();
if (remainder != null) { if (remainder != null) {
return context.restrict(remainder).resolve(resolver, v); return context.restrict(remainder).resolve(v);
} else { } else {
// we don't want to resolve the leaf child. // we don't want to resolve the leaf child.
return v; return v;
@ -285,7 +284,7 @@ final class SimpleConfigObject extends AbstractConfigObject {
} }
} else { } else {
// no restrictToChild, resolve everything // no restrictToChild, resolve everything
return context.unrestricted().resolve(resolver, v); return context.unrestricted().resolve(v);
} }
} }

View File

@ -1,37 +0,0 @@
/**
* Copyright (C) 2011-2012 Typesafe Inc. <http://typesafe.com>
*/
package com.typesafe.config.impl;
import com.typesafe.config.ConfigResolveOptions;
import com.typesafe.config.impl.AbstractConfigValue.NotPossibleToResolve;
/**
* TODO there is no reason for this class to exist, will remove in upcoming
* commit
*/
final class SubstitutionResolver {
SubstitutionResolver() {
}
static AbstractConfigValue resolve(AbstractConfigValue value, AbstractConfigObject root,
ConfigResolveOptions options, Path restrictToChildOrNull) throws NotPossibleToResolve {
SubstitutionResolver resolver = new SubstitutionResolver();
ResolveContext context = new ResolveContext(root, options, restrictToChildOrNull);
return context.resolve(resolver, value);
}
static AbstractConfigValue resolveWithExternalExceptions(AbstractConfigValue value,
AbstractConfigObject root, ConfigResolveOptions options) {
SubstitutionResolver resolver = new SubstitutionResolver();
ResolveContext context = new ResolveContext(root, options, null /* restrictToChild */);
try {
return context.resolve(resolver, value);
} catch (NotPossibleToResolve e) {
throw e.exportException(value.origin(), null);
}
}
}

View File

@ -31,7 +31,7 @@ class ConfParserTest extends TestUtils {
// interpolating arrays into strings // interpolating arrays into strings
tree match { tree match {
case obj: AbstractConfigObject => case obj: AbstractConfigObject =>
SubstitutionResolver.resolveWithExternalExceptions(tree, obj, ConfigResolveOptions.noSystem()) ResolveContext.resolveWithExternalExceptions(tree, obj, ConfigResolveOptions.noSystem())
case _ => case _ =>
tree tree
} }

View File

@ -15,20 +15,20 @@ class ConfigSubstitutionTest extends TestUtils {
private def resolveWithoutFallbacks(v: AbstractConfigObject) = { private def resolveWithoutFallbacks(v: AbstractConfigObject) = {
val options = ConfigResolveOptions.noSystem() val options = ConfigResolveOptions.noSystem()
SubstitutionResolver.resolveWithExternalExceptions(v, v, options).asInstanceOf[AbstractConfigObject].toConfig ResolveContext.resolveWithExternalExceptions(v, v, options).asInstanceOf[AbstractConfigObject].toConfig
} }
private def resolveWithoutFallbacks(s: ConfigSubstitution, root: AbstractConfigObject) = { private def resolveWithoutFallbacks(s: ConfigSubstitution, root: AbstractConfigObject) = {
val options = ConfigResolveOptions.noSystem() val options = ConfigResolveOptions.noSystem()
SubstitutionResolver.resolveWithExternalExceptions(s, root, options) ResolveContext.resolveWithExternalExceptions(s, root, options)
} }
private def resolve(v: AbstractConfigObject) = { private def resolve(v: AbstractConfigObject) = {
val options = ConfigResolveOptions.defaults() val options = ConfigResolveOptions.defaults()
SubstitutionResolver.resolveWithExternalExceptions(v, v, options).asInstanceOf[AbstractConfigObject].toConfig ResolveContext.resolveWithExternalExceptions(v, v, options).asInstanceOf[AbstractConfigObject].toConfig
} }
private def resolve(s: ConfigSubstitution, root: AbstractConfigObject) = { private def resolve(s: ConfigSubstitution, root: AbstractConfigObject) = {
val options = ConfigResolveOptions.defaults() val options = ConfigResolveOptions.defaults()
SubstitutionResolver.resolveWithExternalExceptions(s, root, options) ResolveContext.resolveWithExternalExceptions(s, root, options)
} }
private val simpleObject = { private val simpleObject = {

View File

@ -20,11 +20,11 @@ import com.typesafe.config.ConfigMergeable
class ConfigTest extends TestUtils { class ConfigTest extends TestUtils {
private def resolveNoSystem(v: AbstractConfigValue, root: AbstractConfigObject) = { private def resolveNoSystem(v: AbstractConfigValue, root: AbstractConfigObject) = {
SubstitutionResolver.resolveWithExternalExceptions(v, root, ConfigResolveOptions.noSystem()) ResolveContext.resolveWithExternalExceptions(v, root, ConfigResolveOptions.noSystem())
} }
private def resolveNoSystem(v: SimpleConfig, root: SimpleConfig) = { private def resolveNoSystem(v: SimpleConfig, root: SimpleConfig) = {
SubstitutionResolver.resolveWithExternalExceptions(v.root, root.root, ResolveContext.resolveWithExternalExceptions(v.root, root.root,
ConfigResolveOptions.noSystem()).asInstanceOf[AbstractConfigObject].toConfig ConfigResolveOptions.noSystem()).asInstanceOf[AbstractConfigObject].toConfig
} }

View File

@ -34,7 +34,7 @@ class EquivalentsTest extends TestUtils {
// for purposes of these tests, substitutions are only // for purposes of these tests, substitutions are only
// against the same file's root, and without looking at // against the same file's root, and without looking at
// system prop or env variable fallbacks. // system prop or env variable fallbacks.
SubstitutionResolver.resolveWithExternalExceptions(v, v, ConfigResolveOptions.noSystem()) ResolveContext.resolveWithExternalExceptions(v, v, ConfigResolveOptions.noSystem())
case v => case v =>
v v
} }