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
*/
protected AbstractConfigValue peekPath(Path path, SubstitutionResolver resolver,
ResolveContext context) throws NotPossibleToResolve {
return peekPath(this, path, resolver, context);
protected AbstractConfigValue peekPath(Path path, ResolveContext context) throws NotPossibleToResolve {
return peekPath(this, path, context);
}
/**
@ -97,7 +96,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements Confi
*/
AbstractConfigValue peekPathWithExternalExceptions(Path path) {
try {
return peekPath(this, path, null, null);
return peekPath(this, path, null);
} catch (NotPossibleToResolve e) {
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
// the child itself if needed.
private static AbstractConfigValue peekPath(AbstractConfigObject self, Path path,
SubstitutionResolver resolver, ResolveContext context) throws NotPossibleToResolve {
ResolveContext context) throws NotPossibleToResolve {
try {
if (resolver != null) {
if (context != null) {
// walk down through the path resolving only things along that
// path,
// and then recursively call ourselves with no resolver.
AbstractConfigValue partiallyResolved = context.restrict(path).resolve(resolver,
self);
// path, and then recursively call ourselves with no resolve
// context.
AbstractConfigValue partiallyResolved = context.restrict(path).resolve(self);
if (partiallyResolved instanceof AbstractConfigObject) {
return peekPath((AbstractConfigObject) partiallyResolved, path, null, null);
return peekPath((AbstractConfigObject) partiallyResolved, path, null);
} else {
throw new ConfigException.BugOrBroken("resolved object to non-object " + self
+ " to " + partiallyResolved);
}
} else {
// with no resolver, we'll fail if anything along the path can't
// be
// looked at without resolving.
// be looked at without resolving.
Path next = path.remainder();
AbstractConfigValue v = self.attemptPeekWithPartialResolve(path.first());
@ -132,7 +129,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements Confi
return v;
} else {
if (v instanceof AbstractConfigObject) {
return peekPath((AbstractConfigObject) v, next, null, null);
return peekPath((AbstractConfigObject) v, next, null);
} else {
return null;
}
@ -217,8 +214,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements Confi
}
@Override
abstract AbstractConfigObject resolveSubstitutions(SubstitutionResolver resolver,
ResolveContext context) throws NotPossibleToResolve;
abstract AbstractConfigObject resolveSubstitutions(ResolveContext context) throws NotPossibleToResolve;
@Override
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"
* 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).
* Called only by ResolveContext.resolve().
*
* @param resolver
* the resolver doing the resolving
* @param context
* state of the current resolve
* @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 {
return this;
}

View File

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

View File

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

View File

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

View File

@ -31,7 +31,9 @@ final class ResolveContext {
final private LinkedList<Set<MemoKey>> traversedStack;
final private ConfigResolveOptions options;
// 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.
final private Path restrictToChild;
// if we try to resolve something in here, use the
@ -164,7 +166,7 @@ final class ResolveContext {
return restrict(null);
}
AbstractConfigValue resolve(SubstitutionResolver resolver, AbstractConfigValue original)
AbstractConfigValue resolve(AbstractConfigValue original)
throws NotPossibleToResolve {
// a fully-resolved (no restrictToChild) object can satisfy a
@ -198,14 +200,14 @@ final class ResolveContext {
if (replacement != original) {
// start over, checking if replacement was memoized
return resolve(resolver, replacement);
return resolve(replacement);
} else {
AbstractConfigValue resolved;
if (forceUndefined)
resolved = null;
else
resolved = original.resolveSubstitutions(resolver, this);
resolved = original.resolveSubstitutions(this);
if (resolved == null || resolved.resolveStatus() == ResolveStatus.RESOLVED) {
// 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;
}
/** resolver is null if we should not have refs */
static private AbstractConfigValue findInObject(final AbstractConfigObject obj,
final SubstitutionResolver resolver, final ResolveContext context,
ConfigSubstitution traversed, final SubstitutionExpression subst)
throws NotPossibleToResolve {
final ResolveContext context, ConfigSubstitution traversed,
final SubstitutionExpression subst) throws NotPossibleToResolve {
return context.traversing(traversed, subst, new ResolveContext.Resolver() {
@Override
public AbstractConfigValue call() throws NotPossibleToResolve {
return obj.peekPath(subst.path(), resolver, context);
return obj.peekPath(subst.path(), context);
}
});
}
AbstractConfigValue lookupSubst(final SubstitutionResolver resolver,
final ResolveContext context, ConfigSubstitution traversed,
AbstractConfigValue lookupSubst(final ResolveContext context, ConfigSubstitution traversed,
final SubstitutionExpression subst, int prefixLength) throws NotPossibleToResolve {
// First we look up the full path, which means relative to the
// 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) {
// 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));
if (result == null && prefixLength > 0) {
result = findInObject(root, resolver, context, traversed, unprefixed);
result = findInObject(root, context, traversed, unprefixed);
}
if (result == null && context.options().getUseSystemEnvironment()) {
result = findInObject(ConfigImpl.envVariablesAsConfigObject(), null, context,
traversed, unprefixed);
result = findInObject(ConfigImpl.envVariablesAsConfigObject(), context, traversed,
unprefixed);
}
}
@ -54,7 +51,7 @@ final class ResolveSource {
result = context.traversing(traversed, subst, new ResolveContext.Resolver() {
@Override
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
public SimpleConfig resolve(ConfigResolveOptions options) {
AbstractConfigValue resolved = SubstitutionResolver.resolveWithExternalExceptions(object,
AbstractConfigValue resolved = ResolveContext.resolveWithExternalExceptions(object,
object, options);
if (resolved == object)
@ -72,7 +72,7 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
Path path = Path.newPath(pathExpression);
ConfigValue peeked;
try {
peeked = object.peekPath(path, null, null);
peeked = object.peekPath(path, null);
} catch (NotPossibleToResolve e) {
throw e.exportException(origin(), pathExpression);
} catch (ConfigException.NotResolved e) {

View File

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

View File

@ -259,8 +259,7 @@ final class SimpleConfigObject extends AbstractConfigObject {
}
@Override
AbstractConfigObject resolveSubstitutions(final SubstitutionResolver resolver,
final ResolveContext context) throws NotPossibleToResolve {
AbstractConfigObject resolveSubstitutions(final ResolveContext context) throws NotPossibleToResolve {
if (resolveStatus() == ResolveStatus.RESOLVED)
return this;
@ -274,7 +273,7 @@ final class SimpleConfigObject extends AbstractConfigObject {
if (key.equals(context.restrictToChild().first())) {
Path remainder = context.restrictToChild().remainder();
if (remainder != null) {
return context.restrict(remainder).resolve(resolver, v);
return context.restrict(remainder).resolve(v);
} else {
// we don't want to resolve the leaf child.
return v;
@ -285,7 +284,7 @@ final class SimpleConfigObject extends AbstractConfigObject {
}
} else {
// 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
tree match {
case obj: AbstractConfigObject =>
SubstitutionResolver.resolveWithExternalExceptions(tree, obj, ConfigResolveOptions.noSystem())
ResolveContext.resolveWithExternalExceptions(tree, obj, ConfigResolveOptions.noSystem())
case _ =>
tree
}

View File

@ -15,20 +15,20 @@ class ConfigSubstitutionTest extends TestUtils {
private def resolveWithoutFallbacks(v: AbstractConfigObject) = {
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) = {
val options = ConfigResolveOptions.noSystem()
SubstitutionResolver.resolveWithExternalExceptions(s, root, options)
ResolveContext.resolveWithExternalExceptions(s, root, options)
}
private def resolve(v: AbstractConfigObject) = {
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) = {
val options = ConfigResolveOptions.defaults()
SubstitutionResolver.resolveWithExternalExceptions(s, root, options)
ResolveContext.resolveWithExternalExceptions(s, root, options)
}
private val simpleObject = {

View File

@ -20,11 +20,11 @@ import com.typesafe.config.ConfigMergeable
class ConfigTest extends TestUtils {
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) = {
SubstitutionResolver.resolveWithExternalExceptions(v.root, root.root,
ResolveContext.resolveWithExternalExceptions(v.root, root.root,
ConfigResolveOptions.noSystem()).asInstanceOf[AbstractConfigObject].toConfig
}

View File

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