address code review comments - javadoc, tests, and a few fixes to the more obscure config map methods
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/8156322b Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/8156322b Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/8156322b Branch: refs/heads/master Commit: 8156322b4362c059516505e9d952ae66a81cfbab Parents: 0d655e0 Author: Alex Heneveld <alex.henev...@cloudsoftcorp.com> Authored: Thu Sep 22 12:45:47 2016 +0100 Committer: Alex Heneveld <alex.henev...@cloudsoftcorp.com> Committed: Thu Sep 22 12:47:08 2016 +0100 ---------------------------------------------------------------------- .../apache/brooklyn/api/objs/Configurable.java | 2 +- .../brooklyn/ConfigInheritanceYamlTest.java | 111 ++++++++++--------- .../brooklyn/camp/brooklyn/ObjectsYamlTest.java | 2 +- .../core/config/BasicConfigInheritance.java | 49 +++++--- .../apache/brooklyn/core/config/ConfigKeys.java | 3 +- .../config/internal/AbstractConfigMapImpl.java | 107 +++++++++++++----- .../internal/LazyContainerAndKeyValue.java | 19 +++- .../core/entity/internal/EntityConfigMap.java | 8 ++ .../core/internal/BrooklynProperties.java | 6 +- .../core/internal/BrooklynPropertiesImpl.java | 2 +- .../location/internal/LocationConfigMap.java | 6 + .../internal/DeferredBrooklynProperties.java | 4 +- .../AbstractConfigurationSupportInternal.java | 2 +- .../brooklyn/core/objs/AdjunctConfigMap.java | 6 + .../core/objs/BasicConfigurableObject.java | 2 +- .../entity/ConfigEntityInheritanceTest.java | 69 +++++++++++- .../core/test/BrooklynAppUnitTestSupport.java | 8 +- .../util/core/internal/FlagUtilsTest.java | 2 +- .../brooklyn/config/ConfigInheritance.java | 4 +- .../brooklyn/config/ConfigInheritances.java | 31 ++++-- .../org/apache/brooklyn/config/ConfigMap.java | 2 +- .../brooklyn/config/ConfigValueAtContainer.java | 20 +++- 22 files changed, 325 insertions(+), 140 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java b/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java index ea36c4d..5957d62 100644 --- a/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java +++ b/api/src/main/java/org/apache/brooklyn/api/objs/Configurable.java @@ -98,6 +98,6 @@ public interface Configurable { */ <T> T set(HasConfigKey<T> key, Task<T> val); - Set<ConfigKey<?>> findKeys(Predicate<ConfigKey<?>> predicate); + Set<ConfigKey<?>> findKeys(Predicate<? super ConfigKey<?>> predicate); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 9a71aed..a6fe62c 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 @@ -20,8 +20,7 @@ package org.apache.brooklyn.camp.brooklyn; import static org.testng.Assert.assertEquals; -import java.nio.file.Files; -import java.nio.file.Path; +import java.io.File; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -38,6 +37,7 @@ import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess; import org.apache.brooklyn.entity.stock.BasicApplication; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool; +import org.apache.brooklyn.util.os.Os; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.AfterMethod; @@ -57,9 +57,9 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { @SuppressWarnings("unused") private static final Logger LOG = LoggerFactory.getLogger(ConfigInheritanceYamlTest.class); - private Path emptyFile; - private Path emptyFile2; - private Path emptyFile3; + private File emptyFile; + private File emptyFile2; + private File emptyFile3; private ExecutorService executor; @@ -70,9 +70,9 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { executor = Executors.newCachedThreadPool(); - emptyFile = Files.createTempFile("ConfigInheritanceYamlTest", ".txt"); - emptyFile2 = Files.createTempFile("ConfigInheritanceYamlTest2", ".txt"); - emptyFile3 = Files.createTempFile("ConfigInheritanceYamlTest3", ".txt"); + emptyFile = Os.newTempFile("ConfigInheritanceYamlTest", ".txt"); + emptyFile2 = Os.newTempFile("ConfigInheritanceYamlTest2", ".txt"); + emptyFile3 = Os.newTempFile("ConfigInheritanceYamlTest3", ".txt"); addCatalogItems( "brooklyn.catalog:", @@ -84,17 +84,17 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { " shell.env:", " ENV1: myEnv1", " templates.preinstall:", - " "+emptyFile.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", " files.preinstall:", - " "+emptyFile.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", " templates.install:", - " "+emptyFile.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", " files.install:", - " "+emptyFile.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", " templates.runtime:", - " "+emptyFile.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", " files.runtime:", - " "+emptyFile.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", " provisioning.properties:", " mykey: myval", " templateOptions:", @@ -136,8 +136,9 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { public void tearDown() throws Exception { super.tearDown(); if (executor != null) executor.shutdownNow(); - if (emptyFile != null) Files.deleteIfExists(emptyFile); - if (emptyFile2 != null) Files.deleteIfExists(emptyFile2); + if (emptyFile != null) emptyFile.delete(); + if (emptyFile2 != null) emptyFile2.delete(); + if (emptyFile3 != null) emptyFile3.delete(); } @Test @@ -153,7 +154,7 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { assertEmptySoftwareProcessConfig( entity, ImmutableMap.of("ENV1", "myEnv1"), - ImmutableMap.of(emptyFile.toUri().toString(), "myfile"), + ImmutableMap.of(emptyFile.getAbsolutePath(), "myfile"), ImmutableMap.of("mykey", "myval", "templateOptions", ImmutableMap.of("myOptionsKey", "myOptionsVal"))); } @@ -167,17 +168,17 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { " shell.env:", " ENV2: myEnv2", " templates.preinstall:", - " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", " files.preinstall:", - " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", " templates.install:", - " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", " files.install:", - " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", " templates.runtime:", - " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", " files.runtime:", - " "+emptyFile2.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", " provisioning.properties:", " mykey2: myval2", " templateOptions:", @@ -189,7 +190,7 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { assertEmptySoftwareProcessConfig( entity, ImmutableMap.of("ENV1", "myEnv1", "ENV2", "myEnv2"), - ImmutableMap.of(emptyFile.toUri().toString(), "myfile", emptyFile2.toUri().toString(), "myfile2"), + ImmutableMap.of(emptyFile.getAbsolutePath(), "myfile", emptyFile2.getAbsolutePath(), "myfile2"), ImmutableMap.of("mykey", "myval", "mykey2", "myval2", "templateOptions", ImmutableMap.of("myOptionsKey", "myOptionsVal", "myOptionsKey2", "myOptionsVal2"))); } @@ -323,23 +324,23 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { " ENV: myEnv", " ENV3: myEnv", " templates.preinstall:", - " "+emptyFile.toUri()+": myfile", - " "+emptyFile3.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", + " "+emptyFile3.getAbsolutePath()+": myfile3", " files.preinstall:", - " "+emptyFile.toUri()+": myfile", - " "+emptyFile3.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", + " "+emptyFile3.getAbsolutePath()+": myfile3", " templates.install:", - " "+emptyFile.toUri()+": myfile", - " "+emptyFile3.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", + " "+emptyFile3.getAbsolutePath()+": myfile3", " files.install:", - " "+emptyFile.toUri()+": myfile", - " "+emptyFile3.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", + " "+emptyFile3.getAbsolutePath()+": myfile3", " templates.runtime:", - " "+emptyFile.toUri()+": myfile", - " "+emptyFile3.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", + " "+emptyFile3.getAbsolutePath()+": myfile3", " files.runtime:", - " "+emptyFile.toUri()+": myfile", - " "+emptyFile3.toUri()+": myfile", + " "+emptyFile.getAbsolutePath()+": myfile", + " "+emptyFile3.getAbsolutePath()+": myfile3", " provisioning.properties:", " mykey: myval", " mykey3: myval", @@ -351,41 +352,41 @@ public class ConfigInheritanceYamlTest extends AbstractYamlTest { " brooklyn.config:", " shell.env:", " ENV2: myEnv2", - " ENV3: myEnv2", + " ENV3: myEnv3", " templates.preinstall:", - " "+emptyFile2.toUri()+": myfile2", - " "+emptyFile3.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", + " "+emptyFile3.getAbsolutePath()+": myfile3", " files.preinstall:", - " "+emptyFile2.toUri()+": myfile2", - " "+emptyFile3.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", + " "+emptyFile3.getAbsolutePath()+": myfile3", " templates.install:", - " "+emptyFile2.toUri()+": myfile2", - " "+emptyFile3.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", + " "+emptyFile3.getAbsolutePath()+": myfile3", " files.install:", - " "+emptyFile2.toUri()+": myfile2", - " "+emptyFile3.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", + " "+emptyFile3.getAbsolutePath()+": myfile3", " templates.runtime:", - " "+emptyFile2.toUri()+": myfile2", - " "+emptyFile3.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", + " "+emptyFile3.getAbsolutePath()+": myfile3", " files.runtime:", - " "+emptyFile2.toUri()+": myfile2", - " "+emptyFile3.toUri()+": myfile2", + " "+emptyFile2.getAbsolutePath()+": myfile2", + " "+emptyFile3.getAbsolutePath()+": myfile3", " provisioning.properties:", " mykey2: myval2", - " mykey3: myval2", + " mykey3: myval3", " templateOptions:", " myOptionsKey2: myOptionsVal2", - " myOptionsKey3: myOptionsVal2"); + " myOptionsKey3: myOptionsVal3"); Entity app = createStartWaitAndLogApplication(yaml); Entity entity = Iterables.getOnlyElement(app.getChildren()); assertEmptySoftwareProcessConfig( entity, - 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"))); + ImmutableMap.of("ENV", "myEnv", "ENV2", "myEnv2", "ENV3", "myEnv3"), + ImmutableMap.of(emptyFile.getAbsolutePath(), "myfile", emptyFile2.getAbsolutePath(), "myfile2", emptyFile3.getAbsolutePath(), "myfile3"), + ImmutableMap.of("mykey", "myval", "mykey2", "myval2", "mykey3", "myval3", + "templateOptions", ImmutableMap.of("myOptionsKey", "myOptionsVal", "myOptionsKey2", "myOptionsVal2", "myOptionsKey3", "myOptionsVal3"))); } @Test http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java index f1ea8eb..a0f56ff 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java @@ -188,7 +188,7 @@ public class ObjectsYamlTest extends AbstractYamlTest { } @Override - public Set<ConfigKey<?>> findKeys(Predicate<ConfigKey<?>> predicate) { + public Set<ConfigKey<?>> findKeys(Predicate<? super ConfigKey<?>> predicate) { return MutableSet.copyOf(Iterables.filter(bag.getAllConfigAsConfigKeyMap().keySet(), predicate)); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 2ed7d48..51f2e7a 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,8 @@ package org.apache.brooklyn.core.config; import java.util.Map; +import javax.annotation.Nullable; + import org.apache.brooklyn.config.ConfigInheritance; import org.apache.brooklyn.config.ConfigInheritances; import org.apache.brooklyn.config.ConfigInheritances.BasicConfigValueAtContainer; @@ -56,43 +58,47 @@ public class BasicConfigInheritance implements ConfigInheritance { * (and often the descendant's value will simply overwrite). */ public static BasicConfigInheritance DEEP_MERGE = new BasicConfigInheritance(true,CONFLICT_RESOLUTION_STRATEGY_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 - // (overriding resolveConflict) - protected final String conflictResolutionStrategy; - // 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)" + /** conflict-resolution-strategy? in {@link BasicConfigInheritance} supported values are + * {@link #CONFLICT_RESOLUTION_STRATEGY_DEEP_MERGE} and {@link #CONFLICT_RESOLUTION_STRATEGY_OVERWRITE}. + * subclasses may pass null if they provide a custom implementaton of {@link #resolveWithParentCustomStrategy(ConfigValueAtContainer, ConfigValueAtContainer, org.apache.brooklyn.config.ConfigInheritance.ConfigInheritanceContext)} */ + @Nullable protected final String conflictResolutionStrategy; + /** 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) { + protected BasicConfigInheritance(boolean isReinherited, @Nullable String conflictResolutionStrategy, boolean useLocalDefaultValue) { super(); this.isReinherited = isReinherited; this.conflictResolutionStrategy = conflictResolutionStrategy; this.useLocalDefaultValue = useLocalDefaultValue; } - @SuppressWarnings("deprecation") - @Override + @Override @Deprecated public InheritanceMode isInherited(ConfigKey<?> key, Object from, Object to) { return null; } + protected <TContainer, TValue> void checkInheritanceContext(ConfigValueAtContainer<TContainer, TValue> local, ConfigInheritanceContext context) { + ConfigInheritance rightInheritance = ConfigInheritances.findInheritance(local, context, this); + if (!equals(rightInheritance)) + throw new IllegalStateException("Low level inheritance computation error: caller should invoke on "+rightInheritance+" " + + "(the inheritance at "+local+"), not "+this); + } @Override public <TContainer, TValue> boolean isReinheritable(ConfigValueAtContainer<TContainer, TValue> parent, ConfigInheritanceContext context) { - if (!equals(ConfigInheritances.findInheritance(parent, context, this))) - throw new IllegalStateException("Method can only be invoked on inheritance at "+parent); + checkInheritanceContext(parent, context); return isReinherited(); } - + @Override public <TContainer,TValue> boolean considerParent( ConfigValueAtContainer<TContainer,TValue> local, ConfigValueAtContainer<TContainer,TValue> parent, ConfigInheritanceContext context) { - if (!equals(ConfigInheritances.findInheritance(local, context, this))) - throw new IllegalStateException("Method can only be invoked on inheritance at "+local); + checkInheritanceContext(local, context); if (parent==null) return false; if (CONFLICT_RESOLUTION_STRATEGY_OVERWRITE.equals(conflictResolutionStrategy)) { // overwrite means ignore if there's an explicit value, or we're using the local default @@ -107,6 +113,8 @@ public class BasicConfigInheritance implements ConfigInheritance { ConfigValueAtContainer<TContainer,TValue> parent, ConfigInheritanceContext context) { + checkInheritanceContext(local, context); + if (!parent.isValueExplicitlySet() && !getUseLocalDefaultValue()) return ReferenceWithError.newInstanceWithoutError(new BasicConfigValueAtContainer<TContainer,TValue>(local)); @@ -115,12 +123,13 @@ public class BasicConfigInheritance implements ConfigInheritance { if (!local.isValueExplicitlySet() && !getUseLocalDefaultValue()) return ReferenceWithError.newInstanceWithoutError(new BasicConfigValueAtContainer<TContainer,TValue>(parent)); - // both explicitly set or defaults applicable, and not overwriting; it should be merge + // both explicitly set or defaults applicable, and not overwriting; it should be merge, or something from child + if (CONFLICT_RESOLUTION_STRATEGY_DEEP_MERGE.equals(conflictResolutionStrategy)) { BasicConfigValueAtContainer<TContainer, TValue> result = new BasicConfigValueAtContainer<TContainer,TValue>(local); ReferenceWithError<Maybe<? extends TValue>> resolvedValue = deepMerge( local.isValueExplicitlySet() ? local.asMaybe() : local.getDefaultValue(), - parent.isValueExplicitlySet() ? parent.asMaybe() : parent.getDefaultValue()); + parent.isValueExplicitlySet() ? parent.asMaybe() : parent.getDefaultValue()); result.setValue(resolvedValue.getWithoutError()); return ReferenceWithError.newInstanceThrowingError(result, resolvedValue.getError()); } @@ -128,6 +137,8 @@ public class BasicConfigInheritance implements ConfigInheritance { return resolveWithParentCustomStrategy(local, parent, context); } + /** Provided for subclasses to override. Invoked by {@link #resolveWithParent(ConfigValueAtContainer, ConfigValueAtContainer, org.apache.brooklyn.config.ConfigInheritance.ConfigInheritanceContext)} + * if there is a value for the parent and the child. Default implementation throws {@link IllegalStateException}. */ protected <TContainer, TValue> ReferenceWithError<ConfigValueAtContainer<TContainer, TValue>> resolveWithParentCustomStrategy( ConfigValueAtContainer<TContainer, TValue> local, ConfigValueAtContainer<TContainer, TValue> parent, ConfigInheritanceContext context) { @@ -162,5 +173,9 @@ public class BasicConfigInheritance implements ConfigInheritance { public boolean getUseLocalDefaultValue() { return useLocalDefaultValue; } - + + @Override + public String toString() { + return super.toString()+"[reinherit="+isReinherited()+"; strategy="+getConflictResolutionStrategy()+"; useLocal="+getUseLocalDefaultValue()+"]"; + } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 6359907..cbc8658 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 @@ -47,8 +47,7 @@ public class ConfigKeys { private static final Logger log = LoggerFactory.getLogger(ConfigKeys.class); - public enum InheritanceContext implements ConfigInheritanceContext - { TYPE_DEFINITION, RUNTIME_MANAGEMENT } + public enum InheritanceContext implements ConfigInheritanceContext { TYPE_DEFINITION, RUNTIME_MANAGEMENT } public static <T> ConfigKey<T> newConfigKey(Class<T> type, String name) { return new BasicConfigKey<T>(type, name); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 e964d24..8716cec 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 @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.core.config.internal; +import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -68,15 +69,19 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i private static final Logger LOG = LoggerFactory.getLogger(AbstractConfigMapImpl.class); - @SuppressWarnings("deprecation") + @Deprecated /** @deprecated since 0.10.0 - see method which uses it */ protected final transient org.apache.brooklyn.core.entity.internal.ConfigMapViewWithStringKeys mapViewWithStringKeys = new org.apache.brooklyn.core.entity.internal.ConfigMapViewWithStringKeys(this); + // TODO make final when not working with previously serialized instances + // (we shouldn't be, but just in case!) protected TContainer bo; /** * 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. + * + * All iterator accesses (eg copying) should be synchronized. See {@link #putAllOwnConfigIntoSafely(Map)}. */ protected final Map<ConfigKey<?>,Object> ownConfig; @@ -117,9 +122,20 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i @Override public Map<ConfigKey<?>,Object> getAllConfigLocalRaw() { Map<ConfigKey<?>,Object> result = new LinkedHashMap<ConfigKey<?>,Object>(); - result.putAll(ownConfig); + putAllOwnConfigIntoSafely(result); return Collections.unmodifiableMap(result); } + protected Map<ConfigKey<?>, Object> putAllOwnConfigIntoSafely(Map<ConfigKey<?>, Object> result) { + synchronized (ownConfig) { + result.putAll(ownConfig); + } + return result; + } + protected ConfigBag putAllOwnConfigIntoSafely(ConfigBag bag) { + synchronized (ownConfig) { + return bag.putAll(ownConfig); + } + } /** an immutable copy of the config visible at this entity, local and inherited (preferring local) */ @Override @Deprecated @@ -127,14 +143,14 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i Map<ConfigKey<?>,Object> result = new LinkedHashMap<ConfigKey<?>,Object>(); if (getParent()!=null) result.putAll( getParentInternal().config().getInternalConfigMap().getAllConfig() ); - result.putAll(ownConfig); + putAllOwnConfigIntoSafely(result); return Collections.unmodifiableMap(result); } /** Creates an immutable copy of the config visible at this entity, local and inherited (preferring local), including those that did not match config keys */ @Deprecated public ConfigBag getAllConfigBag() { - ConfigBag result = ConfigBag.newInstance().putAll(ownConfig); + ConfigBag result = putAllOwnConfigIntoSafely(ConfigBag.newInstance()); if (getParent()!=null) { result.putIfAbsent( ((AbstractConfigMapImpl<?>)getParentInternal().config().getInternalConfigMap()).getAllConfigBag() ); @@ -144,7 +160,7 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i /** As {@link #getLocalConfigRaw()} but in a {@link ConfigBag} for convenience */ public ConfigBag getLocalConfigBag() { - return ConfigBag.newInstance().putAll(ownConfig).seal(); + return putAllOwnConfigIntoSafely(ConfigBag.newInstance()).seal(); } public Object setConfig(ConfigKey<?> key, Object v) { @@ -170,10 +186,6 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i @SuppressWarnings("unchecked") public void putAll(Map<?,?> vals) { -// ConfigBag ownConfigBag = ConfigBag.newInstance().putAll(vals); -// ownConfig.putAll(ownConfigBag.getAllConfigAsConfigKeyMap()); - // below seems more straightforward; should be the same. - // potential problem if clash of config key types? for (Map.Entry<?, ?> entry : vals.entrySet()) { if (entry.getKey()==null) throw new IllegalArgumentException("Cannot put null key into "+this); @@ -257,12 +269,14 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i return BasicConfigInheritance.OVERWRITE; } + @Override public <T> ReferenceWithError<ConfigValueAtContainer<TContainer,T>> getConfigAndContainer(ConfigKey<T> key) { return getConfigImpl(key, false); } protected abstract TContainer getParentOfContainer(TContainer container); + @Nullable protected final <T> ConfigKey<T> getKeyAtContainer(TContainer container, ConfigKey<T> queryKey) { if (container==null) return null; @SuppressWarnings("unchecked") @@ -271,10 +285,17 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i } @Nullable protected abstract <T> ConfigKey<?> getKeyAtContainerImpl(@Nonnull TContainer container, ConfigKey<T> queryKey); + protected abstract Collection<ConfigKey<?>> getKeysAtContainer(@Nonnull TContainer container); protected Maybe<Object> getRawValueAtContainer(TContainer container, ConfigKey<? extends Object> configKey) { return ((BrooklynObjectInternal)container).config().getInternalConfigMap().getConfigLocalRaw(configKey); } + /** finds the value at the given container/key, taking in to account any resolution expected by the key (eg for map keys). + * the input is the value in the {@link #ownConfig} map taken from {@link #getRawValueAtContainer(BrooklynObject, ConfigKey)}, + * but the key may have other plans. + * current impl just uses the key to extract again which is a little bit wasteful but simpler. + * <p> + * this does not do any resolution with respect to ancestors. */ protected Maybe<Object> resolveRawValueFromContainer(TContainer container, ConfigKey<?> key, Object value) { Map<ConfigKey<?>, Object> oc = ((AbstractConfigMapImpl<?>) ((BrooklynObjectInternal)container).config().getInternalConfigMap()).ownConfig; if (key instanceof ConfigKeySelfExtracting) { @@ -359,6 +380,7 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i } } + @Override public List<ConfigValueAtContainer<TContainer,?>> getConfigAllInheritedRaw(ConfigKey<?> queryKey) { List<ConfigValueAtContainer<TContainer, ?>> result = MutableList.of(); TContainer c = getContainer(); @@ -375,20 +397,24 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i if (last!=null && !currentInheritance.considerParent(last, next, context)) break; - currentInheritance = ConfigInheritances.findInheritance(next.getKey(), InheritanceContext.RUNTIME_MANAGEMENT, currentInheritance); - if (count>0 && !currentInheritance.isReinheritable(next, context)) break; + ConfigInheritance currentInheritanceExplicit = ConfigInheritances.findInheritance(next.getKey(), InheritanceContext.RUNTIME_MANAGEMENT, null); + if (currentInheritanceExplicit!=null) { + if (count>0 && !currentInheritanceExplicit.isReinheritable(next, context)) break; + currentInheritance = currentInheritanceExplicit; + } if (next.isValueExplicitlySet()) result.add(0, next); last = next; c = getParentOfContainer(c); + count++; } return result; } @Override - public Set<ConfigKey<?>> findKeys(Predicate<ConfigKey<?>> filter) { + public Set<ConfigKey<?>> findKeys(Predicate<? super ConfigKey<?>> filter) { MutableSet<ConfigKey<?>> result = MutableSet.of(); result.addAll(Iterables.filter(ownConfig.keySet(), filter)); // due to set semantics local should be added first, it prevents equal items from parent from being added on top @@ -398,6 +424,7 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i return result; } + @Override @SuppressWarnings("unchecked") public ReferenceWithError<ConfigValueAtContainer<TContainer,?>> getConfigInheritedRaw(ConfigKey<?> key) { return (ReferenceWithError<ConfigValueAtContainer<TContainer,?>>) (ReferenceWithError<?>) getConfigImpl(key, true); @@ -414,19 +441,27 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i } @Override public Map<ConfigKey<?>, ReferenceWithError<ConfigValueAtContainer<TContainer, ?>>> getAllConfigInheritedRawWithErrors() { - return getSelectedConfigInheritedRaw(false); + return getSelectedConfigInheritedRaw(null, false); } + @Override public Map<ConfigKey<?>,ReferenceWithError<ConfigValueAtContainer<TContainer,?>>> getAllReinheritableConfigRaw() { - return getSelectedConfigInheritedRaw(true); + return getSelectedConfigInheritedRaw(null, true); } - protected Map<ConfigKey<?>,ReferenceWithError<ConfigValueAtContainer<TContainer,?>>> getSelectedConfigInheritedRaw(boolean onlyReinheritable) { + protected Map<ConfigKey<?>,ReferenceWithError<ConfigValueAtContainer<TContainer,?>>> getSelectedConfigInheritedRaw(Map<ConfigKey<?>,ConfigKey<?>> knownKeys, boolean onlyReinheritable) { + Map<ConfigKey<?>, ConfigKey<?>> knownKeysOnType = MutableMap.of(); + for (ConfigKey<?> k: getKeysAtContainer(getContainer())) knownKeysOnType.put(k, k); + + Map<ConfigKey<?>, ConfigKey<?>> knownKeysIncludingDescendants = MutableMap.copyOf(knownKeys); + knownKeysIncludingDescendants.putAll(knownKeysOnType); + Map<ConfigKey<?>,ReferenceWithError<ConfigValueAtContainer<TContainer,?>>> parents = MutableMap.of(); if (getParent()!=null) { @SuppressWarnings("unchecked") Map<ConfigKey<?>,ReferenceWithError<ConfigValueAtContainer<TContainer,?>>> po = (Map<ConfigKey<?>,ReferenceWithError<ConfigValueAtContainer<TContainer,?>>>) (Map<?,?>) - getParentInternal().config().getInternalConfigMap().getAllReinheritableConfigRaw(); + ((AbstractConfigMapImpl<?>)getParentInternal().config().getInternalConfigMap()) + .getSelectedConfigInheritedRaw(knownKeysIncludingDescendants, true); parents.putAll(po); } @@ -434,34 +469,48 @@ public abstract class AbstractConfigMapImpl<TContainer extends BrooklynObject> i Map<ConfigKey<?>,ReferenceWithError<ConfigValueAtContainer<TContainer,?>>> result = MutableMap.of(); - for (ConfigKey<?> k: local.keySet()) { - Object v = local.get(k); - ReferenceWithError<ConfigValueAtContainer<TContainer, ?>> vpr = parents.remove(k); + for (ConfigKey<?> kSet: MutableSet.copyOf(local.keySet()).putAll(parents.keySet())) { + Maybe<Object> localValue = local.containsKey(kSet) ? Maybe.ofAllowingNull(local.get(kSet)) : Maybe.absent(); + ReferenceWithError<ConfigValueAtContainer<TContainer, ?>> vpr = parents.remove(kSet); + @SuppressWarnings("unchecked") ConfigValueAtContainer<TContainer, Object> vp = vpr==null ? null : (ConfigValueAtContainer<TContainer,Object>) vpr.getWithoutError(); - ConfigInheritance inh = ConfigInheritances.findInheritance(k, InheritanceContext.RUNTIME_MANAGEMENT, getDefaultRuntimeInheritance()); - ConfigValueAtContainer<TContainer,Object> vl = new BasicConfigValueAtContainer<TContainer,Object>(getContainer(), k, Maybe.ofAllowingNull(v)); + + @Nullable ConfigKey<?> kOnType = knownKeysOnType.get(kSet); + @Nullable ConfigKey<?> kTypeOrDescendant = knownKeysIncludingDescendants.get(kSet); + assert kOnType==null || kOnType==kTypeOrDescendant; + + // if no key on type, we must use any descendant declared key here + // so that the correct descendant conflict resolution strategy is applied + ConfigInheritance inhHereOrDesc = ConfigInheritances.findInheritance(kTypeOrDescendant, InheritanceContext.RUNTIME_MANAGEMENT, getDefaultRuntimeInheritance()); + + // however for the purpose of qualifying we must not give any key except what is exactly declared here, + // else reinheritance will be incorrectly deduced + ConfigValueAtContainer<TContainer,Object> vl = new BasicConfigValueAtContainer<TContainer,Object>(getContainer(), kOnType, localValue); + ReferenceWithError<ConfigValueAtContainer<TContainer, Object>> vlr = null; - if (inh.considerParent(vl, vp, InheritanceContext.RUNTIME_MANAGEMENT)) { - vlr = inh.resolveWithParent(vl, vp, InheritanceContext.RUNTIME_MANAGEMENT); + if (inhHereOrDesc.considerParent(vl, vp, InheritanceContext.RUNTIME_MANAGEMENT)) { + vlr = inhHereOrDesc.resolveWithParent(vl, vp, InheritanceContext.RUNTIME_MANAGEMENT); } else { // no need to consider parent, just take vl + if (!vl.isValueExplicitlySet()) { + // inherited parent value NEVER_INHERIT ie overwritten by default value or null here + continue; + } vlr = ReferenceWithError.newInstanceWithoutError(vl); } if (onlyReinheritable) { - if (ConfigInheritances.findInheritance(k, InheritanceContext.RUNTIME_MANAGEMENT, getDefaultRuntimeInheritance()) - .isReinheritable(vl, InheritanceContext.RUNTIME_MANAGEMENT)) { - // continue - } else { + ConfigInheritance inhHere = ConfigInheritances.findInheritance(kOnType, InheritanceContext.RUNTIME_MANAGEMENT, getDefaultRuntimeInheritance()); + if (localValue.isAbsent() && !inhHere.isReinheritable(vl, InheritanceContext.RUNTIME_MANAGEMENT)) { // skip this one continue; } } @SuppressWarnings("unchecked") ReferenceWithError<ConfigValueAtContainer<TContainer, ?>> vlro = (ReferenceWithError<ConfigValueAtContainer<TContainer, ?>>) (ReferenceWithError<?>) vlr; - result.put(k, vlro); + result.put(kSet, vlro); } - result.putAll(parents); + assert parents.isEmpty(); return result; } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 index fec13af..f72374e 100644 --- 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 @@ -18,27 +18,30 @@ */ package org.apache.brooklyn.core.config.internal; +import javax.annotation.Nullable; + 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; +import com.google.common.base.Preconditions; public class LazyContainerAndKeyValue<TContainer,TValue> implements ConfigValueAtContainer<TContainer,TValue> { - private final TContainer container; - private final ConfigKey<TValue> key; + @Nullable private final TContainer container; + @Nullable private final ConfigKey<TValue> key; private final Function<TContainer,Maybe<Object>> lookupResolutionFunction; private final Function<Maybe<Object>,Maybe<TValue>> conversionFunction; private Maybe<TValue> resolved; - public LazyContainerAndKeyValue(ConfigKey<TValue> key, TContainer container, + public LazyContainerAndKeyValue(@Nullable ConfigKey<TValue> key, @Nullable TContainer container, Function<TContainer, Maybe<Object>> lookupResolutionFunction, Function<Maybe<Object>, Maybe<TValue>> conversionFunction) { this.key = key; this.container = container; - this.lookupResolutionFunction = lookupResolutionFunction; - this.conversionFunction = conversionFunction; + this.lookupResolutionFunction = Preconditions.checkNotNull(lookupResolutionFunction); + this.conversionFunction = Preconditions.checkNotNull(conversionFunction); } protected synchronized Maybe<TValue> resolve() { @@ -81,4 +84,10 @@ public class LazyContainerAndKeyValue<TContainer,TValue> implements ConfigValueA if (key==null || !key.hasDefaultValue()) return Maybe.absent(); return conversionFunction.apply(Maybe.of((Object)key.getDefaultValue())); } + + @Override + public String toString() { + return super.toString()+"[key="+key+"; container="+container+"]"; + } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 400694e..480e1ed 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 @@ -21,14 +21,17 @@ package org.apache.brooklyn.core.entity.internal; import static com.google.common.base.Preconditions.checkNotNull; 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.api.objs.BrooklynObject; +import org.apache.brooklyn.api.objs.EntityAdjunct; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.internal.AbstractConfigMapImpl; import org.apache.brooklyn.core.entity.EntityInternal; +import org.apache.brooklyn.core.objs.AbstractEntityAdjunct; import org.apache.brooklyn.core.objs.BrooklynObjectInternal.ConfigurationSupportInternal; import org.apache.brooklyn.util.guava.Maybe; import org.slf4j.Logger; @@ -103,6 +106,11 @@ public class EntityConfigMap extends AbstractConfigMapImpl<Entity> { return container.getEntityType().getConfigKey(queryKey.getName()); } + @Override + protected Set<ConfigKey<?>> getKeysAtContainer(Entity container) { + return container.getEntityType().getConfigKeys(); + } + @Override @Deprecated public EntityConfigMap submap(Predicate<ConfigKey<?>> filter) { EntityConfigMap m = new EntityConfigMap(getEntity(), Maps.<ConfigKey<?>, Object>newLinkedHashMap()); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynProperties.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynProperties.java b/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynProperties.java index 1bed084..1cfbcbc 100644 --- a/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynProperties.java +++ b/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynProperties.java @@ -311,11 +311,13 @@ public interface BrooklynProperties extends Map, StringConfigMap { public Maybe<Object> getConfigRaw(ConfigKey<?> key); - /** Inheritance is ignored here. Preferable to use {@link #getConfigRaw(ConfigKey)}. */ + /** Inheritance is ignored here. Preferable to use {@link #getConfigRaw(ConfigKey)}. + * @deprecated since 0.10.0 the second parameter is ignored for {@link BrooklynProperties}; use {@link #getConfigLocalRaw(ConfigKey)}. */ + @Deprecated // and confirmed no usages apart from internal @Override public Maybe<Object> getConfigRaw(ConfigKey<?> key, boolean includeInherited); - @Override + @Override @Deprecated public Map<ConfigKey<?>, Object> getAllConfig(); @Override http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 03fb13d..89cb7d2 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 @@ -471,7 +471,7 @@ public class BrooklynPropertiesImpl extends LinkedHashMap implements BrooklynPro } @Override - public Set<ConfigKey<?>> findKeys(Predicate<ConfigKey<?>> filter) { + public Set<ConfigKey<?>> findKeys(Predicate<? super ConfigKey<?>> filter) { Set<ConfigKey<?>> result = new LinkedHashSet<ConfigKey<?>>(); for (Object entry: entrySet()) { ConfigKey<?> k = new BasicConfigKey<Object>(Object.class, ""+((Map.Entry)entry).getKey()); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 076443a..9b38946 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 @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.core.location.internal; +import java.util.Collection; import java.util.Map; import javax.annotation.Nonnull; @@ -94,6 +95,11 @@ public class LocationConfigMap extends AbstractConfigMapImpl<Location> { return ((AbstractLocation)container).getLocationTypeInternal().getConfigKey(queryKey.getName()); } + @Override + protected Collection<ConfigKey<?>> getKeysAtContainer(Location container) { + return ((AbstractLocation)container).getLocationTypeInternal().getConfigKeys().values(); + } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 69f2423..1bc737e 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 @@ -131,7 +131,7 @@ public class DeferredBrooklynProperties implements BrooklynProperties { return getConfigRaw(key, true); } - @Override + @Override @Deprecated public Maybe<Object> getConfigRaw(ConfigKey<?> key, boolean includeInherited) { Maybe<Object> result = delegate.getConfigRaw(key, includeInherited); return (result.isPresent()) ? Maybe.of(transform(key, result.get())) : Maybe.absent(); @@ -203,7 +203,7 @@ public class DeferredBrooklynProperties implements BrooklynProperties { return new DeferredBrooklynProperties(submap, mgmt); } @Override - public Set<ConfigKey<?>> findKeys(Predicate<ConfigKey<?>> filter) { + public Set<ConfigKey<?>> findKeys(Predicate<? super ConfigKey<?>> filter) { return delegate.findKeys(filter); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractConfigurationSupportInternal.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractConfigurationSupportInternal.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractConfigurationSupportInternal.java index 402abb8..1b87d3c 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractConfigurationSupportInternal.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractConfigurationSupportInternal.java @@ -230,7 +230,7 @@ public abstract class AbstractConfigurationSupportInternal implements BrooklynOb } @Override - public Set<ConfigKey<?>> findKeys(Predicate<ConfigKey<?>> filter) { + public Set<ConfigKey<?>> findKeys(Predicate<? super ConfigKey<?>> filter) { return getConfigsInternal().findKeys(filter); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 fc13cd8..602d943 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 @@ -19,6 +19,7 @@ package org.apache.brooklyn.core.objs; import java.util.Map; +import java.util.Set; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.mgmt.ExecutionContext; @@ -91,5 +92,10 @@ public class AdjunctConfigMap extends AbstractConfigMapImpl<EntityAdjunct> { protected <T> ConfigKey<?> getKeyAtContainerImpl(EntityAdjunct container, ConfigKey<T> queryKey) { return ((AbstractEntityAdjunct)container).getAdjunctType().getConfigKey(queryKey.getName()); } + + @Override + protected Set<ConfigKey<?>> getKeysAtContainer(EntityAdjunct container) { + return ((AbstractEntityAdjunct)container).getAdjunctType().getConfigKeys(); + } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/core/src/main/java/org/apache/brooklyn/core/objs/BasicConfigurableObject.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BasicConfigurableObject.java b/core/src/main/java/org/apache/brooklyn/core/objs/BasicConfigurableObject.java index d3e29b6..0e9bd87 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/BasicConfigurableObject.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/BasicConfigurableObject.java @@ -123,7 +123,7 @@ public class BasicConfigurableObject implements Configurable, Identifiable, Mana } @Override - public Set<ConfigKey<?>> findKeys(Predicate<ConfigKey<?>> predicate) { + public Set<ConfigKey<?>> findKeys(Predicate<? super ConfigKey<?>> predicate) { return MutableSet.copyOf(Iterables.filter(config.getAllConfigAsConfigKeyMap().keySet(), predicate)); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 d6a2f9f..ed44096 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 @@ -18,9 +18,14 @@ */ package org.apache.brooklyn.core.entity; +import java.util.List; +import java.util.Map; + import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.config.ConfigMap.ConfigMapWithInheritance; +import org.apache.brooklyn.config.ConfigValueAtContainer; import org.apache.brooklyn.core.config.BasicConfigInheritance; import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.core.entity.EntityConfigTest.MyOtherEntity; @@ -28,9 +33,14 @@ import org.apache.brooklyn.core.entity.EntityConfigTest.MyOtherEntityImpl; import org.apache.brooklyn.core.sensor.AttributeSensorAndConfigKey; import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.IntegerAttributeSensorAndConfigKey; import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; +import org.apache.brooklyn.util.collections.MutableList; +import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.collections.MutableSet; import org.testng.Assert; import org.testng.annotations.Test; +import com.google.common.collect.Iterables; + public class ConfigEntityInheritanceTest extends BrooklynAppUnitTestSupport { protected void checkKeys(Entity entity2, Integer value) { @@ -144,14 +154,23 @@ public class ConfigEntityInheritanceTest extends BrooklynAppUnitTestSupport { } // -------------------- + + @Override + protected Boolean shouldSkipOnBoxBaseDirResolution() { + return null; //because it adds extra config we do not want to test for + } - @Test - public void testConfigKeysInheritance() throws Exception { + protected Entity setupBasicInheritanceTest() { app.config().set(MyEntityWithPartiallyHeritableConfig.HERITABLE_BY_DEFAULT, "heritable"); app.config().set(MyEntityWithPartiallyHeritableConfig.ALWAYS_HERITABLE, "always_heritable"); app.config().set(MyEntityWithPartiallyHeritableConfig.NEVER_INHERIT, "uninheritable"); app.config().set(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE, "maybe"); - Entity child = app.addChild(EntitySpec.create(MyEntityWithPartiallyHeritableConfig.class)); + return app.addChild(EntitySpec.create(MyEntityWithPartiallyHeritableConfig.class)); + } + + @Test + public void testConfigKeysInheritance() throws Exception { + Entity child = setupBasicInheritanceTest(); Assert.assertNotNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.HERITABLE_BY_DEFAULT)); Assert.assertNotNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.ALWAYS_HERITABLE)); @@ -163,6 +182,50 @@ public class ConfigEntityInheritanceTest extends BrooklynAppUnitTestSupport { Assert.assertNull(child.getConfig(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE)); } + @SuppressWarnings("unchecked") + @Test + public void testConfigKeysAllInheritanceMethods() throws Exception { + Entity child = setupBasicInheritanceTest(); + + Assert.assertEquals( ((EntityInternal)child).config().getInternalConfigMap().getAllConfigLocalRaw(), MutableMap.of() ); + + Assert.assertEquals( ((EntityInternal)child).config().getInternalConfigMap().getAllConfigInheritedRawValuesIgnoringErrors(), + MutableMap.of().add(MyEntityWithPartiallyHeritableConfig.HERITABLE_BY_DEFAULT, "heritable") + .add(MyEntityWithPartiallyHeritableConfig.ALWAYS_HERITABLE, "always_heritable") + .add(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE, "maybe") ); + + Map<ConfigKey<?>, ?> rawReinherit = ((EntityInternal)child).config().getInternalConfigMap().getAllReinheritableConfigRaw(); + Assert.assertEquals(rawReinherit.keySet(), MutableSet.of( + MyEntityWithPartiallyHeritableConfig.HERITABLE_BY_DEFAULT, + MyEntityWithPartiallyHeritableConfig.ALWAYS_HERITABLE)); + + + // check the hierarchical list of values is correct + + List<ConfigValueAtContainer<Entity, ?>> rawHierarchy = ((ConfigMapWithInheritance<Entity>)((EntityInternal)child).config().getInternalConfigMap()). + getConfigAllInheritedRaw(MyEntityWithPartiallyHeritableConfig.ALWAYS_HERITABLE); + Assert.assertEquals(rawHierarchy.size(), 1); + Assert.assertEquals(Iterables.getOnlyElement(rawHierarchy).getContainer(), app); + + rawHierarchy = ((ConfigMapWithInheritance<Entity>)((EntityInternal)child).config().getInternalConfigMap()). + getConfigAllInheritedRaw(MyEntityWithPartiallyHeritableConfig.NEVER_INHERIT); + Assert.assertEquals(rawHierarchy, MutableList.of()); + + + // and try with and without NOT_RE declared at the app + + rawHierarchy = ((ConfigMapWithInheritance<Entity>)((EntityInternal)child).config().getInternalConfigMap()). + getConfigAllInheritedRaw(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE); + Assert.assertEquals(rawHierarchy.size(), 1); + Assert.assertEquals(Iterables.getOnlyElement(rawHierarchy).getContainer(), app); + + app.getMutableEntityType().addConfigKey(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE); + + rawHierarchy = ((ConfigMapWithInheritance<Entity>)((EntityInternal)child).config().getInternalConfigMap()). + getConfigAllInheritedRaw(MyEntityWithPartiallyHeritableConfig.NOT_REINHERITABLE); + Assert.assertEquals(rawHierarchy, MutableList.of()); + } + public static class MyEntityWithPartiallyHeritableConfig extends AbstractEntity { 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(); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppUnitTestSupport.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppUnitTestSupport.java b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppUnitTestSupport.java index cbe39d0..6a79a0f 100644 --- a/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppUnitTestSupport.java +++ b/core/src/test/java/org/apache/brooklyn/core/test/BrooklynAppUnitTestSupport.java @@ -38,13 +38,15 @@ public class BrooklynAppUnitTestSupport extends BrooklynMgmtUnitTestSupport { setUpApp(); } - protected boolean shouldSkipOnBoxBaseDirResolution() { + /** set null not to set, or a boolean to set explicitly; default true */ + protected Boolean shouldSkipOnBoxBaseDirResolution() { return true; } protected void setUpApp() { - EntitySpec<TestApplication> appSpec = EntitySpec.create(TestApplication.class) - .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, shouldSkipOnBoxBaseDirResolution()); + EntitySpec<TestApplication> appSpec = EntitySpec.create(TestApplication.class); + if (shouldSkipOnBoxBaseDirResolution()!=null) + appSpec.configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, shouldSkipOnBoxBaseDirResolution()); app = mgmt.getEntityManager().createEntity(appSpec); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/core/src/test/java/org/apache/brooklyn/util/core/internal/FlagUtilsTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/util/core/internal/FlagUtilsTest.java b/core/src/test/java/org/apache/brooklyn/util/core/internal/FlagUtilsTest.java index 792b441..9180183 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/internal/FlagUtilsTest.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/internal/FlagUtilsTest.java @@ -407,7 +407,7 @@ public class FlagUtilsTest { } @Override - public Set<ConfigKey<?>> findKeys(Predicate<ConfigKey<?>> predicate) { + public Set<ConfigKey<?>> findKeys(Predicate<? super ConfigKey<?>> predicate) { return MutableSet.copyOf(Iterables.filter(bag.getAllConfigAsConfigKeyMap().keySet(), predicate)); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 dffa548..5b96a7b 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 @@ -54,6 +54,7 @@ public interface ConfigInheritance extends Serializable { /** @deprecated since 0.10.0 see implementations of this interface */ @Deprecated public static final ConfigInheritance DEEP_MERGE = new Legacy.Merged(); + /** @deprecated since 0.10.0 more complex inheritance conditions now require other methods */ @Deprecated InheritanceMode isInherited(ConfigKey<?> key, Object from, Object to); @@ -65,7 +66,8 @@ public interface ConfigInheritance extends Serializable { * If there is a {@link ConfigInheritance} defined at this node, * this method must be called on that instance and that instance only. * In that case it is an error to invoke this method on any other {@link ConfigInheritance} instance. - * If there is not one, the config generally should be considered reinheritable. + * If there is not one, the config generally should be considered reinheritable; + * callers will typically not invoke this method from a descendant inheritance context. * <p> * Consumers will typically find the methods in {@link ConfigInheritances} more convenient. */ public <TContainer,TValue> boolean isReinheritable( http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritances.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritances.java b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritances.java index 95d80ff..bac207d 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritances.java +++ b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigInheritances.java @@ -20,6 +20,7 @@ package org.apache.brooklyn.config; import java.util.Iterator; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.brooklyn.config.ConfigInheritance.ConfigInheritanceContext; @@ -116,28 +117,38 @@ public class ConfigInheritances { public static class BasicConfigValueAtContainer<TContainer,TValue> implements ConfigValueAtContainer<TContainer,TValue> { - TContainer container = null; - Maybe<? extends TValue> value = Maybe.absent(); + @Nullable TContainer container = null; + @Nonnull Maybe<? extends TValue> value = Maybe.absent(); boolean valueWasExplicitlySet = false; - ConfigKey<? extends TValue> key = null; - Maybe<TValue> defaultValue = null; + @Nullable ConfigKey<? extends TValue> key = null; + @Nullable Maybe<TValue> defaultValue = null; public BasicConfigValueAtContainer() {} public BasicConfigValueAtContainer(ConfigValueAtContainer<TContainer,TValue> toCopy) { this(toCopy.getContainer(), toCopy.getKey(), toCopy.asMaybe(), toCopy.isValueExplicitlySet(), toCopy.getDefaultValue()); } - public BasicConfigValueAtContainer(TContainer container, ConfigKey<? extends TValue> key, Maybe<? extends TValue> value) { + public BasicConfigValueAtContainer(@Nullable TContainer container, @Nullable ConfigKey<? extends TValue> key, + @Nullable Maybe<? extends TValue> value) { this(container, key, value, value.isPresent()); } - public BasicConfigValueAtContainer(TContainer container, ConfigKey<? extends TValue> key, Maybe<? extends TValue> value, boolean isValueSet) { + public BasicConfigValueAtContainer(@Nullable TContainer container, @Nullable ConfigKey<? extends TValue> key, @Nullable Maybe<? extends TValue> value, boolean isValueSet) { this(container, key, value, isValueSet, null); } - public BasicConfigValueAtContainer(TContainer container, ConfigKey<? extends TValue> key, Maybe<? extends TValue> value, boolean isValueSet, Maybe<TValue> defaultValue) { + /** Creates an instance, configuring all parameters. + * + * @param container May be null as per contract. + * @param key May be null as per contract. + * @param value Null means always to take {@link #getDefaultValue()}; if absent and isValueSet is false, it will also take {@link #getDefaultValue()}. + * @param isValueSet + * @param defaultValue Null means to take a default value from the key ({@link #getKey()}), otherwise this {@link Maybe} will be preferred to that value + * (even if absent). + */ + public BasicConfigValueAtContainer(@Nullable TContainer container, @Nullable ConfigKey<? extends TValue> key, @Nullable Maybe<? extends TValue> value, boolean isValueSet, @Nullable Maybe<TValue> defaultValue) { this.container = container; this.key = key; this.valueWasExplicitlySet = isValueSet; this.defaultValue = defaultValue; - this.value = value!=null && (value.isPresent() || isValueSet || key==null || !key.hasDefaultValue()) ? value + this.value = value!=null && (value.isPresent() || isValueSet || getDefaultValue().isPresent()) ? value : getDefaultValue(); } @@ -166,6 +177,10 @@ public class ConfigInheritances { return key!=null && key.hasDefaultValue() ? Maybe.ofAllowingNull((TValue) key.getDefaultValue()) : Maybe.<TValue>absent(); } + @Override + public String toString() { + return super.toString()+"[key="+key+"; value="+value+"; container="+container+"]"; + } } /** determine whether a key is reinheritable from the point in the given inheritance hierarchy where it is introduced; http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 7b0b576..dd805d1 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 @@ -81,7 +81,7 @@ public interface ConfigMap { public ConfigMap submap(Predicate<ConfigKey<?>> filter); /** returns all keys matching the given filter predicate; see ConfigPredicates for common predicates */ - public Set<ConfigKey<?>> findKeys(Predicate<ConfigKey<?>> filter); + public Set<ConfigKey<?>> findKeys(Predicate<? super ConfigKey<?>> filter); /** returns a read-only map view which has string keys (corresponding to the config key names); * callers encouraged to use the typed keys (and so not use this method), http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/8156322b/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 index a4c60ca..59168a3 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java +++ b/utils/common/src/main/java/org/apache/brooklyn/config/ConfigValueAtContainer.java @@ -18,6 +18,9 @@ */ package org.apache.brooklyn.config; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import org.apache.brooklyn.util.guava.Maybe; import com.google.common.base.Supplier; @@ -25,19 +28,24 @@ import com.google.common.base.Supplier; public interface ConfigValueAtContainer<TContainer,TValue> extends Supplier<TValue> { /** Returns the value for this key, or null. Technically this returns {@link #asMaybe()} or null. */ - TValue get(); + @Nullable TValue get(); /** Absent if no value can be found, typically meaning no default value, but in raw value lookups it may ignore default values. */ - Maybe<? extends TValue> asMaybe(); + @Nonnull Maybe<? extends TValue> asMaybe(); /** If false, any 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(); + /** The container where the value was found (possibly an ancestor of the queried object). + * This may be null in internal uses to indicate an anonymous query. */ + @Nullable TContainer getContainer(); - ConfigKey<? extends TValue> getKey(); + /** The key whose value is being held here. + * <p> + * This may be null when working in a context where the query key is widely known + * to indicate that no key was defined at this container. */ + @Nullable ConfigKey<? extends TValue> getKey(); /** The default value on the key, if available and permitted, * possibly coerced or resolved in the scope of {@link #getContainer()}, * and possibly absent e.g. in raw value lookups */ - Maybe<TValue> getDefaultValue(); + @Nonnull Maybe<TValue> getDefaultValue(); }