refactor and tidy config-value classes

Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/e8d44d5a
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/e8d44d5a
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/e8d44d5a

Branch: refs/heads/master
Commit: e8d44d5a051dc8dff4d994905b67a15bd6752aa5
Parents: bcd8b26
Author: Alex Heneveld <alex.henev...@cloudsoftcorp.com>
Authored: Tue Sep 20 15:56:23 2016 +0100
Committer: Alex Heneveld <alex.henev...@cloudsoftcorp.com>
Committed: Wed Sep 21 16:06:07 2016 +0100

----------------------------------------------------------------------
 .../BrooklynComponentTemplateResolver.java      |  33 ++---
 .../core/config/BasicConfigInheritance.java     | 130 +++++++----------
 .../apache/brooklyn/core/config/ConfigKeys.java |  27 ++--
 .../config/internal/AbstractConfigMapImpl.java  |   6 +-
 .../AncestorContainerAndKeyValueIterator.java   |  63 ++++++++
 .../internal/BasicConfigValueAtContainer.java   |  54 +++++++
 .../internal/LazyContainerAndKeyValue.java      |  83 +++++++++++
 .../core/entity/internal/EntityConfigMap.java   |  10 +-
 .../location/internal/LocationConfigMap.java    |  10 +-
 .../brooklyn/core/objs/AdjunctConfigMap.java    |   6 +-
 .../entity/ConfigEntityInheritanceTest.java     |  14 +-
 .../brooklyn/config/ConfigInheritance.java      | 143 ++++---------------
 .../brooklyn/config/ConfigValueAtContainer.java |  40 ++++++
 13 files changed, 370 insertions(+), 249 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git 
a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
 
b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index 8cbe4b8..2f7c643 100644
--- 
a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ 
b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -46,14 +46,13 @@ import 
org.apache.brooklyn.camp.spi.ApplicationComponentTemplate;
 import org.apache.brooklyn.camp.spi.AssemblyTemplate;
 import org.apache.brooklyn.camp.spi.PlatformComponentTemplate;
 import org.apache.brooklyn.config.ConfigInheritance;
-import org.apache.brooklyn.config.ConfigInheritance.ContainerAndKeyValue;
-import org.apache.brooklyn.config.ConfigInheritance.ContainerAndValue;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.ConfigValueAtContainer;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.config.BasicConfigInheritance;
-import 
org.apache.brooklyn.core.config.BasicConfigInheritance.BasicContainerAndKeyValue;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.ConfigKeys.InheritanceContext;
+import org.apache.brooklyn.core.config.internal.LazyContainerAndKeyValue;
 import org.apache.brooklyn.core.mgmt.BrooklynTags;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
