You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/09/22 21:09:36 UTC
[04/22] brooklyn-server git commit: using new config inheritance
evaluation, inserted in several places
using new config inheritance evaluation, inserted in several places
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/94179834
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/94179834
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/94179834
Branch: refs/heads/master
Commit: 94179834619d0890dde40b7169c788317457215c
Parents: 2970656
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Sep 19 17:59:56 2016 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Sep 20 08:48:30 2016 +0100
----------------------------------------------------------------------
.../BrooklynComponentTemplateResolver.java | 95 +++++----
.../core/config/BasicConfigInheritance.java | 144 +++++++++++++-
.../apache/brooklyn/core/config/ConfigKeys.java | 26 ++-
.../core/entity/internal/EntityConfigMap.java | 79 +++-----
.../brooklyn/config/ConfigInheritance.java | 191 +++++++++++++------
5 files changed, 359 insertions(+), 176 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/94179834/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 0cbc641..7f87ca5 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,17 +46,19 @@ 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.InheritanceMode;
+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.catalog.internal.CatalogUtils;
+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.mgmt.BrooklynTags;
import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
import org.apache.brooklyn.core.resolve.entity.EntitySpecResolver;
-import org.apache.brooklyn.util.collections.CollectionMerger;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.collections.MutableSet;
@@ -256,7 +258,7 @@ public class BrooklynComponentTemplateResolver {
}
@SuppressWarnings({ "unchecked", "rawtypes" })
- private void configureEntityConfig(EntitySpec<?> spec, Set<String> encounteredRegisteredTypeIds) {
+ private void configureEntityConfig(final EntitySpec<?> spec, Set<String> encounteredRegisteredTypeIds) {
// first take *recognised* flags and config keys from the top-level, and put them in the bag (of brooklyn.config)
// attrs will contain only brooklyn.xxx properties when coming from BrooklynEntityMatcher.
// Any top-level flags will go into "brooklyn.flags". When resolving a spec from $brooklyn:entitySpec
@@ -288,31 +290,55 @@ public class BrooklynComponentTemplateResolver {
Set<String> keyNamesUsed = new LinkedHashSet<String>();
for (FlagConfigKeyAndValueRecord r: records) {
if (r.getFlagMaybeValue().isPresent()) {
- String flag = r.getFlagName();
- Object ownVal = new SpecialFlagsTransformer(loader, encounteredRegisteredTypeIds).apply(r.getFlagMaybeValue().get());
- Maybe<?> superVal = spec.getFlags().containsKey(flag) ? Maybe.of(spec.getFlags().get(flag)) : Maybe.absent();
- Object combinedVal = combineValues(entityConfigKeys.get(flag), spec, Maybe.of(ownVal), superVal).get();
- spec.configure(flag, combinedVal);
+ final String flag = r.getFlagName();
+ final ConfigKey<Object> key = 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>>() {
+ @Override
+ public Maybe<Object> apply(Void input) {
+ return spec.getFlags().containsKey(flag) ? Maybe.of((Object)spec.getFlags().get(flag)) : Maybe.absent();
+ }
+ }));
+
+ ContainerAndValue<Object> combinedVal = getDefaultConfigInheritance().resolveInheriting(
+ key, Maybe.ofAllowingNull(ownValueF), null,
+ ckvi.iterator(), InheritanceContext.TYPE_DEFINITION);
+
+ spec.configure(flag, combinedVal.getValue());
keyNamesUsed.add(flag);
}
+
if (r.getConfigKeyMaybeValue().isPresent()) {
- ConfigKey<Object> key = (ConfigKey<Object>) r.getConfigKey();
- Object ownVal = new SpecialFlagsTransformer(loader, encounteredRegisteredTypeIds).apply(r.getConfigKeyMaybeValue().get());
- Maybe<?> superVal = spec.getConfig().containsKey(key) ? Maybe.of(spec.getConfig().get(key)) : Maybe.absent();
- Object combinedVal = combineValues(entityConfigKeys.get(key.getName()), spec, Maybe.of(ownVal), superVal).get();
- spec.configure(key, combinedVal);
+ 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>>() {
+ @Override
+ public Maybe<Object> apply(Void input) {
+ return spec.getConfig().containsKey(key) ? Maybe.of(spec.getConfig().get(key)) : Maybe.absent();
+ }
+ }));
+
+ ContainerAndValue<Object> combinedVal = getDefaultConfigInheritance().resolveInheriting(
+ key, Maybe.ofAllowingNull(ownValueF), null,
+ ckvi.iterator(), InheritanceContext.TYPE_DEFINITION);
+
+ spec.configure(key, combinedVal.getValue());
keyNamesUsed.add(key.getName());
}
}
+
+ // TODO clean up above
- // For anything that should not be inherited, clear if from the spec
+ // For anything that should not be inherited, clear it from the spec (if not set above)
for (Map.Entry<String, ConfigKey<?>> entry : entityConfigKeys.entrySet()) {
if (keyNamesUsed.contains(entry.getKey())) {
continue;
}
ConfigKey<?> key = entry.getValue();
- InheritanceMode mode = getInheritanceMode(key, spec);
- if (mode == InheritanceMode.NONE) {
+ if (!ConfigKeys.isRehinherited(key, InheritanceContext.TYPE_DEFINITION)) {
spec.removeConfig(key);
spec.removeFlag(key.getName());
}
@@ -331,41 +357,8 @@ public class BrooklynComponentTemplateResolver {
}
}
- // TODO Duplicates some logic in EntityConfigMap.getConfig()
- private Maybe<?> combineValues(ConfigKey<?> key, EntitySpec<?> spec, Maybe<?> ownVal, Maybe<?> superVal) {
- InheritanceMode mode = getInheritanceMode(key, spec);
- switch (mode) {
- case IF_NO_EXPLICIT_VALUE:
- return ownVal.isPresent() ? ownVal : superVal;
- case DEEP_MERGE:
- return deepMerge(ownVal, superVal, key);
- case NONE:
- return ownVal;
- default:
- throw new IllegalStateException("Unsupported type-inheritance mode for "+key.getName()+": "+mode);
- }
- }
-
- private InheritanceMode getInheritanceMode(ConfigKey<?> key, EntitySpec<?> spec) {
- ConfigInheritance inheritance = (key != null && key.getTypeInheritance() != null) ? key.getTypeInheritance() : ConfigInheritance.ALWAYS;
- return inheritance.isInherited(key, spec, attrs);
- }
-
- // TODO Duplicate of EntityConfigMap.deepMerge
- private <T> Maybe<?> deepMerge(Maybe<? extends T> val1, Maybe<? extends T> val2, ConfigKey<?> keyForLogging) {
- 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
- log.debug("Cannot merge values for "+keyForLogging.getName()+", because values are not maps: "+val1.get().getClass()+", and "+val2.get().getClass());
- return val1;
- }
+ protected ConfigInheritance getDefaultConfigInheritance() {
+ return ConfigInheritance.ALWAYS;
}
/**
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/94179834/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 a238809..86fee4d 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
@@ -19,9 +19,16 @@
package org.apache.brooklyn.core.config;
import java.util.Iterator;
+import java.util.Map;
+
+import javax.annotation.Nullable;
import org.apache.brooklyn.config.ConfigInheritance;
import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.util.collections.CollectionMerger;
+import org.apache.brooklyn.util.guava.Maybe;
+
+import com.google.common.base.Function;
public class BasicConfigInheritance implements ConfigInheritance {
@@ -33,11 +40,13 @@ public class BasicConfigInheritance implements ConfigInheritance {
public static BasicConfigInheritance OVERWRITE = new BasicConfigInheritance(true,"overwrite",false);
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
+ // reinheritable? true/false; if false, children/descendants/inheritors will never see it; default true
protected final boolean isReinherited;
-// conflict-resolution-strategy? overwrite or deep_merge or null; default null meaning caller supplies
+ // conflict-resolution-strategy? overwrite or deep_merge or null; default null meaning caller supplies
+ // (overriding resolveConflict)
protected final String conflictResolutionStrategy;
-// use-local-default-value? true/false; if true, overwrite above means "always ignore"; default false
+ // use-local-default-value? true/false; if true, overwrite above means "always ignore (even if null)"; default false
+ // whereas merge means "use local default (if non-null)"
protected final boolean useLocalDefaultValue;
protected BasicConfigInheritance(boolean isReinherited, String conflictResolutionStrategy, boolean useLocalDefaultValue) {
@@ -55,12 +64,131 @@ public class BasicConfigInheritance implements ConfigInheritance {
@Override
public <T> ContainerAndValue<T> resolveInheriting(
- Iterator<ContainerAndKeyValue<T>> containerAndDataThroughAncestors,
- ConfigInheritanceContext context) {
-// XXX;
- return null;
+ @Nullable ConfigKey<T> key, Maybe<T> localValue, Object container,
+ Iterator<? extends ContainerAndKeyValue<T>> 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()) {
+ // 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();
+ ConfigInheritance inh2 = c.getKey()==null ? null : c.getKey().getInheritanceByContext(context);
+ if (inh2==null) inh2 = this;
+ if (!this.isReinherited) {
+ // can't inherit
+ } else {
+ // get inherited value
+ v2 = inh2.resolveInheriting(c.getKey(),
+ c.isValueSet() ? Maybe.of(c.getValue()) : Maybe.<T>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.getDefaultValue();
+ } else {
+ v.value = resolveConflict(key, localValue, Maybe.ofAllowingNull(v2.getValue()));
+ v.isValueSet = 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) {
+ 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 (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();
+ }
+ 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;
+ } 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) {
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ Maybe<T> result = (Maybe)Maybe.of(CollectionMerger.builder().build().merge((Map<?,?>)val1.get(), (Map<?,?>)val2.get()));
+ return result;
+ } else {
+ // cannot merge; just return val1
+ return val1;
+ }
}
-}
+ 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();
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/94179834/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 21247c0..a02a2ce 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
@@ -22,20 +22,27 @@ import java.util.Map;
import javax.annotation.Nonnull;
-import org.apache.brooklyn.config.ConfigKey;
+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.core.config.BasicConfigKey.BasicConfigKeyOverwriting;
import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey;
import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
import org.apache.brooklyn.core.sensor.TemplatedStringAttributeSensorAndConfigKey;
+import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.text.Strings;
import org.apache.brooklyn.util.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.CaseFormat;
+import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.reflect.TypeToken;
@@ -283,4 +290,21 @@ public class ConfigKeys {
}
+ /** determine whether a key is reinherited, ie its value is exported to container's descendants */
+ public static <T> boolean isRehinherited(final ConfigKey<T> key, final InheritanceContext context) {
+ // 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>>() {
+ @Override
+ public Maybe<T> apply(Void input) {
+ return Maybe.ofAllowingNull(null);
+ }
+ }));
+
+ ContainerAndValue<T> combinedVal = ConfigInheritance.ALWAYS.resolveInheriting(
+ key, Maybe.<T>absent(), null,
+ ckvi.iterator(), InheritanceContext.TYPE_DEFINITION);
+ return combinedVal.isValueSet();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/94179834/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 ee31779..2bbddf3 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
@@ -36,12 +36,13 @@ import org.apache.brooklyn.config.ConfigInheritance.ContainerAndKeyValue;
import org.apache.brooklyn.config.ConfigInheritance.ContainerAndValue;
import org.apache.brooklyn.config.ConfigInheritance.InheritanceMode;
import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.BasicConfigInheritance.BasicContainerAndKeyValue;
import org.apache.brooklyn.core.config.ConfigKeys.InheritanceContext;
import org.apache.brooklyn.core.config.Sanitizer;
import org.apache.brooklyn.core.config.StructuredConfigKey;
import org.apache.brooklyn.core.config.internal.AbstractConfigMapImpl;
import org.apache.brooklyn.core.entity.AbstractEntity;
-import org.apache.brooklyn.util.collections.CollectionMerger;
+import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.flags.FlagUtils;
@@ -52,6 +53,7 @@ import org.apache.brooklyn.util.guava.Maybe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -121,11 +123,9 @@ public class EntityConfigMap extends AbstractConfigMapImpl {
return TypeCoercions.coerce((defaultValue != null) ? defaultValue : ownKey.getDefaultValue(), key.getTypeToken());
}
- @SuppressWarnings("unchecked")
private <T> Maybe<T> getConfigImpl(final ConfigKeySelfExtracting<T> key) {
final ExecutionContext exec = entity.getExecutionContext();
Maybe<T> ownValue;
- Maybe<T> parentValue;
// Get own value
if (((ConfigKeySelfExtracting<T>)key).isSet(ownConfig)) {
@@ -142,61 +142,26 @@ public class EntityConfigMap extends AbstractConfigMapImpl {
} else {
ownValue = Maybe.<T>absent();
}
- final Maybe<T> ownValueF = ownValue;
-
- ContainerAndValue<T> result = getDefaultRuntimeInheritance().resolveInheriting(new Iterator<ContainerAndKeyValue<T>>() {
- int count = 0;
- @Override
- public boolean hasNext() {
- return count < 2;
- }
- @Override
- public ContainerAndKeyValue<T> next() {
- if (count >= 2) throw new NoSuchElementException();
- final boolean isLookingAtInheritedBag = (count==1);
- try {
- return new ContainerAndKeyValue<T>() {
- @Override
- public Object getContainer() {
- // TODO the current inheritedConfigBag is not good enough to detect the ancestor container
- return !isLookingAtInheritedBag ? entity : entity.getParent();
- }
- @Override
- public T getValue() {
- return peekValue().orNull();
- }
- protected Maybe<T> peekValue() {
- if (!isLookingAtInheritedBag) return ownValueF;
- if (((ConfigKeySelfExtracting<T>)key).isSet(inheritedConfig)) {
- return Maybe.of( ((ConfigKeySelfExtracting<T>)key).extractValue(inheritedConfig, exec) );
- } else if (inheritedConfigBag.containsKey(key)) {
- return Maybe.of(inheritedConfigBag.get(key));
- } else {
- return Maybe.absent();
- }
- }
-
- @Override
- public boolean isValueSet() {
- return peekValue().isPresent();
- }
-
- @Override
- public ConfigKey<T> getKey() {
- return key;
- }
-
- @Override
- public T getDefaultValue() {
- return key.getDefaultValue();
- }
- };
- } finally {
- count++;
+
+ // TODO the current inheritedConfigBag is not good enough to detect the ancestor container
+ // (only goes up one level in hierarchy)
+ Iterable<? extends ContainerAndKeyValue<T>> ckvi = MutableList.of(
+ new BasicContainerAndKeyValue<Entity,T>(key, entity.getParent(), new Function<Entity,Maybe<T>>() {
+ @Override
+ public Maybe<T> apply(Entity input) {
+ if (((ConfigKeySelfExtracting<T>)key).isSet(inheritedConfig)) {
+ return Maybe.of( ((ConfigKeySelfExtracting<T>)key).extractValue(inheritedConfig, exec) );
+ } else if (inheritedConfigBag.containsKey(key)) {
+ return Maybe.of(inheritedConfigBag.get(key));
+ } else {
+ return Maybe.absent();
+ }
}
- }
- @Override public void remove() { throw new UnsupportedOperationException(); }
- }, InheritanceContext.RUNTIME_MANAGEMENT);
+ }));
+
+ ContainerAndValue<T> result = getDefaultRuntimeInheritance().resolveInheriting(key,
+ ownValue, entity,
+ ckvi.iterator(), InheritanceContext.RUNTIME_MANAGEMENT);
if (result.isValueSet()) return Maybe.of(result.getValue());
return Maybe.absent();
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/94179834/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 a07a9d2..6b8fde3 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
@@ -22,6 +22,8 @@ import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
+import javax.annotation.Nullable;
+
import org.apache.brooklyn.util.collections.CollectionMerger;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.text.Strings;
@@ -65,12 +67,11 @@ public interface ConfigInheritance extends Serializable {
}
/**
- * given an iterable of the config containers (eg an entity) and associated data,
- * with the first entry being the container of immediate interest
- * and the subsequent nodes being the ancestors,
- * this finds the value set for a config key after all inheritance strategies are applied,
- * for instance merging a map throughout a container hierarchy,
- * or traversing up until a non-reinheritable key definition is found and then returning the default value of the key
+ * 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>.
+ * for instance this may merge a map throughout a container hierarchy,
+ * or this may traverse up until a non-reinheritable key definition is found and in the absence of values lower
+ * in the hierarchy this will return the default value of the key
* <p>
* this uses an interface on the input so that:
* - the caller can supply the hierarchy
@@ -93,7 +94,10 @@ public interface ConfigInheritance extends Serializable {
* if null is returned the caller knows nothing is to be exported to children.
*/
<T> ContainerAndValue<T> resolveInheriting(
- Iterator<ContainerAndKeyValue<T>> containerAndDataThroughAncestors,
+ ConfigKey<T> key,
+ @Nullable Maybe<T> localValue,
+ @Nullable Object container,
+ Iterator<? extends ContainerAndKeyValue<T>> ancestorContainerKeyValues,
ConfigInheritanceContext context);
/** @deprecated since 0.10.0 see implementations of this interface */ @Deprecated
@@ -121,65 +125,60 @@ public interface ConfigInheritance extends Serializable {
@Override public T getValue() { return value; }
@Override public boolean isValueSet() { return isValueSet; }
}
+
+ // close copy of method in BasicConfigInheritance for this legacy compatibility evaluation
@Override
public <T> ContainerAndValue<T> resolveInheriting(
- Iterator<ContainerAndKeyValue<T>> containerAndLocalValues,
- ConfigInheritanceContext context) {
- if (containerAndLocalValues.hasNext()) {
- ContainerAndKeyValue<T> c = containerAndLocalValues.next();
- if (c==null) return resolveInheriting(containerAndLocalValues, context);
-
- ConfigKey<T> key = c.getKey();
- ConfigInheritance ci = null;
- if (key!=null) ci = key.getInheritanceByContext(context);
- if (ci==null) ci = this;
-
+ @Nullable ConfigKey<T> key, Maybe<T> localValue, Object container,
+ Iterator<? extends ContainerAndKeyValue<T>> 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 (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();
+ ConfigInheritance inh2 = c.getKey()==null ? null : c.getKey().getInheritanceByContext(context);
+ if (inh2==null) inh2 = 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(containerAndLocalValues, context);
- if (ri.isValueSet()) {
- // value found, return it
- return ri;
- }
- // else no inherited, fall through to below
+ // can't inherit
} 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(containerAndLocalValues, 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;
- }
- }
+ // get inherited value
+ v2 = inh2.resolveInheriting(c.getKey(),
+ c.isValueSet() ? Maybe.of(c.getValue()) : Maybe.<T>absent(), c.getContainer(),
+ ancestorContainerKeyValues, context);
}
- 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();
+
+ if (v2!=null && v2.isValueSet() && !localValue.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.getDefaultValue();
+ } else {
+ v.value = resolveConflict(key, localValue, Maybe.ofAllowingNull(v2.getValue()));
+ v.isValueSet = true;
+ }
+ return v;
}
- protected abstract InheritanceMode getMode();
- private static <T> Maybe<T> asMaybe(ContainerAndValue<T> cv) {
- if (cv.isValueSet()) return Maybe.of(cv.getValue());
- return Maybe.absent();
+ /** 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) {
+ if (getMode()==InheritanceMode.IF_NO_EXPLICIT_VALUE) {
+ if (localValue.isPresent()) return localValue.get();
+ return ancestorValue.orNull();
+ }
+ if (getMode()==InheritanceMode.DEEP_MERGE) {
+ return deepMerge(localValue, ancestorValue).orNull();
+ }
+ throw new IllegalStateException("Unknown config conflict resolution strategy '"+getMode()+"' evaluating "+key);
}
- private static <T> Maybe<?> deepMerge(Maybe<? extends T> val1, Maybe<? extends T> val2) {
+ private static <T> Maybe<? extends T> deepMerge(Maybe<? extends T> val1, Maybe<? extends T> val2) {
if (val2.isAbsent() || val2.isNull()) {
return val1;
} else if (val1.isAbsent()) {
@@ -187,12 +186,86 @@ public interface ConfigInheritance extends Serializable {
} 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()));
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ Maybe<T> result = (Maybe)Maybe.of(CollectionMerger.builder().build().merge((Map<?,?>)val1.get(), (Map<?,?>)val2.get()));
+ return result;
} else {
// cannot merge; just return val1
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