change impl of EntityConfigMap to not cache inherited fix tests, and misc other more fixes and notes
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/8847b2ee Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/8847b2ee Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/8847b2ee Branch: refs/heads/master Commit: 8847b2eed525f23080e8741ed5d9ba7119507534 Parents: c701fcb Author: Alex Heneveld <alex.henev...@cloudsoftcorp.com> Authored: Mon Sep 19 23:11:11 2016 +0100 Committer: Alex Heneveld <alex.henev...@cloudsoftcorp.com> Committed: Tue Sep 20 09:58:13 2016 +0100 ---------------------------------------------------------------------- .../brooklyn/ConfigInheritanceYamlTest.java | 32 +- .../core/config/BasicConfigInheritance.java | 44 ++- .../apache/brooklyn/core/config/ConfigKeys.java | 12 +- .../config/internal/AbstractConfigMapImpl.java | 6 + .../brooklyn/core/entity/AbstractEntity.java | 14 +- .../brooklyn/core/entity/EntityAsserts.java | 2 +- .../brooklyn/core/entity/EntityFunctions.java | 44 ++- .../core/entity/internal/EntityConfigMap.java | 305 +++++++------------ .../core/internal/BrooklynPropertiesImpl.java | 5 + .../core/location/AbstractLocation.java | 6 + .../internal/DeferredBrooklynProperties.java | 5 + .../core/objs/AbstractEntityAdjunct.java | 5 + .../core/objs/BrooklynObjectInternal.java | 18 +- .../entity/software/base/SoftwareProcess.java | 1 + .../SoftwareProcessEntityFeedRebindTest.java | 2 +- .../brooklyn/config/ConfigInheritance.java | 17 +- .../org/apache/brooklyn/config/ConfigMap.java | 11 + 17 files changed, 316 insertions(+), 213 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigInheritanceYamlTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigInheritanceYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigInheritanceYamlTest.java index fd4472c..c3d4ebc 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigInheritanceYamlTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ConfigInheritanceYamlTest.java @@ -60,6 +60,7 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { private Path emptyFile; private Path emptyFile2; + private Path emptyFile3; private ExecutorService executor; @@ -72,6 +73,7 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { emptyFile = Files.createTempFile("ConfigInheritanceYamlTest", ".txt"); emptyFile2 = Files.createTempFile("ConfigInheritanceYamlTest2", ".txt"); + emptyFile3 = Files.createTempFile("ConfigInheritanceYamlTest3", ".txt"); addCatalogItems( "brooklyn.catalog:", @@ -326,53 +328,72 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { "- type: org.apache.brooklyn.entity.stock.BasicApplication", " brooklyn.config:", " shell.env:", - " ENV1: myEnv1", + " ENV: myEnv", + " ENV3: myEnv", " templates.preinstall:", " "+emptyFile.toUri()+": myfile", + " "+emptyFile3.toUri()+": myfile", " files.preinstall:", " "+emptyFile.toUri()+": myfile", + " "+emptyFile3.toUri()+": myfile", " templates.install:", " "+emptyFile.toUri()+": myfile", + " "+emptyFile3.toUri()+": myfile", " files.install:", " "+emptyFile.toUri()+": myfile", + " "+emptyFile3.toUri()+": myfile", " templates.runtime:", " "+emptyFile.toUri()+": myfile", + " "+emptyFile3.toUri()+": myfile", " files.runtime:", " "+emptyFile.toUri()+": myfile", + " "+emptyFile3.toUri()+": myfile", " provisioning.properties:", " mykey: myval", + " mykey3: myval", " templateOptions:", " myOptionsKey: myOptionsVal", + " myOptionsKey3: myOptionsVal", " brooklyn.children:", " - type: org.apache.brooklyn.entity.software.base.EmptySoftwareProcess", " brooklyn.config:", " shell.env:", " ENV2: myEnv2", + " ENV3: myEnv2", " templates.preinstall:", " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile3.toUri()+": myfile2", " files.preinstall:", " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile3.toUri()+": myfile2", " templates.install:", " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile3.toUri()+": myfile2", " files.install:", " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile3.toUri()+": myfile2", " templates.runtime:", " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile3.toUri()+": myfile2", " files.runtime:", " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile3.toUri()+": myfile2", " provisioning.properties:", " mykey2: myval2", + " mykey3: myval2", " templateOptions:", - " myOptionsKey2: myOptionsVal2"); + " myOptionsKey2: myOptionsVal2", + " myOptionsKey3: myOptionsVal2"); Entity app = createStartWaitAndLogApplication(yaml); Entity entity = Iterables.getOnlyElement(app.getChildren()); assertEmptySoftwareProcessConfig( entity, - ImmutableMap.of("ENV2", "myEnv2"), - ImmutableMap.of(emptyFile2.toUri().toString(), "myfile2"), - ImmutableMap.of("mykey2", "myval2", "templateOptions", ImmutableMap.of("myOptionsKey2", "myOptionsVal2"))); + ImmutableMap.of("ENV", "myEnv", "ENV2", "myEnv2", "ENV3", "myEnv2"), + ImmutableMap.of(emptyFile.toUri().toString(), "myfile", emptyFile2.toUri().toString(), "myfile2", emptyFile3.toUri().toString(), "myfile2"), + ImmutableMap.of("mykey", "myval", "mykey2", "myval2", "mykey3", "myval2", + "templateOptions", ImmutableMap.of("myOptionsKey", "myOptionsVal", "myOptionsKey2", "myOptionsVal2", "myOptionsKey3", "myOptionsVal2"))); } @Test @@ -629,6 +650,7 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { // TODO Has never worked, and probably hard to fix?! We need to figure out that "env" corresponds to the // config key. Maybe FlagUtils could respect SetFromFlags when returning Map<String,ConfigKey>? + // TODO should be able to fix in this phase of work @Test(groups={"WIP", "Broken"}) public void testExtendsSuperTypeConfigMixingShortOverridingShortName() throws Exception { ImmutableMap<String, Object> expectedEnv = ImmutableMap.<String, Object>of("ENV1", "myEnv1", "ENV2", "myEnv2"); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/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 c4ac255..764e0d6 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 @@ -20,6 +20,7 @@ package org.apache.brooklyn.core.config; import java.util.Iterator; import java.util.Map; +import java.util.NoSuchElementException; import javax.annotation.Nullable; @@ -80,12 +81,12 @@ public class BasicConfigInheritance implements ConfigInheritance { // 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) { + if (inh2!=null && !ConfigKeys.isReinherited(c.getKey(), context)) { // can't inherit } else { // get inherited value - v2 = inh2.resolveInheriting(c.getKey(), + 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(), ancestorContainerKeyValues, context); } @@ -99,7 +100,7 @@ public class BasicConfigInheritance implements ConfigInheritance { v.container = container; if (v2==null || !v2.isValueSet()) { v.isValueSet = localValue.isPresent(); - v.value = v.isValueSet() ? localValue.get() : key.getDefaultValue(); + v.value = v.isValueSet() ? localValue.get() : key!=null ? key.getDefaultValue() : null; } else { v.value = resolveConflict(key, localValue, Maybe.ofAllowingNull(v2.getValue())); v.isValueSet = true; @@ -190,6 +191,41 @@ public class BasicConfigInheritance implements ConfigInheritance { public TValue getDefaultValue() { return key.getDefaultValue(); } + } + + public static class AncestorContainerAndKeyValueIterator<TContainer,TValue> implements Iterator<ContainerAndKeyValue<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 ContainerAndKeyValue<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); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("This iterator does not support removal"); + } } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/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 5dd7204..795da50 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,6 +22,7 @@ import java.util.Map; 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; @@ -290,10 +291,17 @@ public class ConfigKeys { } /** determine whether a key is reinherited, ie its value is exported to container's descendants - * @deprecated since 0.10.0 In order to determine whether a key is inherited we might need to know whether + * @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 InheritanceContext context) { + public static <T> boolean isReinherited(final ConfigKey<T> key, final ConfigInheritanceContext context) { + if (key==null) return true; + ConfigInheritance inh = key.getInheritanceByContext(context); + if (inh==null) return true; + if (inh instanceof BasicConfigInheritance) { + return ((BasicConfigInheritance)inh).isReinherited; + } + // 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>>() { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/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 fd02fc1..26e44b6 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 @@ -30,6 +30,7 @@ import org.apache.brooklyn.core.config.StructuredConfigKey; import org.apache.brooklyn.core.entity.internal.ConfigMapViewWithStringKeys; import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.apache.brooklyn.util.core.task.DeferredSupplier; +import org.apache.brooklyn.util.guava.Maybe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,6 +64,11 @@ public abstract class AbstractConfigMapImpl implements ConfigMap { return getConfigRaw(key, true).orNull(); } + @Override + public Maybe<Object> getConfigLocalRaw(ConfigKey<?> key) { + return getConfigRaw(key, false); + } + protected Object coerceConfigVal(ConfigKey<?> key, Object v) { Object val; if ((v instanceof Future) || (v instanceof DeferredSupplier)) { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java index 3c9e18d..0b40e32 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java @@ -54,6 +54,7 @@ import org.apache.brooklyn.api.sensor.Sensor; import org.apache.brooklyn.api.sensor.SensorEvent; import org.apache.brooklyn.api.sensor.SensorEventListener; import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.config.ConfigMap; import org.apache.brooklyn.config.ConfigKey.HasConfigKey; import org.apache.brooklyn.core.BrooklynFeatureEnablement; import org.apache.brooklyn.core.BrooklynLogging; @@ -1254,12 +1255,8 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E @Override public void refreshInheritedConfig() { - if (getParent() != null) { - configsInternal.setInheritedConfig(((EntityInternal)getParent()).getAllConfig(), ((EntityInternal)getParent()).config().getBag()); - } else { - configsInternal.clearInheritedConfig(); - } - + // no-op, for now, because the impl always looks at ancestors + // but in a distributed impl it will need to clear any local cache refreshInheritedConfigOfChildren(); } @@ -1290,6 +1287,11 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E protected ExecutionContext getContext() { return AbstractEntity.this.getExecutionContext(); } + + @Override + public ConfigMap getInternalConfigMap() { + return configsInternal; + } } @Override http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/core/src/main/java/org/apache/brooklyn/core/entity/EntityAsserts.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityAsserts.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityAsserts.java index a793c1f..449d498 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityAsserts.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityAsserts.java @@ -159,7 +159,7 @@ public class EntityAsserts { try { Asserts.succeedsEventually(new Runnable() { @Override public void run() { - Asserts.assertTrue(changed.get(), entity + " -> " + attribute + " not changed"); + Asserts.assertTrue(changed.get(), entity + " -> " + attribute + " not changed from "+origValue); }}); } finally { entity.subscriptions().unsubscribe(entity, handle); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java b/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java index 7d8fa3d..505c0d6 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/EntityFunctions.java @@ -19,10 +19,13 @@ package org.apache.brooklyn.core.entity; import static com.google.common.base.Preconditions.checkNotNull; +import static org.apache.brooklyn.util.groovy.GroovyJavaMethods.elvis; import java.util.Collection; import java.util.Map; +import javax.annotation.Nullable; + import org.apache.brooklyn.api.entity.Application; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntityLocal; @@ -347,7 +350,8 @@ public class EntityFunctions { private static class LocationMatching implements Function<Entity, Location> { private Predicate<? super Location> filter; - private LocationMatching() { /* for xstream */ + @SuppressWarnings("unused") + private LocationMatching() { /* for xstream */ } public LocationMatching(Predicate<? super Location> filter) { this.filter = filter; @@ -356,4 +360,42 @@ public class EntityFunctions { return Iterables.find(input.getLocations(), filter); } } + + public static Function<Entity, Entity> parent() { + return new EntityParent(); + } + + private static class EntityParent implements Function<Entity, Entity> { + @Override public Entity apply(Entity input) { + return input==null ? null : input.getParent(); + } + } + + /** Returns a function that finds the best match for the given config key on an entity */ + public static <T> Function<Entity, ConfigKey<T>> configKeyFinder(ConfigKey<T> queryKey, @Nullable ConfigKey<T> defaultValue) { + return new EntityKeyFinder<T>(queryKey, defaultValue); + } + + /** As {@link #configKeyFinder(ConfigKey,ConfigKey)} using the query key as the default value */ + public static <T> Function<Entity, ConfigKey<T>> configKeyFinder(ConfigKey<T> queryKey) { + return new EntityKeyFinder<T>(queryKey, queryKey); + } + + private static class EntityKeyFinder<T> implements Function<Entity, ConfigKey<T>> { + private ConfigKey<T> queryKey; + private ConfigKey<T> defaultValue; + + @SuppressWarnings("unused") + private EntityKeyFinder() { /* for xstream */ } + public EntityKeyFinder(ConfigKey<T> queryKey, ConfigKey<T> defaultValue) { + this.queryKey = queryKey; + this.defaultValue = defaultValue; + } + + @SuppressWarnings("unchecked") + @Override public ConfigKey<T> apply(Entity entity) { + return entity!=null ? (ConfigKey<T>)elvis(entity.getEntityType().getConfigKey(queryKey.getName()), defaultValue) : defaultValue; + } + } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/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 72d494c..9014d84 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 @@ -19,33 +19,31 @@ package org.apache.brooklyn.core.entity.internal; import static com.google.common.base.Preconditions.checkNotNull; -import static org.apache.brooklyn.util.groovy.GroovyJavaMethods.elvis; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Set; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.mgmt.ExecutionContext; import org.apache.brooklyn.api.mgmt.Task; 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.ConfigMap; 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.BasicConfigInheritance.AncestorContainerAndKeyValueIterator; 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.MutableList; +import org.apache.brooklyn.core.entity.EntityFunctions; +import org.apache.brooklyn.core.entity.EntityInternal; +import org.apache.brooklyn.core.objs.BrooklynObjectInternal; +import org.apache.brooklyn.core.objs.BrooklynObjectInternal.ConfigurationSupportInternal; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.config.ConfigBag; -import org.apache.brooklyn.util.core.flags.FlagUtils; -import org.apache.brooklyn.util.core.flags.SetFromFlag; import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.apache.brooklyn.util.core.internal.ConfigKeySelfExtracting; import org.apache.brooklyn.util.guava.Maybe; @@ -55,7 +53,6 @@ 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; public class EntityConfigMap extends AbstractConfigMapImpl { @@ -63,19 +60,9 @@ public class EntityConfigMap extends AbstractConfigMapImpl { /** entity against which config resolution / task execution will occur */ private final AbstractEntity entity; - - /** - * Map of configuration information that is defined at start-up time for the entity. These - * configuration parameters are shared and made accessible to the "children" of this - * entity. - */ - private final Map<ConfigKey<?>,Object> inheritedConfig = Collections.synchronizedMap(new LinkedHashMap<ConfigKey<?>, Object>()); - // TODO do we really want to have *both* bags and maps for these? danger that they get out of synch. - // have added some logic (Oct 2014) so that the same changes are applied to both, in most places at least; - // i (alex) think we should prefer ConfigBag (the input keys don't matter, it is more a question of retrieval keys), - // but first we need ConfigBag to support StructuredConfigKeys - private final ConfigBag localConfigBag; - private final ConfigBag inheritedConfigBag; + /** config bag cache for local anonymous key lookup */ + // TODO this could be removed and everything made more like AdjunctConfigMap + private final ConfigBag ownConfigBag; public EntityConfigMap(AbstractEntity entity) { // Not using ConcurrentMap, because want to (continue to) allow null values. @@ -86,96 +73,88 @@ public class EntityConfigMap extends AbstractConfigMapImpl { public EntityConfigMap(AbstractEntity entity, Map<ConfigKey<?>, Object> storage) { this.entity = checkNotNull(entity, "entity must be specified"); this.ownConfig = checkNotNull(storage, "storage map must be specified"); - - // TODO store ownUnused in backing-storage - this.localConfigBag = ConfigBag.newInstance(); - this.inheritedConfigBag = ConfigBag.newInstance(); + this.ownConfigBag = ConfigBag.newInstance(); } + + /* These flags are included for documentation. + * Changes will require testing. + * Note that trying to get a raw inherited value can be problematic + * if it is merging resolved values. + */ + final static boolean RESOLVE_AND_COERCE_EXTRACTING_KEYS = true; + final static boolean COERCE_DEFAULT_VALUES = true; + // TODO We're notifying of config-changed because currently persistence needs to know when the + // attributeWhenReady is complete (so it can persist the result). + // Long term, we'll just persist tasks properly so the call to onConfigChanged will go! + final static boolean NOTIFY_ON_TASK_RESOLUTION = true; - @SuppressWarnings("unchecked") - public <T> T getConfig(ConfigKey<T> key, T defaultValue) { - // In case this entity class has overridden the given key (e.g. to set default), then retrieve this entity's key - // TODO If ask for a config value that's not in our configKeys, should we really continue with rest of method and return key.getDefaultValue? - // e.g. SshBasedJavaAppSetup calls setAttribute(JMX_USER), which calls getConfig(JMX_USER) - // but that example doesn't have a default... - ConfigKey<T> ownKey = entity!=null ? (ConfigKey<T>)elvis(entity.getEntityType().getConfigKey(key.getName()), key) : key; + protected static class LocalEvaluateKeyValue<T> implements Function<Entity,Maybe<T>> { + ConfigKey<T> keyIgnoringInheritance; - // TODO We're notifying of config-changed because currently persistence needs to know when the - // attributeWhenReady is complete (so it can persist the result). - // Long term, we'll just persist tasks properly so the call to onConfigChanged will go! - - // Don't use groovy truth: if the set value is e.g. 0, then would ignore set value and return default! - if (ownKey instanceof ConfigKeySelfExtracting) { - Object rawval = ownConfig.get(key); - // TODO this no longer looks at key's inheritance - Maybe<T> result = getConfigImpl((ConfigKeySelfExtracting<T>)ownKey); - - if (rawval instanceof Task) { - entity.getManagementSupport().getEntityChangeListener().onConfigChanged(key); + public LocalEvaluateKeyValue(ConfigKey<T> keyIgnoringInheritance) { + this.keyIgnoringInheritance = keyIgnoringInheritance; + } + + @Override + public Maybe<T> apply(Entity entity) { + ExecutionContext exec = ((EntityInternal)entity).getExecutionContext(); + ConfigMap configMap = ((ConfigurationSupportInternal)entity.config()).getInternalConfigMap(); + Map<ConfigKey<?>,Object> ownConfig = ((EntityConfigMap)configMap).ownConfig; + ConfigBag ownConfigBag = ((EntityConfigMap)configMap).ownConfigBag; + Maybe<Object> rawValue = configMap.getConfigLocalRaw(keyIgnoringInheritance); + Maybe<T> ownValue; + + // Get own value + if (RESOLVE_AND_COERCE_EXTRACTING_KEYS && keyIgnoringInheritance instanceof ConfigKeySelfExtracting && ((ConfigKeySelfExtracting<T>)keyIgnoringInheritance).isSet(ownConfig)) { + Map<ConfigKey<?>, ?> ownCopy; + synchronized (ownConfig) { + // TODO wasteful to make a copy to look up; maybe try once opportunistically? + ownCopy = MutableMap.copyOf(ownConfig); + } + ownValue = Maybe.of(((ConfigKeySelfExtracting<T>) keyIgnoringInheritance).extractValue(ownCopy, exec)); + } else if (ownConfigBag.containsKey(keyIgnoringInheritance)) { + // TODO configBag.get doesn't handle tasks/attributeWhenReady - it only uses TypeCoercions + // Precedence ordering has changed; previously we'd prefer an explicit isSet(inheritedConfig) + // over the localConfigBag.get(key). + ownValue = Maybe.of(ownConfigBag.get(keyIgnoringInheritance)); + } else { + ownValue = Maybe.<T>absent(); } - if (result.isPresent()) { - return result.get(); + + if (NOTIFY_ON_TASK_RESOLUTION && rawValue.isPresent() && (rawValue.get() instanceof Task)) { + ((EntityInternal)entity).getManagementSupport().getEntityChangeListener().onConfigChanged(keyIgnoringInheritance); } - } else { - LOG.warn("Config key {} of {} is not a ConfigKeySelfExtracting; cannot retrieve value; returning default", ownKey, this); + + return ownValue; } - return TypeCoercions.coerce((defaultValue != null) ? defaultValue : ownKey.getDefaultValue(), key.getTypeToken()); } - private <T> Maybe<T> getConfigImpl(final ConfigKeySelfExtracting<T> key) { - final ExecutionContext exec = entity.getExecutionContext(); - Maybe<T> ownValue; - - // Get own value - if (((ConfigKeySelfExtracting<T>)key).isSet(ownConfig)) { - Map<ConfigKey<?>, ?> ownCopy; - synchronized (ownConfig) { - ownCopy = MutableMap.copyOf(ownConfig); - } - ownValue = Maybe.of(((ConfigKeySelfExtracting<T>) key).extractValue(ownCopy, exec)); - } else if (localConfigBag.containsKey(key)) { - // TODO configBag.get doesn't handle tasks/attributeWhenReady - it only uses TypeCoercions - // Precedence ordering has changed; previously we'd prefer an explicit isSet(inheritedConfig) - // over the localConfigBag.get(key). - ownValue = Maybe.of(localConfigBag.get(key)); - } else { - ownValue = Maybe.<T>absent(); - } + public <T> T getConfig(ConfigKey<T> key, T defaultValue) { + Function<Entity, ConfigKey<T>> keyFn = EntityFunctions.configKeyFinder(key, null); - // 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(); - } - } - })); + // In case this entity class has overridden the given key (e.g. to set default), then retrieve this entity's key + ConfigKey<T> ownKey = keyFn.apply(entity); + if (ownKey==null) ownKey = key; + + LocalEvaluateKeyValue<T> evalFn = new LocalEvaluateKeyValue<T>(ownKey); - ContainerAndValue<T> result = getDefaultRuntimeInheritance().resolveInheriting(key, - ownValue, entity, - ckvi.iterator(), InheritanceContext.RUNTIME_MANAGEMENT); + if (ownKey instanceof ConfigKeySelfExtracting) { + Maybe<T> ownExplicitValue = evalFn.apply(entity); + + AncestorContainerAndKeyValueIterator<Entity, T> ckvi = new AncestorContainerAndKeyValueIterator<Entity,T>( + entity, keyFn, evalFn, EntityFunctions.parent()); + + ContainerAndValue<T> result = getDefaultRuntimeInheritance().resolveInheriting(ownKey, + ownExplicitValue, entity, + ckvi, InheritanceContext.RUNTIME_MANAGEMENT); - if (result.isValueSet()) return Maybe.of(result.getValue()); - return Maybe.absent(); + if (result.getValue()!=null) return result.getValue(); + } else { + LOG.warn("Config key {} of {} is not a ConfigKeySelfExtracting; cannot retrieve value; returning default", ownKey, this); + } + return COERCE_DEFAULT_VALUES ? TypeCoercions.coerce(defaultValue, key.getTypeToken()) : defaultValue; } - private <T> boolean isInherited(ConfigKey<T> key) { - // TODO - return ConfigKeys.isReinherited(key, InheritanceContext.RUNTIME_MANAGEMENT); - } -// private <T> boolean isInherited(ConfigKey<T> key, ConfigInheritance inheritance) { -// if (inheritance==null) inheritance = getDefaultRuntimeInheritance(); -// InheritanceMode mode = inheritance.isInherited(key, entity.getParent(), entity); -// return mode != null && mode != InheritanceMode.NONE; -// } - private ConfigInheritance getDefaultRuntimeInheritance() { return BasicConfigInheritance.OVERWRITE; } @@ -183,14 +162,16 @@ public class EntityConfigMap extends AbstractConfigMapImpl { @Override public Maybe<Object> getConfigRaw(ConfigKey<?> key, boolean includeInherited) { if (ownConfig.containsKey(key)) return Maybe.of(ownConfig.get(key)); - if (includeInherited && inheritedConfig.containsKey(key)) return Maybe.of(inheritedConfig.get(key)); - return Maybe.absent(); + if (!includeInherited || entity.getParent()==null) return Maybe.absent(); + return ((ConfigurationSupportInternal)entity.getParent().config()).getRaw(key); } /** an immutable copy of the config visible at this entity, local and inherited (preferring local) */ + // TODO deprecate because key inheritance not respected public Map<ConfigKey<?>,Object> getAllConfig() { - Map<ConfigKey<?>,Object> result = new LinkedHashMap<ConfigKey<?>,Object>(inheritedConfig.size()+ownConfig.size()); - result.putAll(inheritedConfig); + Map<ConfigKey<?>,Object> result = new LinkedHashMap<ConfigKey<?>,Object>(); + if (entity.getParent()!=null) + result.putAll( ((BrooklynObjectInternal)entity.getParent()).config().getInternalConfigMap().getAllConfig() ); result.putAll(ownConfig); return Collections.unmodifiableMap(result); } @@ -203,17 +184,20 @@ public class EntityConfigMap extends AbstractConfigMapImpl { } /** Creates an immutable copy of the config visible at this entity, local and inherited (preferring local), including those that did not match config keys */ + // TODO deprecate because key inheritance not respected public ConfigBag getAllConfigBag() { - return ConfigBag.newInstanceCopying(localConfigBag) - .putAll(ownConfig) - .putIfAbsent(inheritedConfig) - .putIfAbsent(inheritedConfigBag) - .seal(); + ConfigBag result = ConfigBag.newInstanceCopying(ownConfigBag) + .putAll(ownConfig); + if (entity.getParent()!=null) { + result.putIfAbsent( + ((EntityConfigMap) ((BrooklynObjectInternal)entity.getParent()).config().getInternalConfigMap()).getAllConfigBag() ); + } + return result.seal(); } /** Creates an immutable copy of the config defined at this entity, ie not inherited, including those that did not match config keys */ public ConfigBag getLocalConfigBag() { - return ConfigBag.newInstanceCopying(localConfigBag) + return ConfigBag.newInstanceCopying(ownConfigBag) .putAll(ownConfig) .seal(); } @@ -227,10 +211,10 @@ public class EntityConfigMap extends AbstractConfigMapImpl { // TODO ConfigBag does not handle structured config keys; quick fix is to remove (and should also remove any subkeys; // as it stands if someone set string a.b.c in the config bag then removed structured key a.b, then got a.b.c they'd get a vale); // long term fix is to support structured config keys in ConfigBag, at which point i think we could remove ownConfig altogether - localConfigBag.remove(key); + ownConfigBag.remove(key); } else { oldVal = ownConfig.put(key, val); - localConfigBag.put((ConfigKey<Object>)key, v); + ownConfigBag.put((ConfigKey<Object>)key, v); } entity.config().refreshInheritedConfigOfChildren(); return oldVal; @@ -239,95 +223,27 @@ public class EntityConfigMap extends AbstractConfigMapImpl { public void setLocalConfig(Map<ConfigKey<?>, ?> vals) { synchronized (ownConfig) { ownConfig.clear(); - localConfigBag.clear(); + ownConfigBag.clear(); ownConfig.putAll(vals); - localConfigBag.putAll(vals); - } - } - - public void setInheritedConfig(Map<ConfigKey<?>, ?> valsO, ConfigBag configBagVals) { - Map<ConfigKey<?>, ?> vals = filterUninheritable(valsO); - - inheritedConfig.clear(); - inheritedConfig.putAll(vals); - - // The configBagVals contains all inherited, including strings that did not match a config key on the parent. - // They might match a config-key on this entity though, so need to check that: - // - if it matches one of our keys, set it in inheritedConfig - // - otherwise add it to our inheritedConfigBag - Set<String> valKeyNames = Sets.newLinkedHashSet(); - for (ConfigKey<?> key : vals.keySet()) { - valKeyNames.add(key.getName()); - } - Map<String,Object> valsUnmatched = MutableMap.<String,Object>builder() - .putAll(configBagVals.getAllConfig()) - .removeAll(valKeyNames) - .build(); - inheritedConfigBag.clear(); - Map<ConfigKey<?>, SetFromFlag> annotatedConfigKeys = FlagUtils.getAnnotatedConfigKeys(entity.getClass()); - Map<String, ConfigKey<?>> renamedConfigKeys = Maps.newLinkedHashMap(); - for (Map.Entry<ConfigKey<?>, SetFromFlag> entry: annotatedConfigKeys.entrySet()) { - String rename = entry.getValue().value(); - if (rename != null) { - renamedConfigKeys.put(rename, entry.getKey()); - } - } - for (Map.Entry<String,Object> entry : valsUnmatched.entrySet()) { - String name = entry.getKey(); - Object value = entry.getValue(); - ConfigKey<?> key = renamedConfigKeys.get(name); - if (key == null) key = entity.getEntityType().getConfigKey(name); - if (key != null) { - if (!isInherited(key)) { - // no-op - } else if (inheritedConfig.containsKey(key)) { - LOG.warn("Entity "+entity+" inherited duplicate config for key "+key+", via explicit config and string name "+name+"; using value of key"); - } else { - inheritedConfig.put(key, value); - } - } else { - // a config bag has discarded the keys, so we must assume default inheritance for things given that way - // unless we can infer a key; not a big deal, as we should have the key in inheritedConfig for everything - // which originated with a key ... but still, it would be nice to clean up the use of config bag! - inheritedConfigBag.putStringKey(name, value); - } + ownConfigBag.putAll(vals); } } - - private Map<ConfigKey<?>, ?> filterUninheritable(Map<ConfigKey<?>, ?> vals) { - Map<ConfigKey<?>, Object> result = Maps.newLinkedHashMap(); - for (Map.Entry<ConfigKey<?>, ?> entry : vals.entrySet()) { - if (isInherited(entry.getKey())) { - result.put(entry.getKey(), entry.getValue()); - } - } - return result; - } - + public void addToLocalBag(Map<String,?> vals) { - localConfigBag.putAll(vals); - // quick fix for problem that ownConfig can get out of synch - ownConfig.putAll(localConfigBag.getAllConfigAsConfigKeyMap()); + ownConfigBag.putAll(vals); + // TODO quick fix for problem that ownConfig can get out of synch + ownConfig.putAll(ownConfigBag.getAllConfigAsConfigKeyMap()); } public void removeFromLocalBag(String key) { - localConfigBag.remove(key); + ownConfigBag.remove(key); ownConfig.remove(key); } - public void clearInheritedConfig() { - inheritedConfig.clear(); - inheritedConfigBag.clear(); - } - @Override + // TODO deprecate or clarify syntax public EntityConfigMap submap(Predicate<ConfigKey<?>> filter) { EntityConfigMap m = new EntityConfigMap(entity, Maps.<ConfigKey<?>, Object>newLinkedHashMap()); - for (Map.Entry<ConfigKey<?>,Object> entry: inheritedConfig.entrySet()) { - if (filter.apply(entry.getKey())) { - m.inheritedConfig.put(entry.getKey(), entry.getValue()); - } - } synchronized (ownConfig) { for (Map.Entry<ConfigKey<?>,Object> entry: ownConfig.entrySet()) { if (filter.apply(entry.getKey())) { @@ -335,16 +251,29 @@ public class EntityConfigMap extends AbstractConfigMapImpl { } } } + if (entity.getParent()!=null) { + merge(m, ((EntityConfigMap) ((ConfigurationSupportInternal)entity.getParent().config()).getInternalConfigMap()).submap(filter)); + } + m.ownConfigBag.putAll(ownConfig); return m; } + private void merge(EntityConfigMap local, EntityConfigMap parent) { + for (ConfigKey<?> k: parent.ownConfig.keySet()) { + // TODO apply inheritance + if (!local.ownConfig.containsKey(k)) { + local.ownConfig.put(k, parent.ownConfig.get(k)); + } + } + } + @Override public String toString() { Map<ConfigKey<?>, Object> sanitizeConfig; synchronized (ownConfig) { sanitizeConfig = Sanitizer.sanitize(ownConfig); } - return super.toString()+"[own="+sanitizeConfig+"; inherited="+Sanitizer.sanitize(inheritedConfig)+"]"; + return super.toString()+"[local="+sanitizeConfig+"]"; } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynPropertiesImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynPropertiesImpl.java b/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynPropertiesImpl.java index 023b3e3..d4593b3 100644 --- a/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynPropertiesImpl.java +++ b/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynPropertiesImpl.java @@ -450,6 +450,11 @@ public class BrooklynPropertiesImpl extends LinkedHashMap implements BrooklynPro } @Override + public Maybe<Object> getConfigLocalRaw(ConfigKey<?> key) { + return getConfigRaw(key, false); + } + + @Override public Map<ConfigKey<?>, Object> getAllConfig() { Map<ConfigKey<?>, Object> result = new LinkedHashMap<ConfigKey<?>, Object>(); for (Object entry: entrySet()) http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/core/src/main/java/org/apache/brooklyn/core/location/AbstractLocation.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/AbstractLocation.java b/core/src/main/java/org/apache/brooklyn/core/location/AbstractLocation.java index 1d5c71f..20b44ce 100644 --- a/core/src/main/java/org/apache/brooklyn/core/location/AbstractLocation.java +++ b/core/src/main/java/org/apache/brooklyn/core/location/AbstractLocation.java @@ -45,6 +45,7 @@ import org.apache.brooklyn.api.sensor.Sensor; import org.apache.brooklyn.api.sensor.SensorEventListener; import org.apache.brooklyn.config.ConfigInheritance; import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.config.ConfigMap; import org.apache.brooklyn.config.ConfigKey.HasConfigKey; import org.apache.brooklyn.core.BrooklynFeatureEnablement; import org.apache.brooklyn.core.config.BasicConfigInheritance; @@ -501,6 +502,11 @@ public abstract class AbstractLocation extends AbstractBrooklynObject implements protected ExecutionContext getContext() { return AbstractLocation.this.getManagementContext().getServerExecutionContext(); } + + @Override + public ConfigMap getInternalConfigMap() { + throw new UnsupportedOperationException("location does not use config map"); + } } public class BasicSubscriptionSupport implements SubscriptionSupportInternal { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/DeferredBrooklynProperties.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/DeferredBrooklynProperties.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/DeferredBrooklynProperties.java index ae0c7a5..4e3d342 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/DeferredBrooklynProperties.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/DeferredBrooklynProperties.java @@ -137,6 +137,11 @@ public class DeferredBrooklynProperties implements BrooklynProperties { Maybe<Object> result = delegate.getConfigRaw(key, includeInherited); return (result.isPresent()) ? Maybe.of(transform(key, result.get())) : Maybe.absent(); } + + @Override + public Maybe<Object> getConfigLocalRaw(ConfigKey<?> key) { + return getConfigRaw(key, false); + } @Override public Map<ConfigKey<?>, Object> getAllConfig() { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java index b800334..1f20d6d 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java @@ -359,6 +359,11 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple protected ExecutionContext getContext() { return AbstractEntityAdjunct.this.execution; } + + @Override + public ConfigMap getInternalConfigMap() { + return configsInternal; + } } @Override http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java index 89c4e32..4baea63 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java @@ -26,6 +26,7 @@ import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.objs.Configurable; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.config.ConfigKey.HasConfigKey; +import org.apache.brooklyn.config.ConfigMap; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.guava.Maybe; @@ -51,10 +52,16 @@ public interface BrooklynObjectInternal extends BrooklynObject, Rebindable { * Returns a read-only view of all the config key/value pairs on this entity, backed by a string-based map, * including config names that did not match anything on this entity. * - * TODO This method gives no information about which config is inherited versus local; - * this means {@link ConfigKey#getInheritance()} cannot be respected. This is an unsolvable problem - * for "config names that did not match anything on this entity". Therefore consider using - * alternative getters. + * This method gives no information about which config is inherited versus local; + * this means {@link ConfigKey#getInheritanceByContext()} cannot be respected + * if an anonymous key (not matching a declared config key) is set but the + * strongly typed key is accessed. + * <p> + * It does not identify the container where it is defined, meaning URLs and deferred config values + * cannot be resolved in the context of the appropriate ancestor. + * <p> + * For these reasons it is recommended to use a different accessor, + * and callers should be advised this beta method may be removed. */ @Beta ConfigBag getBag(); @@ -128,6 +135,9 @@ public interface BrooklynObjectInternal extends BrooklynObject, Rebindable { @Beta void refreshInheritedConfigOfChildren(); + + @Beta + ConfigMap getInternalConfigMap(); } @Beta http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java index 0225729..d28bdc6 100644 --- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java +++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/SoftwareProcess.java @@ -258,6 +258,7 @@ public interface SoftwareProcess extends Entity, Startable { .description("Custom properties to be passed in when provisioning a new machine") .defaultValue(ImmutableMap.<String, Object>of()) .typeInheritance(BasicConfigInheritance.DEEP_MERGE) + .runtimeInheritance(BasicConfigInheritance.NOT_REINHERITED_ELSE_DEEP_MERGE) .build(); @SetFromFlag("maxRebindSensorsDelay") http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityFeedRebindTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityFeedRebindTest.java b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityFeedRebindTest.java index aaac53d..960c244 100644 --- a/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityFeedRebindTest.java +++ b/software/base/src/test/java/org/apache/brooklyn/entity/software/base/SoftwareProcessEntityFeedRebindTest.java @@ -68,7 +68,7 @@ public class SoftwareProcessEntityFeedRebindTest extends RebindTestFixtureWithAp runFeedsDoNotPollUntilManaged(1, Duration.millis(250)); } - @Test(groups="Integeration") + @Test(groups="Integration") public void testFeedsDoNotPollUntilManagedManyEntities() throws Exception { runFeedsDoNotPollUntilManaged(100, Duration.ONE_SECOND); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/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 6b8fde3..b9b567c 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,6 +29,7 @@ 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 { @@ -54,6 +55,20 @@ 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(); @@ -160,7 +175,7 @@ public interface ConfigInheritance extends Serializable { v.container = container; if (v2==null || !v2.isValueSet()) { v.isValueSet = localValue.isPresent(); - v.value = v.isValueSet() ? localValue.get() : key.getDefaultValue(); + v.value = v.isValueSet() ? localValue.get() : key!=null ? key.getDefaultValue() : null; } else { v.value = resolveConflict(key, localValue, Maybe.ofAllowingNull(v2.getValue())); v.isValueSet = true; http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8847b2ee/utils/common/src/main/java/org/apache/brooklyn/config/ConfigMap.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigMap.java b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigMap.java index 665bbf6..7838b15 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigMap.java +++ b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigMap.java @@ -66,7 +66,18 @@ public interface ConfigMap { * @return raw, unresolved, uncoerced value of key in map, * but <b>not</b> any default on the key */ + // TODO behaviour of this is undefined if the key specifies a merge public Maybe<Object> getConfigRaw(ConfigKey<?> key, boolean includeInherited); + + /** returns the value stored against the given key, + * <b>not</b> any default, + * <b>not</b> inherited (if there is an inheritance hierarchy), + * <b>not</b> type-coerced or further resolved (eg a task or supplier, if such rules are applicable) + * @param key key to look up + * @return raw, unresolved, uncoerced value of key explicitly in map + */ + // TODO deprecate other methods? getRaw won't be able to merge for instance + public Maybe<Object> getConfigLocalRaw(ConfigKey<?> key); /** returns a map of all config keys to their raw (unresolved+uncoerced) contents */ public Map<ConfigKey<?>,Object> getAllConfig();