@@ -290,57 +289,59 @@ public class BrooklynComponentTemplateResolver {
         Collection<FlagConfigKeyAndValueRecord> records = 
findAllFlagsAndConfigKeyValues(spec, bag);
         Set<String> keyNamesUsed = new LinkedHashSet<String>();
         for (FlagConfigKeyAndValueRecord r: records) {
+            // run through flags *and* config keys (may be overkill, but...)
+            
             if (r.getFlagMaybeValue().isPresent()) {
                 final String flag = r.getFlagName();
                 final ConfigKey<Object> key = (ConfigKey<Object>) 
r.getConfigKey();
                 if (key==null) ConfigKeys.newConfigKey(Object.class, flag);
                 final Object ownValueF = new SpecialFlagsTransformer(loader, 
encounteredRegisteredTypeIds).apply(r.getFlagMaybeValue().get());
 
-                Iterable<? extends ContainerAndKeyValue<Object>> ckvi = 
MutableList.of(
-                    new BasicContainerAndKeyValue<Void,Object>(key, null, new 
Function<Void,Maybe<Object>>() {
+                Iterable<? extends 
ConfigValueAtContainer<EntitySpec<?>,Object>> ckvi = MutableList.of(
+                    new LazyContainerAndKeyValue<EntitySpec<?>,Object>(key, 
null, new Function<EntitySpec<?>,Maybe<Object>>() {
                         @Override
-                        public Maybe<Object> apply(Void input) {
+                        public Maybe<Object> apply(EntitySpec<?> input) {
                             return spec.getFlags().containsKey(flag) ? 
Maybe.of((Object)spec.getFlags().get(flag)) : Maybe.absent();
                         }
                     }));
                 
-                ContainerAndValue<Object> combinedVal = 
getDefaultConfigInheritance().resolveInheriting(
+                ConfigValueAtContainer<EntitySpec<?>,Object> combinedVal = 
getDefaultConfigInheritance().resolveInheriting(
                     key, Maybe.ofAllowingNull(ownValueF), null,
                     ckvi.iterator(), InheritanceContext.TYPE_DEFINITION);
                 
-                spec.configure(flag, combinedVal.getValue());
+                spec.configure(flag, combinedVal.get());
                 keyNamesUsed.add(flag);
             }
             
             if (r.getConfigKeyMaybeValue().isPresent()) {
                 final ConfigKey<Object> key = (ConfigKey<Object>) 
r.getConfigKey();
                 final Object ownValueF = new SpecialFlagsTransformer(loader, 
encounteredRegisteredTypeIds).apply(r.getConfigKeyMaybeValue().get());
-                Iterable<? extends ContainerAndKeyValue<Object>> ckvi = 
MutableList.of(
-                    new BasicContainerAndKeyValue<Void,Object>(key, null, new 
Function<Void,Maybe<Object>>() {
+                Iterable<? extends 
ConfigValueAtContainer<EntitySpec<?>,Object>> ckvi = MutableList.of(
+                    new LazyContainerAndKeyValue<EntitySpec<?>,Object>(key, 
null, new Function<EntitySpec<?>,Maybe<Object>>() {
                         @Override
-                        public Maybe<Object> apply(Void input) {
+                        public Maybe<Object> apply(EntitySpec<?> input) {
                             return spec.getConfig().containsKey(key) ? 
Maybe.of(spec.getConfig().get(key)) : Maybe.absent();
                         }
                     }));
                 
-                ContainerAndValue<Object> combinedVal = 
getDefaultConfigInheritance().resolveInheriting(
+                ConfigValueAtContainer<EntitySpec<?>,Object> combinedVal = 
getDefaultConfigInheritance().resolveInheriting(
                     key, Maybe.ofAllowingNull(ownValueF), null,
                     ckvi.iterator(), InheritanceContext.TYPE_DEFINITION);
                 
-                spec.configure(key, combinedVal.getValue());
+                spec.configure(key, combinedVal.get());
                 keyNamesUsed.add(key.getName());
             }
         }
-        
-        // TODO clean up above
 
         // For anything that should not be inherited, clear it from the spec 
(if not set above)
+        // (very few things follow this, esp not on the spec; things like 
camp.id do;
+        // the meaning here is essentially that the given config cannot be 
stored in a parent spec)
         for (Map.Entry<String, ConfigKey<?>> entry : 
entityConfigKeys.entrySet()) {
             if (keyNamesUsed.contains(entry.getKey())) {
                 continue;
             }
             ConfigKey<?> key = entry.getValue();
-            if (!ConfigKeys.isReinherited(key, 
InheritanceContext.TYPE_DEFINITION)) {
+            if (!ConfigKeys.isKeyReinheritable(key, 
InheritanceContext.TYPE_DEFINITION)) {
                 spec.removeConfig(key);
                 spec.removeFlag(key.getName());
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigInheritance.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigInheritance.java
 
b/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigInheritance.java
index 764e0d6..edd8550 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigInheritance.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/config/BasicConfigInheritance.java
@@ -26,6 +26,9 @@ import javax.annotation.Nullable;
 
 import org.apache.brooklyn.config.ConfigInheritance;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.ConfigValueAtContainer;
+import org.apache.brooklyn.core.config.internal.BasicConfigValueAtContainer;
+import org.apache.brooklyn.core.config.internal.LazyContainerAndKeyValue;
 import org.apache.brooklyn.util.collections.CollectionMerger;
 import org.apache.brooklyn.util.guava.Maybe;
 
@@ -35,11 +38,24 @@ public class BasicConfigInheritance implements 
ConfigInheritance {
 
     private static final long serialVersionUID = -5916548049057961051L;
 
-    // TODO javadoc
+    /** Indicates that a config key value should not be passed down from a 
container where it is defined.
+     * Unlike {@link #NEVER_INHERITED} these values can be passed down if set 
as anonymous keys at a container
+     * (ie the container does not expect it) to a container which does expect 
it, but it will not be passed down further. 
+     * If the inheritor also defines a value the parent's value is ignored 
irrespective 
+     * (as in {@link #OVERWRITE}; see {@link #NOT_REINHERITED_ELSE_DEEP_MERGE} 
if merging is desired). */
     public static BasicConfigInheritance NOT_REINHERITED = new 
BasicConfigInheritance(false,"overwrite",false);
+    /** As {@link #NOT_REINHERITED} but in cases where a value is inherited 
because a parent did not recognize it,
+     * if the inheritor also defines a value the two values should be merged. 
*/
     public static BasicConfigInheritance NOT_REINHERITED_ELSE_DEEP_MERGE = new 
BasicConfigInheritance(false,"deep_merge",false);
+    /** Indicates that a key's value should never be inherited, even if 
defined on a container that does not know the key.
+     * Most usages will prefer {@link #NOT_REINHERITED}. */
     public static BasicConfigInheritance NEVER_INHERITED = new 
BasicConfigInheritance(false,"overwrite",true);
+    /** Indicates that if a key has a value at both an ancestor and a 
descendant, the descendant and his descendants
+     * will prefer the value at the descendant. */
     public static BasicConfigInheritance OVERWRITE = new 
BasicConfigInheritance(true,"overwrite",false);
+    /** Indicates that if a key has a value at both an ancestor and a 
descendant, the descendant and his descendants
+     * should attempt to merge the values. If the values are not mergable 
behaviour is undefined
+     * (and often the descendant's value will simply overwrite). */
     public static BasicConfigInheritance DEEP_MERGE = new 
BasicConfigInheritance(true,"deep_merge",false);
     
     // reinheritable? true/false; if false, children/descendants/inheritors 
will never see it; default true
@@ -65,71 +81,67 @@ public class BasicConfigInheritance implements 
ConfigInheritance {
     }
     
     @Override
-    public <T> ContainerAndValue<T> resolveInheriting(
-            @Nullable ConfigKey<T> key, Maybe<T> localValue, Object container,
-            Iterator<? extends ContainerAndKeyValue<T>> 
ancestorContainerKeyValues, ConfigInheritanceContext context) {
+    public <TContainer,TValue> ConfigValueAtContainer<TContainer,TValue> 
resolveInheriting(
+            @Nullable ConfigKey<TValue> key, Maybe<TValue> localValue, 
TContainer container,
+            Iterator<? extends ConfigValueAtContainer<TContainer,TValue>> 
ancestorContainerKeyValues, ConfigInheritanceContext context) {
         ConfigInheritance inh = key==null ? null : 
key.getInheritanceByContext(context);
         if (inh==null) inh = this;
         if (inh!=this) return inh.resolveInheriting(key, localValue, 
container, ancestorContainerKeyValues, context);
         
-        ContainerAndValue<T> v2 = null;
-        if 
(OVERWRITE.conflictResolutionStrategy.equals(conflictResolutionStrategy) && 
localValue.isPresent()) {
+        ConfigValueAtContainer<TContainer,TValue> v2 = null;
+        if 
(OVERWRITE.conflictResolutionStrategy.equals(conflictResolutionStrategy) && 
+                (localValue.isPresent() || useLocalDefaultValue)) {
             // don't inherit
         } else if (ancestorContainerKeyValues==null || 
!ancestorContainerKeyValues.hasNext()) {
             // nothing to inherit
         } else {
             // check whether parent allows us to get inherited value
-            ContainerAndKeyValue<T> c = ancestorContainerKeyValues.next();
+            ConfigValueAtContainer<TContainer,TValue> c = 
ancestorContainerKeyValues.next();
             ConfigInheritance inh2 = c.getKey()==null ? null : 
c.getKey().getInheritanceByContext(context);
-            if (inh2!=null && !ConfigKeys.isReinherited(c.getKey(), context)) {
+            if (inh2!=null && !ConfigKeys.isKeyReinheritable(c.getKey(), 
context)) {
                 // can't inherit
             } else {
                 // get inherited value
                 if (inh2==null) inh2=this;
                 v2 = inh2.resolveInheriting(c.getKey()!=null ? c.getKey() : 
null, 
-                    c.isValueSet() ? Maybe.of(c.getValue()) : 
Maybe.<T>absent(), c.getContainer(), 
+                    c.isValueExplicitlySet() ? c.asMaybe() : 
Maybe.<TValue>absent(), c.getContainer(), 
                         ancestorContainerKeyValues, context);
             }
         }
 
-        Maybe<T> localValueOrConflictableDefault = localValue.isPresent() ? 
localValue : 
-            useLocalDefaultValue ? Maybe.ofAllowingNull(key==null || 
!key.hasDefaultValue() ? null : key.getDefaultValue()) :
-            Maybe.<T>absent();
-        if (v2!=null && v2.isValueSet() && 
!localValueOrConflictableDefault.isPresent()) return v2;
-        Result<T> v = new Result<T>();
-        v.container = container;
-        if (v2==null || !v2.isValueSet()) {
-            v.isValueSet = localValue.isPresent();
-            v.value = v.isValueSet() ? localValue.get() : key!=null ? 
key.getDefaultValue() : null; 
+        BasicConfigValueAtContainer<TContainer,TValue> v = new 
BasicConfigValueAtContainer<TContainer,TValue>();
+        v.setContainer(container);
+        v.setKey(key);
+        
+        Maybe<TValue> localValueOrConflictableDefault = localValue.isPresent() 
? localValue : 
+            useLocalDefaultValue ? v.getDefaultValueMaybe() : 
Maybe.<TValue>absent();
+        if (v2!=null && v2.isValueExplicitlySet() && 
!localValueOrConflictableDefault.isPresent()) return v2;
+        if (v2==null || !v2.isValueExplicitlySet()) {
+            v.setValueWasExplicitlySet(localValue.isPresent());
+            v.setValue(v.isValueExplicitlySet() ? localValue : 
v.getDefaultValueMaybe()); 
         } else {
-            v.value = resolveConflict(key, localValue, 
Maybe.ofAllowingNull(v2.getValue()));
-            v.isValueSet = true;
+            v.setValue(resolveConflict(key, localValue, v2.asMaybe()));
+            v.setValueWasExplicitlySet(true);
         }
         return v;
     }
     /** only invoked if there is an ancestor value; custom strategies can 
overwrite */
-    protected <T> T resolveConflict(ConfigKey<T> key, Maybe<T> localValue, 
Maybe<T> ancestorValue) {
+    protected <T> Maybe<T> resolveConflict(ConfigKey<T> key, Maybe<T> 
localValue, Maybe<T> ancestorValue) {
         if 
(OVERWRITE.conflictResolutionStrategy.equals(conflictResolutionStrategy)) {
-            if (localValue.isPresent()) return localValue.get();
-            if (useLocalDefaultValue) return (key==null || 
!key.hasDefaultValue()) ? null : key.getDefaultValue();
-            return ancestorValue.orNull();
+            if (localValue.isPresent()) return localValue;
+            if (useLocalDefaultValue) return (key==null || 
!key.hasDefaultValue()) ? Maybe.<T>absent() : 
Maybe.ofAllowingNull(key.getDefaultValue());
+            return ancestorValue;
         }
         if 
(DEEP_MERGE.conflictResolutionStrategy.equals(conflictResolutionStrategy)) {
             localValue = localValue.isPresent() ? localValue : 
                 useLocalDefaultValue && key!=null && key.hasDefaultValue() ? 
Maybe.ofAllowingNull(key.getDefaultValue()) :
                 Maybe.<T>absent();
-            return deepMerge(localValue, ancestorValue).orNull();
+            @SuppressWarnings("unchecked")
+            Maybe<T> result = (Maybe<T>) deepMerge(localValue, ancestorValue);
+            return result;
         }
         throw new IllegalStateException("Unknown config conflict resolution 
strategy '"+conflictResolutionStrategy+"' evaluating "+key);
     }
-    private static class Result<T> implements ContainerAndValue<T> {
-        Object container = null;
-        T value = null;
-        boolean isValueSet = false;
-        @Override public Object getContainer() { return container; }
-        @Override public T getValue() { return value; }
-        @Override public boolean isValueSet() { return isValueSet; }
-    }
     private static <T> Maybe<? extends T> deepMerge(Maybe<? extends T> val1, 
Maybe<? extends T> val2) {
         if (val2.isAbsent() || val2.isNull()) {
             return val1;
@@ -147,53 +159,7 @@ public class BasicConfigInheritance implements 
ConfigInheritance {
         }
     }
 
-    public static class BasicContainerAndKeyValue<TContainer,TValue> 
implements ContainerAndKeyValue<TValue> {
-        private final TContainer container;
-        private final ConfigKey<TValue> key;
-        private final Function<TContainer,Maybe<TValue>> evaluationFunction;
-        private Maybe<TValue> resolved;
-        
-        public BasicContainerAndKeyValue(ConfigKey<TValue> key, TContainer 
container, Function<TContainer, Maybe<TValue>> evaluationFunction) {
-            this.key = key;
-            this.container = container;
-            this.evaluationFunction = evaluationFunction;
-        }
-
-        protected synchronized Maybe<TValue> resolve() {
-            if (resolved==null) { 
-                resolved = evaluationFunction.apply(getContainer());
-            }
-            return resolved;
-        }
-
-        @Override
-        public TContainer getContainer() {
-            return container;
-        }
-
-        @Override
-        public TValue getValue() {
-            if (resolve().isPresent()) return resolve().get();
-            return getDefaultValue();
-        }
-
-        @Override
-        public boolean isValueSet() {
-            return resolve().isPresent();
-        }
-
-        @Override
-        public ConfigKey<TValue> getKey() {
-            return key;
-        }
-
-        @Override
-        public TValue getDefaultValue() {
-            return key.getDefaultValue();
-        }
-    }
-    
-    public static class 
AncestorContainerAndKeyValueIterator<TContainer,TValue> implements 
Iterator<ContainerAndKeyValue<TValue>> {
+    public static class 
AncestorContainerAndKeyValueIterator<TContainer,TValue> implements 
Iterator<ConfigValueAtContainer<TContainer,TValue>> {
         private TContainer lastContainer;
         private final Function<TContainer, ConfigKey<TValue>> 
keyFindingFunction; 
         private final Function<TContainer, Maybe<TValue>> 
localEvaluationFunction; 
@@ -215,11 +181,11 @@ public class BasicConfigInheritance implements 
ConfigInheritance {
         }
         
         @Override
-        public ContainerAndKeyValue<TValue> next() {
+        public ConfigValueAtContainer<TContainer,TValue> next() {
             TContainer nextContainer = parentFunction.apply(lastContainer);
             if (nextContainer==null) throw new NoSuchElementException("Cannot 
search ancestors further than "+lastContainer);
             lastContainer = nextContainer;
-            return new 
BasicContainerAndKeyValue<TContainer,TValue>(keyFindingFunction.apply(lastContainer),
 lastContainer, localEvaluationFunction);
+            return new 
LazyContainerAndKeyValue<TContainer,TValue>(keyFindingFunction.apply(lastContainer),
 lastContainer, localEvaluationFunction);
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java 
b/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java
index 795da50..2743b80 100644
--- a/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java
+++ b/core/src/main/java/org/apache/brooklyn/core/config/ConfigKeys.java
@@ -24,11 +24,10 @@ import javax.annotation.Nonnull;
 
 import org.apache.brooklyn.config.ConfigInheritance;
 import org.apache.brooklyn.config.ConfigInheritance.ConfigInheritanceContext;
-import org.apache.brooklyn.config.ConfigInheritance.ContainerAndKeyValue;
-import org.apache.brooklyn.config.ConfigInheritance.ContainerAndValue;
 import org.apache.brooklyn.config.ConfigKey;
-import 
org.apache.brooklyn.core.config.BasicConfigInheritance.BasicContainerAndKeyValue;
+import org.apache.brooklyn.config.ConfigValueAtContainer;
 import 
org.apache.brooklyn.core.config.BasicConfigKey.BasicConfigKeyOverwriting;
+import org.apache.brooklyn.core.config.internal.LazyContainerAndKeyValue;
 import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
 import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
@@ -290,11 +289,15 @@ public class ConfigKeys {
 
     }
 
-    /** determine whether a key is reinherited, ie its value is exported to 
container's descendants  
-     * @deprecated since introduction in 0.10.0 In order to determine whether 
a key is inherited we might need to know whether
-     * it was explicitly defined as a key on a parent; callers should be 
refactored. */
-    @Deprecated
-    public static <T> boolean isReinherited(final ConfigKey<T> key, final 
ConfigInheritanceContext context) {
+    /** determine whether a key is reinheritable from the point in the given 
inheritance hierarchy where it is introduced;
+     * default is true, but some keys may define not being reinherited or may 
have that effective result
+     * <p>
+     * note that this does not mean a value should never be *inherited*; 
+     * callers should query with the key defined at a given point in a 
hierarchy,
+     * so if a key is not defined at some point in the hierarchy
+     * (eg not on a type in the type hierarchy, or not an an entity in the 
runtime management hierarchy)
+     * then null should be passed and values will be reinheritable */
+    public static <T> boolean isKeyReinheritable(final ConfigKey<T> key, final 
ConfigInheritanceContext context) {
         if (key==null) return true;
         ConfigInheritance inh = key.getInheritanceByContext(context);
         if (inh==null) return true;
@@ -303,18 +306,18 @@ public class ConfigKeys {
         }
         
         // evaluate by faking a parent who sets a value and seeing if it's 
reinherited
-        Iterable<? extends ContainerAndKeyValue<T>> ckvi = MutableList.of(
-            new BasicContainerAndKeyValue<Void,T>(key, null, new 
Function<Void,Maybe<T>>() {
+        Iterable<? extends ConfigValueAtContainer<Void,T>> ckvi = 
MutableList.of(
+            new LazyContainerAndKeyValue<Void,T>(key, null, new 
Function<Void,Maybe<T>>() {
                 @Override
                 public Maybe<T> apply(Void input) {
                     return Maybe.ofAllowingNull(null);
                 }
             }));
         
-        ContainerAndValue<T> combinedVal = 
BasicConfigInheritance.OVERWRITE.resolveInheriting(
+        ConfigValueAtContainer<Void,T> combinedVal = 
BasicConfigInheritance.OVERWRITE.resolveInheriting(
             key, Maybe.<T>absent(), null,
             ckvi.iterator(), InheritanceContext.TYPE_DEFINITION);
-        return combinedVal.isValueSet();
+        return combinedVal.isValueExplicitlySet();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java
 
b/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java
index 6593aed..6c31b97 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/config/internal/AbstractConfigMapImpl.java
@@ -79,12 +79,12 @@ public abstract class AbstractConfigMapImpl implements 
ConfigMap {
     }
     
     public <T> T getConfig(ConfigKey<T> key) {
-        return getConfigImpl(key);
+        return getConfigImpl(key).orNull();
     }
     
 
     public <T> T getConfig(HasConfigKey<T> key) {
-        return getConfigImpl(key.getConfigKey());
+        return getConfigImpl(key.getConfigKey()).orNull();
     }
     
     @Override
@@ -92,7 +92,7 @@ public abstract class AbstractConfigMapImpl implements 
ConfigMap {
         return getConfigRaw(key, false);
     }
 
-    protected abstract <T> T getConfigImpl(ConfigKey<T> key);
+    protected abstract <T> Maybe<T> getConfigImpl(ConfigKey<T> key);
     
     protected abstract ExecutionContext getExecutionContext(BrooklynObject bo);
     protected abstract void postLocalEvaluate(ConfigKey<?> key, BrooklynObject 
bo, Maybe<?> rawValue, Maybe<?> resolvedValue);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/core/src/main/java/org/apache/brooklyn/core/config/internal/AncestorContainerAndKeyValueIterator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/config/internal/AncestorContainerAndKeyValueIterator.java
 
b/core/src/main/java/org/apache/brooklyn/core/config/internal/AncestorContainerAndKeyValueIterator.java
new file mode 100644
index 0000000..62fb970
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/config/internal/AncestorContainerAndKeyValueIterator.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.config.internal;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.ConfigValueAtContainer;
+import org.apache.brooklyn.util.guava.Maybe;
+
+import com.google.common.base.Function;
+
+public class AncestorContainerAndKeyValueIterator<TContainer,TValue> 
implements Iterator<ConfigValueAtContainer<TContainer,TValue>> {
+    private TContainer lastContainer;
+    private final Function<TContainer, ConfigKey<TValue>> keyFindingFunction; 
+    private final Function<TContainer, Maybe<TValue>> localEvaluationFunction; 
+    private final Function<TContainer, TContainer> parentFunction;
+    
+    public AncestorContainerAndKeyValueIterator(TContainer childContainer, 
+            Function<TContainer, ConfigKey<TValue>> keyFindingFunction, 
+            Function<TContainer, Maybe<TValue>> localEvaluationFunction, 
+            Function<TContainer, TContainer> parentFunction) {
+        this.lastContainer = childContainer;
+        this.keyFindingFunction = keyFindingFunction;
+        this.localEvaluationFunction = localEvaluationFunction;
+        this.parentFunction = parentFunction;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return parentFunction.apply(lastContainer)!=null;
+    }
+    
+    @Override
+    public ConfigValueAtContainer<TContainer,TValue> next() {
+        TContainer nextContainer = parentFunction.apply(lastContainer);
+        if (nextContainer==null) throw new NoSuchElementException("Cannot 
search ancestors further than "+lastContainer);
+        lastContainer = nextContainer;
+        return new 
LazyContainerAndKeyValue<TContainer,TValue>(keyFindingFunction.apply(lastContainer),
 lastContainer, localEvaluationFunction);
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("This iterator does not 
support removal");
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/core/src/main/java/org/apache/brooklyn/core/config/internal/BasicConfigValueAtContainer.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/config/internal/BasicConfigValueAtContainer.java
 
b/core/src/main/java/org/apache/brooklyn/core/config/internal/BasicConfigValueAtContainer.java
new file mode 100644
index 0000000..79041d4
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/config/internal/BasicConfigValueAtContainer.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.config.internal;
+
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.ConfigValueAtContainer;
+import org.apache.brooklyn.util.guava.Maybe;
+
+public class BasicConfigValueAtContainer<TContainer,TValue> implements 
ConfigValueAtContainer<TContainer,TValue> {
+    
+    TContainer container = null;
+    Maybe<TValue> value = Maybe.absent();
+    boolean valueWasExplicitlySet;
+    ConfigKey<TValue> key = null;
+    
+    @Override public TContainer getContainer() { return container; }
+    @Override public TValue get() { return value.orNull(); }
+    @Override public Maybe<TValue> asMaybe() { return value; }
+    @Override public boolean isValueExplicitlySet() { return 
valueWasExplicitlySet; }
+    @Override public ConfigKey<TValue> getKey() { return key; }
+    @Override public TValue getDefaultValue() { return 
getDefaultValueMaybe().orNull(); }
+    
+    public void setContainer(TContainer container) {
+        this.container = container;
+    }
+    public void setValue(Maybe<TValue> value) {
+        this.value = value;
+    }
+    public void setValueWasExplicitlySet(boolean valueWasExplicitlySet) {
+        this.valueWasExplicitlySet = valueWasExplicitlySet;
+    }
+    public void setKey(ConfigKey<TValue> key) {
+        this.key = key;
+    }
+    
+    public Maybe<TValue> getDefaultValueMaybe() { return key!=null && 
key.hasDefaultValue() ? Maybe.ofAllowingNull(key.getDefaultValue()) : 
Maybe.<TValue>absent(); }
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/core/src/main/java/org/apache/brooklyn/core/config/internal/LazyContainerAndKeyValue.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/config/internal/LazyContainerAndKeyValue.java
 
b/core/src/main/java/org/apache/brooklyn/core/config/internal/LazyContainerAndKeyValue.java
new file mode 100644
index 0000000..df11735
--- /dev/null
+++ 
b/core/src/main/java/org/apache/brooklyn/core/config/internal/LazyContainerAndKeyValue.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.config.internal;
+
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.ConfigValueAtContainer;
+import org.apache.brooklyn.util.guava.Maybe;
+
+import com.google.common.base.Function;
+
+public class LazyContainerAndKeyValue<TContainer,TValue> implements 
ConfigValueAtContainer<TContainer,TValue> {
+    
+    private final TContainer container;
+    private final ConfigKey<TValue> key;
+    private final Function<TContainer,Maybe<TValue>> evaluationFunction;
+    private Maybe<TValue> resolved;
+    
+    public LazyContainerAndKeyValue(ConfigKey<TValue> key, TContainer 
container, Function<TContainer, Maybe<TValue>> evaluationFunction) {
+        this.key = key;
+        this.container = container;
+        this.evaluationFunction = evaluationFunction;
+    }
+
+    protected synchronized Maybe<TValue> resolve() {
+        if (resolved==null) { 
+            resolved = evaluationFunction.apply(getContainer());
+        }
+        return resolved;
+    }
+
+    @Override
+    public TContainer getContainer() {
+        return container;
+    }
+
+    @Override
+    public TValue get() {
+        if (resolve().isPresent()) return resolve().get();
+        return getDefaultValue();
+    }
+    
+    @Override
+    public Maybe<TValue> asMaybe() {
+        if (resolve().isPresent()) return resolve();
+        return getDefaultValueMaybe();
+    }
+
+    @Override
+    public boolean isValueExplicitlySet() {
+        return resolve().isPresent();
+    }
+
+    @Override
+    public ConfigKey<TValue> getKey() {
+        return key;
+    }
+
+    @Override
+    public TValue getDefaultValue() {
+        return getDefaultValueMaybe().orNull();
+    }
+    
+    public Maybe<TValue> getDefaultValueMaybe() {
+        if (key==null || !key.hasDefaultValue()) return Maybe.absent();
+        return Maybe.of(key.getDefaultValue());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/core/src/main/java/org/apache/brooklyn/core/entity/internal/EntityConfigMap.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/entity/internal/EntityConfigMap.java
 
b/core/src/main/java/org/apache/brooklyn/core/entity/internal/EntityConfigMap.java
index c1314b3..15f8ffa 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/entity/internal/EntityConfigMap.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/entity/internal/EntityConfigMap.java
@@ -27,8 +27,8 @@ import org.apache.brooklyn.api.mgmt.ExecutionContext;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.config.ConfigInheritance;
-import org.apache.brooklyn.config.ConfigInheritance.ContainerAndValue;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.ConfigValueAtContainer;
 import org.apache.brooklyn.core.config.BasicConfigInheritance;
 import 
org.apache.brooklyn.core.config.BasicConfigInheritance.AncestorContainerAndKeyValueIterator;
 import org.apache.brooklyn.core.config.ConfigKeys.InheritanceContext;
@@ -101,7 +101,7 @@ public class EntityConfigMap extends AbstractConfigMapImpl {
     }
     
     @Override
-    protected <T> T getConfigImpl(ConfigKey<T> key) {
+    protected <T> Maybe<T> getConfigImpl(ConfigKey<T> key) {
         Function<Entity, ConfigKey<T>> keyFn = 
EntityFunctions.configKeyFinder(key, null);
         
         // In case this entity class has overridden the given key (e.g. to set 
default), then retrieve this entity's key
@@ -116,15 +116,15 @@ public class EntityConfigMap extends 
AbstractConfigMapImpl {
             AncestorContainerAndKeyValueIterator<Entity, T> ckvi = new 
AncestorContainerAndKeyValueIterator<Entity,T>(
                 getEntity(), keyFn, evalFn, EntityFunctions.parent());
             
-            ContainerAndValue<T> result = 
getDefaultRuntimeInheritance().resolveInheriting(ownKey,
+            ConfigValueAtContainer<Entity,T> result = 
getDefaultRuntimeInheritance().resolveInheriting(ownKey,
                 ownExplicitValue, getEntity(),
                 ckvi, InheritanceContext.RUNTIME_MANAGEMENT);
         
-            if (result.getValue()!=null) return result.getValue();
+            return result.asMaybe();
         } else {
             LOG.warn("Config key {} of {} is not a ConfigKeySelfExtracting; 
cannot retrieve value; returning default", ownKey, getBrooklynObject());
+            return Maybe.absent();
         }
-        return null;
     }
 
     private ConfigInheritance getDefaultRuntimeInheritance() {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationConfigMap.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationConfigMap.java
 
b/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationConfigMap.java
index 4a854f6..e820f0d 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationConfigMap.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/location/internal/LocationConfigMap.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.api.mgmt.ExecutionContext;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.config.ConfigInheritance;
-import org.apache.brooklyn.config.ConfigInheritance.ContainerAndValue;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.config.ConfigMap;
+import org.apache.brooklyn.config.ConfigValueAtContainer;
 import org.apache.brooklyn.core.config.BasicConfigInheritance;
 import 
org.apache.brooklyn.core.config.BasicConfigInheritance.AncestorContainerAndKeyValueIterator;
 import org.apache.brooklyn.core.config.ConfigKeys.InheritanceContext;
@@ -66,7 +66,7 @@ public class LocationConfigMap extends AbstractConfigMapImpl {
     }
     
     @Override
-    protected <T> T getConfigImpl(final ConfigKey<T> key) {
+    protected <T> Maybe<T> getConfigImpl(final ConfigKey<T> key) {
         Function<Location, ConfigKey<T>> keyFn = new Function<Location, 
ConfigKey<T>>() {
             @SuppressWarnings("unchecked")
             @Override
@@ -96,15 +96,15 @@ public class LocationConfigMap extends 
AbstractConfigMapImpl {
                     }
                 });
             
-            ContainerAndValue<T> result = 
getDefaultRuntimeInheritance().resolveInheriting(ownKey,
+            ConfigValueAtContainer<Location,T> result = 
getDefaultRuntimeInheritance().resolveInheriting(ownKey,
                 ownExplicitValue, getLocation(),
                 ckvi, InheritanceContext.RUNTIME_MANAGEMENT);
         
-            if (result.getValue()!=null) return result.getValue();
+            return result.asMaybe();
         } else {
             log.warn("Config key {} of {} is not a ConfigKeySelfExtracting; 
cannot retrieve value; returning default", ownKey, getBrooklynObject());
+            return Maybe.absent();
         }
-        return null;
     }
     
     private ConfigInheritance getDefaultRuntimeInheritance() {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/core/src/main/java/org/apache/brooklyn/core/objs/AdjunctConfigMap.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/objs/AdjunctConfigMap.java 
b/core/src/main/java/org/apache/brooklyn/core/objs/AdjunctConfigMap.java
index f3ecdea..6494600 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/AdjunctConfigMap.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/AdjunctConfigMap.java
@@ -84,7 +84,7 @@ public class AdjunctConfigMap extends AbstractConfigMapImpl {
         return (entity != null) ? 
((EntityInternal)entity).getExecutionContext() : null;
     }
     
-    protected <T> T getConfigImpl(ConfigKey<T> key) {
+    protected <T> Maybe<T> getConfigImpl(ConfigKey<T> key) {
         // tasks won't resolve if we aren't yet connected to an entity
         
         // no need for inheritance, so much simpler than other impls
@@ -94,12 +94,12 @@ public class AdjunctConfigMap extends AbstractConfigMapImpl 
{
         
         if (ownKey instanceof ConfigKeySelfExtracting) {
             if (((ConfigKeySelfExtracting<T>)ownKey).isSet(ownConfig)) {
-                return 
((ConfigKeySelfExtracting<T>)ownKey).extractValue(ownConfig, 
getExecutionContext(getAdjunct()));
+                return Maybe.ofAllowingNull( 
((ConfigKeySelfExtracting<T>)ownKey).extractValue(ownConfig, 
getExecutionContext(getAdjunct())) );
             }
         } else {
             LOG.warn("Config key {} of {} is not a ConfigKeySelfExtracting; 
cannot retrieve value; returning default", ownKey, this);
         }
-        return TypeCoercions.coerce(ownKey.getDefaultValue(), 
key.getTypeToken());
+        return Maybe.ofAllowingNull( 
TypeCoercions.coerce(ownKey.getDefaultValue(), key.getTypeToken()) );
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/core/src/test/java/org/apache/brooklyn/core/entity/ConfigEntityInheritanceTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/entity/ConfigEntityInheritanceTest.java
 
b/core/src/test/java/org/apache/brooklyn/core/entity/ConfigEntityInheritanceTest.java
index d0c8aaf..d6a2f9f 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/entity/ConfigEntityInheritanceTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/entity/ConfigEntityInheritanceTest.java
@@ -147,25 +147,25 @@ public class ConfigEntityInheritanceTest extends 
BrooklynAppUnitTestSupport {
 
     @Test
     public void testConfigKeysInheritance() throws Exception {
-        app.config().set(MyEntityWithPartiallyHeritableConfig.HERITABLE, 
"heritable");
+        
app.config().set(MyEntityWithPartiallyHeritableConfig.HERITABLE_BY_DEFAULT, 
"heritable");
         
app.config().set(MyEntityWithPartiallyHeritableConfig.ALWAYS_HERITABLE, 
"always_heritable");
-        app.config().set(MyEntityWithPartiallyHeritableConfig.UNINHERITABLE, 
"uninheritable");
+        app.config().set(MyEntityWithPartiallyHeritableConfig.NEVER_INHERIT, 
"uninheritable");
         
app.config().set(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE, 
"maybe");
         Entity child = 
app.addChild(EntitySpec.create(MyEntityWithPartiallyHeritableConfig.class));
         
-        
Assert.assertNotNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.HERITABLE));
+        
Assert.assertNotNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.HERITABLE_BY_DEFAULT));
         
Assert.assertNotNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.ALWAYS_HERITABLE));
-        
Assert.assertNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.UNINHERITABLE),
 null);
+        
Assert.assertNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.NEVER_INHERIT));
         
         // it's reinheritable unless explicitly declared
         
Assert.assertNotNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE));
         
app.getMutableEntityType().addConfigKey(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE);
-        
Assert.assertNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE),
 null);
+        
Assert.assertNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE));
     }
     
     public static class MyEntityWithPartiallyHeritableConfig extends 
AbstractEntity {
-        public static final ConfigKey<String> HERITABLE = 
ConfigKeys.builder(String.class, "herit.default").build();
-        public static final ConfigKey<String> UNINHERITABLE = 
ConfigKeys.builder(String.class, 
"herit.never").runtimeInheritance(BasicConfigInheritance.NEVER_INHERITED).build();
+        public static final ConfigKey<String> HERITABLE_BY_DEFAULT = 
ConfigKeys.builder(String.class, "herit.default").build();
+        public static final ConfigKey<String> NEVER_INHERIT = 
ConfigKeys.builder(String.class, 
"herit.never").runtimeInheritance(BasicConfigInheritance.NEVER_INHERITED).build();
         public static final ConfigKey<String> NOT_REINHERITABLE = 
ConfigKeys.builder(String.class, 
"herit.not_re").runtimeInheritance(BasicConfigInheritance.NOT_REINHERITED).build();
         // i find a strange joy in words where the prefix "in-" does not mean 
not, like inflammable 
         public static final ConfigKey<String> ALWAYS_HERITABLE = 
ConfigKeys.builder(String.class, 
"herit.always").runtimeInheritance(BasicConfigInheritance.OVERWRITE).build();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java 
b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java
index b9b567c..e415a1c 100644
--- 
a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritance.java
@@ -29,7 +29,6 @@ import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.text.Strings;
 
 import com.google.common.annotations.Beta;
-import com.google.common.base.Supplier;
 
 @SuppressWarnings("serial")
 public interface ConfigInheritance extends Serializable {
@@ -55,32 +54,6 @@ public interface ConfigInheritance extends Serializable {
     @Deprecated
     InheritanceMode isInherited(ConfigKey<?> key, Object from, Object to);
 
-//    // TODO
-//    interface ConfigKeyValueInContext<TContainer,TValue> extends 
Supplier<TValue> {
-//        TValue get();
-//        Maybe<TValue> asMaybe();
-//        
-//        TContainer getContainer();
-//        
-//        /** if false, the contents of {@link #getValue()} will have come 
from the default */
-//        boolean isValueExplicitlySet();
-//        
-//        ConfigKey<TValue> getKey();
-//        TValue getDefaultValue();
-//    }
-
-    interface ContainerAndValue<T> {
-        Object getContainer();
-        T getValue();
-        /** if false, the contents of {@link #getValue()} will have come from 
the default */
-        boolean isValueSet();
-    }
-    
-    interface ContainerAndKeyValue<T> extends ContainerAndValue<T> {
-        ConfigKey<T> getKey();
-        T getDefaultValue();
-    }
-    
     /** 
      * given a key and local value, together with an optional record of 
ancestor containers (eg an entity) and associated data,
      * this finds the value for a config key <b>applying the appropriate 
inheritance strategies</b>.
@@ -108,11 +81,11 @@ public interface ConfigInheritance extends Serializable {
      * and whose second entry gives the container, key, and potential value to 
be exported.
      * if null is returned the caller knows nothing is to be exported to 
children.
      */
-    <T> ContainerAndValue<T> resolveInheriting(
-        ConfigKey<T> key,
-        @Nullable Maybe<T> localValue,
-        @Nullable Object container,
-        Iterator<? extends ContainerAndKeyValue<T>> ancestorContainerKeyValues,
+    <TContainer,TValue> ConfigValueAtContainer<TContainer,TValue> 
resolveInheriting(
+        ConfigKey<TValue> key,
+        @Nullable Maybe<TValue> localValue,
+        @Nullable TContainer container,
+        Iterator<? extends ConfigValueAtContainer<TContainer,TValue>> 
ancestorContainerKeyValues,
         ConfigInheritanceContext context);
     
     /** @deprecated since 0.10.0 see implementations of this interface */ 
@Deprecated
@@ -132,32 +105,36 @@ public interface ConfigInheritance extends Serializable {
             }
         }
         private abstract static class LegacyAbstractConversion implements 
ConfigInheritance {
-            private static class Result<T> implements ContainerAndValue<T> {
-                Object container = null;
-                T value = null;
+            private static class Result<TContainer,TValue> implements 
ConfigValueAtContainer<TContainer,TValue> {
+                TContainer container = null;
+                Maybe<TValue> value = Maybe.absent();
                 boolean isValueSet = false;
-                @Override public Object getContainer() { return container; }
-                @Override public T getValue() { return value; }
-                @Override public boolean isValueSet() { return isValueSet; }
+                ConfigKey<TValue> key = null;
+                @Override public TContainer getContainer() { return container; 
}
+                @Override public TValue get() { return value.orNull(); }
+                @Override public Maybe<TValue> asMaybe() { return value; }
+                @Override public boolean isValueExplicitlySet() { return 
isValueSet; }
+                @Override public ConfigKey<TValue> getKey() { return key; }
+                @Override public TValue getDefaultValue() { return key==null ? 
null : key.getDefaultValue(); }
             }
 
             // close copy of method in BasicConfigInheritance for this legacy 
compatibility evaluation
             @Override
-            public <T> ContainerAndValue<T> resolveInheriting(
-                    @Nullable ConfigKey<T> key, Maybe<T> localValue, Object 
container,
-                    Iterator<? extends ContainerAndKeyValue<T>> 
ancestorContainerKeyValues, ConfigInheritanceContext context) {
+            public <TContainer,TValue> 
ConfigValueAtContainer<TContainer,TValue> resolveInheriting(
+                    @Nullable ConfigKey<TValue> key, Maybe<TValue> localValue, 
TContainer container,
+                    Iterator<? extends 
ConfigValueAtContainer<TContainer,TValue>> ancestorContainerKeyValues, 
ConfigInheritanceContext context) {
                 ConfigInheritance inh = key==null ? null : 
key.getInheritanceByContext(context);
                 if (inh==null) inh = this;
                 if (inh!=this) return inh.resolveInheriting(key, localValue, 
container, ancestorContainerKeyValues, context);
                 
-                ContainerAndValue<T> v2 = null;
+                ConfigValueAtContainer<TContainer,TValue> v2 = null;
                 if (getMode()==InheritanceMode.IF_NO_EXPLICIT_VALUE && 
localValue.isPresent()) {
                     // don't inherit
                 } else if (ancestorContainerKeyValues==null || 
!ancestorContainerKeyValues.hasNext()) {
                     // nothing to inherit
                 } else {
                     // check whether parent allows us to get inherited value
-                    ContainerAndKeyValue<T> c = 
ancestorContainerKeyValues.next();
+                    ConfigValueAtContainer<TContainer,TValue> c = 
ancestorContainerKeyValues.next();
                     ConfigInheritance inh2 = c.getKey()==null ? null : 
c.getKey().getInheritanceByContext(context);
                     if (inh2==null) inh2 = this;
                     if (getMode()==InheritanceMode.NONE) {
@@ -165,19 +142,20 @@ public interface ConfigInheritance extends Serializable {
                     } else {
                         // get inherited value
                         v2 = inh2.resolveInheriting(c.getKey(), 
-                            c.isValueSet() ? Maybe.of(c.getValue()) : 
Maybe.<T>absent(), c.getContainer(), 
+                            c.isValueExplicitlySet() ? c.asMaybe() : 
Maybe.<TValue>absent(), c.getContainer(), 
                                 ancestorContainerKeyValues, context);
                     }
                 }
 
-                if (v2!=null && v2.isValueSet() && !localValue.isPresent()) 
return v2;
-                Result<T> v = new Result<T>();
+                if (v2!=null && v2.isValueExplicitlySet() && 
!localValue.isPresent()) return v2;
+                Result<TContainer,TValue> v = new Result<TContainer,TValue>();
                 v.container = container;
-                if (v2==null || !v2.isValueSet()) {
+                if (v2==null || !v2.isValueExplicitlySet()) {
                     v.isValueSet = localValue.isPresent();
-                    v.value = v.isValueSet() ? localValue.get() : key!=null ? 
key.getDefaultValue() : null; 
+                    v.value = v.isValueExplicitlySet() ? localValue : 
+                        key!=null && key.hasDefaultValue() ? 
Maybe.of(key.getDefaultValue()) : Maybe.<TValue>absent(); 
                 } else {
-                    v.value = resolveConflict(key, localValue, 
Maybe.ofAllowingNull(v2.getValue()));
+                    v.value = Maybe.of(resolveConflict(key, localValue, 
v2.asMaybe()));
                     v.isValueSet = true;
                 }
                 return v;
@@ -209,78 +187,11 @@ public interface ConfigInheritance extends Serializable {
                     return val1;
                 }
             }
-//            @Override
-//            public <T> ContainerAndValue<T> resolveInheriting(ConfigKey<T> 
key, Maybe<T> localValue, Object container,
-//                    Iterator<ContainerAndKeyValue<T>> 
ancestorContainerKeyValues, ConfigInheritanceContext context) {
-//                if (ancestorContainerKeyValues.hasNext()) {
-//                    
-//                    ContainerAndKeyValue<T> c = 
ancestorContainerKeyValues.next();
-//                    if (c==null) return 
resolveInheriting(ancestorContainerKeyValues, context);
-//                    
-//                    ConfigKey<T> key = c.getKey();
-//                    ConfigInheritance ci = null;
-//                    if (key!=null) ci = key.getInheritanceByContext(context);
-//                    if (ci==null) ci = this;
-//                    
-//                    if (getMode()==InheritanceMode.NONE) {
-//                        // don't inherit, fall through to below
-//                    } else if (!c.isValueSet()) {
-//                        // no value here, try to inherit
-//                        ContainerAndValue<T> ri = 
ci.resolveInheriting(ancestorContainerKeyValues, context);
-//                        if (ri.isValueSet()) {
-//                            // value found, return it
-//                            return ri;
-//                        }
-//                        // else no inherited, fall through to below
-//                    } else {
-//                        if (getMode()==InheritanceMode.IF_NO_EXPLICIT_VALUE) 
{
-//                            // don't inherit, fall through to below
-//                        } else {
-//                            // merging
-//                            Maybe<?> mr = deepMerge(asMaybe(c), 
-//                                
asMaybe(ci.resolveInheriting(ancestorContainerKeyValues, context)));
-//                            if (mr.isPresent()) {
-//                                Result<T> r = new Result<T>();
-//                                r.container = c.getContainer();
-//                                r.isValueSet = true;
-//                                @SuppressWarnings("unchecked")
-//                                T vt = (T) mr.get();
-//                                r.value = vt;
-//                                return r;
-//                            }
-//                        }
-//                    }
-//                    Result<T> r = new Result<T>();
-//                    r.container = c.getContainer();
-//                    r.isValueSet = c.isValueSet();
-//                    r.value = r.isValueSet ? c.getValue() : 
c.getDefaultValue();
-//                    return r;
-//                }
-//                return new Result<T>();
-//            }
             @Override
             public InheritanceMode isInherited(ConfigKey<?> key, Object from, 
Object to) {
                 return getMode();
             }
             protected abstract InheritanceMode getMode();
-            private static <T> Maybe<T> asMaybe(ContainerAndValue<T> cv) {
-                if (cv.isValueSet()) return Maybe.of(cv.getValue());
-                return Maybe.absent();
-            }
-//            private static <T> Maybe<?> deepMerge(Maybe<? extends T> val1, 
Maybe<? extends T> val2) {
-//                if (val2.isAbsent() || val2.isNull()) {
-//                    return val1;
-//                } else if (val1.isAbsent()) {
-//                    return val2;
-//                } else if (val1.isNull()) {
-//                    return val1; // an explicit null means an override; 
don't merge
-//                } else if (val1.get() instanceof Map && val2.get() 
instanceof Map) {
-//                    return 
Maybe.of(CollectionMerger.builder().build().merge((Map<?,?>)val1.get(), 
(Map<?,?>)val2.get()));
-//                } else {
-//                    // cannot merge; just return val1
-//                    return val1;
-//                }
-//            }
         }
         private static class Always extends LegacyAbstractConversion {
             @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8d44d5a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java
 
b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java
new file mode 100644
index 0000000..38e1259
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.config;
+
+import org.apache.brooklyn.util.guava.Maybe;
+
+import com.google.common.base.Supplier;
+
+public interface ConfigValueAtContainer<TContainer,TValue> extends 
Supplier<TValue> {
+    
+    /** Returns the value, or null */
+    TValue get();
+    /** Absent if no value can be found, typically including no default value. 
*/ 
+    Maybe<TValue> asMaybe();
+    /** If false, the contents of {@link #get()} will have come from {@link 
#getDefaultValue()}. */
+    boolean isValueExplicitlySet();
+    
+    /** The container where the value was found (possibly an ancestor of the 
queried object) */
+    TContainer getContainer();
+    
+    ConfigKey<TValue> getKey();
+    TValue getDefaultValue();
+    
+}

Reply via email to