You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2017/02/15 18:30:56 UTC
[03/28] brooklyn-server git commit: migrate config inheritance to new
classes
migrate config inheritance to new classes
pioneers use of `readResolve` that actually works brilliantly out of the box due to xstream
also tidying `BasicConfigInheritance` and adding a placeholder (not used yet)
for resolving ancestor defaults
includes tests for config inheritance serialization
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/53ae1c61
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/53ae1c61
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/53ae1c61
Branch: refs/heads/master
Commit: 53ae1c611c736ee572801f840785266690531da9
Parents: 9f8a3aa
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Nov 24 10:56:46 2016 +0000
Committer: Alex Heneveld <al...@Alexs-MacBook-Pro.local>
Committed: Tue Dec 6 10:05:21 2016 +0000
----------------------------------------------------------------------
.../core/config/BasicConfigInheritance.java | 255 +++++++++++++++++--
.../util/core/xstream/ClassRenamingMapper.java | 4 +-
.../rebind/RebindConfigInheritanceTest.java | 145 +++++++++++
.../core/mgmt/rebind/RebindOptions.java | 6 +
.../core/mgmt/rebind/RebindTestFixture.java | 1 -
...RebindWithDeserializingClassRenamesTest.java | 35 ++-
.../config-inheritance-basic-2016-10-wj5s8u9h73 | 50 ++++
.../config-inheritance-basic-2016-11-kmpez5fznt | 46 ++++
...nfig-inheritance-prebasic-2016-07-toruf2wxg4 | 137 ++++++++++
.../brooklyn/config/ConfigInheritance.java | 29 ++-
10 files changed, 661 insertions(+), 47 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/53ae1c61/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 51f2e7a..dd3b336 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
@@ -18,8 +18,12 @@
*/
package org.apache.brooklyn.core.config;
+import java.lang.reflect.Field;
+import java.util.Arrays;
import java.util.Map;
+import java.util.Objects;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.brooklyn.config.ConfigInheritance;
@@ -28,51 +32,176 @@ import org.apache.brooklyn.config.ConfigInheritances.BasicConfigValueAtContainer
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.config.ConfigValueAtContainer;
import org.apache.brooklyn.util.collections.CollectionMerger;
+import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.exceptions.ReferenceWithError;
import org.apache.brooklyn.util.guava.Maybe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+@SuppressWarnings("serial")
public class BasicConfigInheritance implements ConfigInheritance {
+ private static final Logger log = LoggerFactory.getLogger(BasicConfigInheritance.class);
+
private static final long serialVersionUID = -5916548049057961051L;
public static final String CONFLICT_RESOLUTION_STRATEGY_DEEP_MERGE = "deep_merge";
public static final String CONFLICT_RESOLUTION_STRATEGY_OVERWRITE = "overwrite";
+ public static abstract class DelegatingConfigInheritance implements ConfigInheritance {
+ protected abstract ConfigInheritance getDelegate();
+
+ @Override @Deprecated public InheritanceMode isInherited(ConfigKey<?> key, Object from, Object to) {
+ return getDelegate().isInherited(key, from, to);
+ }
+ @Override public <TContainer, TValue> boolean isReinheritable(ConfigValueAtContainer<TContainer, TValue> parent, ConfigInheritanceContext context) {
+ return getDelegate().isReinheritable(parent, context);
+ }
+ @Override public <TContainer, TValue> boolean considerParent(ConfigValueAtContainer<TContainer, TValue> local, ConfigValueAtContainer<TContainer, TValue> parent, ConfigInheritanceContext context) {
+ return getDelegate().considerParent(local, parent, context);
+ }
+ @Override
+ public <TContainer, TValue> ReferenceWithError<ConfigValueAtContainer<TContainer, TValue>> resolveWithParent(ConfigValueAtContainer<TContainer, TValue> local, ConfigValueAtContainer<TContainer, TValue> resolvedParent, ConfigInheritanceContext context) {
+ return getDelegate().resolveWithParent(local, resolvedParent, context);
+ }
+ @Override
+ public boolean equals(Object obj) {
+ return super.equals(obj) || getDelegate().equals(obj);
+ }
+ }
+
+ /*
+ * use of delegate is so that stateless classes can be defined to make the serialization nice,
+ * both the name and hiding the implementation detail (also making it easier for that detail to change);
+ * with aliased type names the field names here could even be aliases for the type names.
+ * (we could alternatively have an "alias-for-final-instance" mode in serialization,
+ * to optimize where we know that a java instance is final.)
+ */
+
+ private static class NotReinherited extends DelegatingConfigInheritance {
+ final transient BasicConfigInheritance delegate = new BasicConfigInheritance(false, CONFLICT_RESOLUTION_STRATEGY_OVERWRITE, false, true);
+ @Override protected ConfigInheritance getDelegate() { return delegate; }
+ }
/** Indicates that a config key value should not be passed down from a container where it is defined.
* Unlike {@link #NEVER_INHERITED} these values can be passed down if set as anonymous keys at a container
* (ie the container does not expect it) to a container which does expect it, but it will not be passed down further.
* If the inheritor also defines a value the parent's value is ignored irrespective
* (as in {@link #OVERWRITE}; see {@link #NOT_REINHERITED_ELSE_DEEP_MERGE} if merging is desired). */
- public static BasicConfigInheritance NOT_REINHERITED = new BasicConfigInheritance(false,CONFLICT_RESOLUTION_STRATEGY_OVERWRITE,false);
+ public static ConfigInheritance NOT_REINHERITED = new NotReinherited();
+
+ private static class NotReinheritedElseDeepMerge extends DelegatingConfigInheritance {
+ final transient BasicConfigInheritance delegate = new BasicConfigInheritance(false, CONFLICT_RESOLUTION_STRATEGY_DEEP_MERGE, false, true);
+ @Override protected ConfigInheritance getDelegate() { return delegate; }
+ }
/** As {@link #NOT_REINHERITED} but in cases where a value is inherited because a parent did not recognize it,
* if the inheritor also defines a value the two values should be merged. */
- public static BasicConfigInheritance NOT_REINHERITED_ELSE_DEEP_MERGE = new BasicConfigInheritance(false,CONFLICT_RESOLUTION_STRATEGY_DEEP_MERGE,false);
- /** Indicates that a key's value should never be inherited, even if defined on a container that does not know the key.
- * Most usages will prefer {@link #NOT_REINHERITED}. */
- public static BasicConfigInheritance NEVER_INHERITED = new BasicConfigInheritance(false,CONFLICT_RESOLUTION_STRATEGY_OVERWRITE,true);
+ public static ConfigInheritance NOT_REINHERITED_ELSE_DEEP_MERGE = new NotReinheritedElseDeepMerge();
+
+ private static class NeverInherited extends DelegatingConfigInheritance {
+ final transient BasicConfigInheritance delegate = new BasicConfigInheritance(false, CONFLICT_RESOLUTION_STRATEGY_OVERWRITE, true, false);
+ @Override protected ConfigInheritance getDelegate() { return delegate; }
+ }
+ /** Indicates that a key's value should never be inherited, even if inherited from a value set on a container that does not know the key.
+ * (Most usages will prefer {@link #NOT_REINHERITED}.) */
+ public static ConfigInheritance NEVER_INHERITED = new NeverInherited();
+
+ private static class Overwrite extends DelegatingConfigInheritance {
+ final transient BasicConfigInheritance delegate = new BasicConfigInheritance(true, CONFLICT_RESOLUTION_STRATEGY_OVERWRITE, false, true);
+ @Override protected ConfigInheritance getDelegate() { return delegate; }
+ }
/** Indicates that if a key has a value at both an ancestor and a descendant, the descendant and his descendants
* will prefer the value at the descendant. */
- public static BasicConfigInheritance OVERWRITE = new BasicConfigInheritance(true,CONFLICT_RESOLUTION_STRATEGY_OVERWRITE,false);
+ public static ConfigInheritance OVERWRITE = new Overwrite();
+
+ private static class DeepMerge extends DelegatingConfigInheritance {
+ final transient BasicConfigInheritance delegate = new BasicConfigInheritance(true, CONFLICT_RESOLUTION_STRATEGY_DEEP_MERGE, false, true);
+ @Override protected ConfigInheritance getDelegate() { return delegate; }
+ }
/** Indicates that if a key has a value at both an ancestor and a descendant, the descendant and his descendants
* should attempt to merge the values. If the values are not mergable behaviour is undefined
* (and often the descendant's value will simply overwrite). */
- public static BasicConfigInheritance DEEP_MERGE = new BasicConfigInheritance(true,CONFLICT_RESOLUTION_STRATEGY_DEEP_MERGE,false);
+ public static ConfigInheritance DEEP_MERGE = new DeepMerge();
+
+ // support conversion from these legacy fields
+ @SuppressWarnings("deprecation")
+ private static void registerReplacements() {
+ ConfigInheritance.Legacy.registerReplacement(ConfigInheritance.DEEP_MERGE, DEEP_MERGE);
+ ConfigInheritance.Legacy.registerReplacement(ConfigInheritance.ALWAYS, OVERWRITE);
+ ConfigInheritance.Legacy.registerReplacement(ConfigInheritance.NONE, NOT_REINHERITED);
+ }
+ static { registerReplacements(); }
- /** reinheritable? true/false; if false, children/descendants/inheritors will never see it; default true */
+ /** whether a value on a key defined locally should be inheritable by descendants.
+ * if false at a point where a key is defined,
+ * children/descendants/inheritors will not be able to see its value, whether explicit or default.
+ * default true: things are normally reinherited.
+ * <p>
+ * note that this only takes effect where a key is defined locally.
+ * if a key is not defined at an ancestor, a descendant setting this value false will not prevent it
+ * from inheriting values from ancestors.
+ * <p>
+ * typical use case for setting this is false is where a key is consumed and descendants should not
+ * "reconsume" it. for example setting files to install on a VM need only be applied once,
+ * and if it has <b>runtime management</b> hierarchy descendants which also understand that field they
+ * should not install the same files.
+ * (there is normally no reason to set this false in the context of <b>type hierarchy</b> inheritance because
+ * an ancestor type cannot "consume" a value.) */
protected final boolean isReinherited;
- /** conflict-resolution-strategy? in {@link BasicConfigInheritance} supported values are
+
+ /** a symbol indicating a conflict-resolution-strategy understood by the implementation.
+ * 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)} */
+ * subclasses may pass null or a different string 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;
+
+ /** @deprecated since 0.10.0 when this was introduced, now renamed {@link #localDefaultResolvesWithAncestorValue} */
+ @Deprecated protected final Boolean useLocalDefaultValue;
+ /** whether a local default value should be considered for resolution in the presence of an ancestor value.
+ * can use true with overwrite to mean don't inherit, or true with merge to mean local default merged on top of inherited
+ * (but be careful here, if local default is null in a merge it will delete ancestor values).
+ * <p>
+ * in most cases this is false, meaning a default value is ignored if the parent has a value.
+ * <p>
+ * null should not be used. a boxed object is taken (as opposed to a primitive boolean) only in order to support migration.
+ */
+ @Nonnull
+ protected final Boolean localDefaultResolvesWithAncestorValue;
- protected BasicConfigInheritance(boolean isReinherited, @Nullable String conflictResolutionStrategy, boolean useLocalDefaultValue) {
+ /** whether a default set in an ancestor container's key definition will be considered as the
+ * local default value at descendants who don't define any other value (nothing set locally and local default is null);
+ * <p>
+ * if true (now the usual behaviour), if an ancestor defines a default and a descendant doesn't, the ancestor's value will be taken as a default.
+ * if it is also the case that localDefaultResolvesWithAncestorValue is true at the <i>ancestor</i> then a descendant who
+ * defines a local default value (with this field true) will have its conflict resolution strategy
+ * applied with the ancestor's default value.
+ * <p>
+ * if this is false, ancestor defaults are completely ignored; prior to 0.10.0 this was the normal behaviour,
+ * but it caused surprises where default values in parameters did not take effect.
+ * <p>
+ * null should not be used. a boxed object is taken (as opposed to a primitive boolean) only in order to support migration.
+ */
+ @Nonnull
+ protected final Boolean ancestorDefaultInheritable;
+
+ /* TODO
+ * - document key definition inference vs explicitness (conflict resolution is inferred from nearest descendant explicit key; whereas other values don't apply if no explicit key)
+ * - ancestor default value inheritance -- https://issues.apache.org/jira/browse/BROOKLYN-267
+ * - immediate config evaluation
+ */
+
+ @Deprecated /** @deprecated since 0.10.0 use four-arg constructor */
+ protected BasicConfigInheritance(boolean isReinherited, @Nullable String conflictResolutionStrategy, boolean localDefaultResolvesWithAncestorValue) {
+ this(isReinherited, conflictResolutionStrategy, localDefaultResolvesWithAncestorValue, true);
+ }
+
+ protected BasicConfigInheritance(boolean isReinherited, @Nullable String conflictResolutionStrategy, boolean localDefaultResolvesWithAncestorValue, boolean ancestorDefaultInheritable) {
super();
this.isReinherited = isReinherited;
this.conflictResolutionStrategy = conflictResolutionStrategy;
- this.useLocalDefaultValue = useLocalDefaultValue;
+ this.useLocalDefaultValue = null;
+ this.localDefaultResolvesWithAncestorValue = localDefaultResolvesWithAncestorValue;
+ this.ancestorDefaultInheritable = ancestorDefaultInheritable;
}
@Override @Deprecated
@@ -82,9 +211,17 @@ public class BasicConfigInheritance implements ConfigInheritance {
protected <TContainer, TValue> void checkInheritanceContext(ConfigValueAtContainer<TContainer, TValue> local, ConfigInheritanceContext context) {
ConfigInheritance rightInheritance = ConfigInheritances.findInheritance(local, context, this);
- if (!equals(rightInheritance))
+ if (!isSameRootInstanceAs(rightInheritance)) {
throw new IllegalStateException("Low level inheritance computation error: caller should invoke on "+rightInheritance+" "
+ "(the inheritance at "+local+"), not "+this);
+ }
+ }
+
+ private boolean isSameRootInstanceAs(ConfigInheritance other) {
+ if (other==null) return false;
+ if (this==other) return true;
+ if (other instanceof DelegatingConfigInheritance) return isSameRootInstanceAs( ((DelegatingConfigInheritance)other).getDelegate() );
+ return false;
}
@Override
@@ -102,7 +239,7 @@ public class BasicConfigInheritance implements ConfigInheritance {
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
- return !local.isValueExplicitlySet() && !getUseLocalDefaultValue();
+ return !local.isValueExplicitlySet() && !getLocalDefaultResolvesWithAncestorValue();
}
return true;
}
@@ -115,12 +252,12 @@ public class BasicConfigInheritance implements ConfigInheritance {
checkInheritanceContext(local, context);
- if (!parent.isValueExplicitlySet() && !getUseLocalDefaultValue())
+ if (!parent.isValueExplicitlySet() && !getLocalDefaultResolvesWithAncestorValue())
return ReferenceWithError.newInstanceWithoutError(new BasicConfigValueAtContainer<TContainer,TValue>(local));
// parent explicitly set (or we might have to merge defaults),
// and by the contract of this method we can assume reinheritable
- if (!local.isValueExplicitlySet() && !getUseLocalDefaultValue())
+ if (!local.isValueExplicitlySet() && !getLocalDefaultResolvesWithAncestorValue())
return ReferenceWithError.newInstanceWithoutError(new BasicConfigValueAtContainer<TContainer,TValue>(parent));
// both explicitly set or defaults applicable, and not overwriting; it should be merge, or something from child
@@ -170,12 +307,88 @@ public class BasicConfigInheritance implements ConfigInheritance {
return conflictResolutionStrategy;
}
+ @Deprecated /** @deprecated since 0.10.0 when it was introduced, prefer {@link #getLocalDefaultResolvesWithAncestorValue()} */
public boolean getUseLocalDefaultValue() {
- return useLocalDefaultValue;
+ return getLocalDefaultResolvesWithAncestorValue();
+ }
+
+ /** see {@link #localDefaultResolvesWithAncestorValue} */
+ public boolean getLocalDefaultResolvesWithAncestorValue() {
+ if (localDefaultResolvesWithAncestorValue==null) {
+ // in case some legacy path is using an improperly deserialized object
+ log.warn("Encountered legacy "+this+" with null localDefaultResolvesWithAncestorValue; transforming", new Throwable("stack trace for legacy "+this));
+ readResolve();
+ }
+ return localDefaultResolvesWithAncestorValue;
+ }
+
+ public boolean getAncestorDefaultInheritable() {
+ if (ancestorDefaultInheritable==null) {
+ log.warn("Encountered legacy "+this+" with null ancestorDefaultInheritable; transforming", new Throwable("stack trace for legacy "+this));
+ readResolve();
+ }
+ return ancestorDefaultInheritable;
}
+ // standard deserialization method
+ private ConfigInheritance readResolve() {
+ try {
+ if (useLocalDefaultValue!=null) {
+ // move away from useLocalDefaultValue to localDefaultResolvesWithAncestorValue
+
+ Field fNew = getClass().getDeclaredField("localDefaultResolvesWithAncestorValue");
+ fNew.setAccessible(true);
+ Field fOld = getClass().getDeclaredField("useLocalDefaultValue");
+ fOld.setAccessible(true);
+
+ if (fNew.get(this)==null) {
+ fNew.set(this, useLocalDefaultValue);
+ } else {
+ if (!fNew.get(this).equals(useLocalDefaultValue)) {
+ throw new IllegalStateException("Incompatible values detected for "+fOld+" ("+fOld.get(this)+") and "+fNew+" ("+fNew.get(this)+")");
+ }
+ }
+ fOld.set(this, null);
+ }
+
+ if (ancestorDefaultInheritable==null) {
+ Field f = getClass().getDeclaredField("ancestorDefaultInheritable");
+ f.setAccessible(true);
+ f.set(this, true);
+ }
+
+ } catch (Exception e) {
+ throw Exceptions.propagate(e);
+ }
+
+ for (ConfigInheritance knownMode: Arrays.asList(
+ NOT_REINHERITED, NOT_REINHERITED_ELSE_DEEP_MERGE, NEVER_INHERITED, OVERWRITE, DEEP_MERGE)) {
+ if (equals(knownMode)) return knownMode;
+ }
+ if (equals(new BasicConfigInheritance(false, CONFLICT_RESOLUTION_STRATEGY_OVERWRITE, true, true))) {
+ // ignore the ancestor flag for this mode
+ return NEVER_INHERITED;
+ }
+
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj==null) return false;
+ if (obj instanceof DelegatingConfigInheritance) return equals( ((DelegatingConfigInheritance)obj).getDelegate() );
+ if (obj.getClass().equals(BasicConfigInheritance.class)) {
+ BasicConfigInheritance b = (BasicConfigInheritance)obj;
+ return Objects.equals(conflictResolutionStrategy, b.conflictResolutionStrategy) &&
+ Objects.equals(isReinherited, b.isReinherited) &&
+ Objects.equals(getLocalDefaultResolvesWithAncestorValue(), b.getLocalDefaultResolvesWithAncestorValue()) &&
+ Objects.equals(getAncestorDefaultInheritable(), b.getAncestorDefaultInheritable());
+ }
+ return false;
+ }
+
@Override
public String toString() {
- return super.toString()+"[reinherit="+isReinherited()+"; strategy="+getConflictResolutionStrategy()+"; useLocal="+getUseLocalDefaultValue()+"]";
+ return super.toString()+"[reinherit="+isReinherited()+"; strategy="+getConflictResolutionStrategy()+"; localDefaultResolvesWithAncestor="+localDefaultResolvesWithAncestorValue+"]";
}
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/53ae1c61/core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java b/core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java
index aae4a6e..a30fdfb 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java
@@ -22,11 +22,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
+import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.javalang.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
import com.thoughtworks.xstream.mapper.Mapper;
import com.thoughtworks.xstream.mapper.MapperWrapper;
@@ -42,7 +42,7 @@ public class ClassRenamingMapper extends MapperWrapper {
@Override
public Class<?> realClass(String elementName) {
- Optional<String> elementNameOpt = Reflections.tryFindMappedName(nameToType, elementName);
+ Maybe<String> elementNameOpt = Reflections.findMappedNameMaybe(nameToType, elementName);
if (elementNameOpt.isPresent()) {
LOG.debug("Mapping class '"+elementName+"' to '"+elementNameOpt.get()+"'");
elementName = elementNameOpt.get();
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/53ae1c61/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindConfigInheritanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindConfigInheritanceTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindConfigInheritanceTest.java
new file mode 100644
index 0000000..2eeef35
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindConfigInheritanceTest.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.mgmt.rebind;
+
+import java.io.File;
+import java.io.FileReader;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.config.ConfigInheritance;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.BasicConfigInheritance;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.config.ConfigKeys.InheritanceContext;
+import org.apache.brooklyn.core.config.ConfigPredicates;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.os.Os;
+import org.apache.brooklyn.util.stream.Streams;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+
+public class RebindConfigInheritanceTest extends RebindTestFixtureWithApp {
+
+ private static final Logger log = LoggerFactory.getLogger(RebindConfigInheritanceTest.class);
+
+ ConfigKey<String> key1 = ConfigKeys.builder(String.class, "key1").runtimeInheritance(BasicConfigInheritance.NEVER_INHERITED).build();
+ String origMemento, newMemento;
+ Application rebindedApp;
+
+ @Override
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ protected void doReadConfigInheritance(String label, String entityId) throws Exception {
+ String mementoFilename = "config-inheritance-"+label+"-"+entityId;
+ origMemento = Streams.readFullyString(getClass().getResourceAsStream(mementoFilename));
+
+ File persistedEntityFile = new File(mementoDir, Os.mergePaths("entities", entityId));
+ Files.write(origMemento.getBytes(), persistedEntityFile);
+
+ // we'll make assertions on what we've loaded
+ rebind();
+ rebindedApp = (Application) newManagementContext.lookup(entityId);
+
+ // we'll also make assertions on the contents written out
+ RebindTestUtils.waitForPersisted(mgmt());
+ newMemento = Joiner.on("\n").join(Files.readLines(persistedEntityFile, Charsets.UTF_8));
+ }
+
+ /** also see {@link RebindWithDeserializingClassRenamesTest} */
+ @Test
+ public void testPreBasicConfigInheritance_2016_07() throws Exception {
+ doReadConfigInheritance("prebasic-2016-07", "toruf2wxg4");
+
+ ConfigKey<?> k = Iterables.getOnlyElement( rebindedApp.config().findKeys(ConfigPredicates.nameEqualTo("my.config.inheritanceMerged")) );
+
+ Asserts.assertStringContains(origMemento, "<parentInheritance class=\"org.apache.brooklyn.config.ConfigInheritance$Merged\"/>");
+ Asserts.assertStringDoesNotContain(origMemento, BasicConfigInheritance.DEEP_MERGE.getClass().getName());
+
+ // should now convert it to BasicConfigInheritance.DEEP_MERGE
+ Asserts.assertStringDoesNotContain(newMemento, "ConfigInheritance$Merged");
+ Asserts.assertStringDoesNotContain(newMemento, "ConfigInheritance$Legacy$Merged");
+ Asserts.assertStringContains(newMemento, BasicConfigInheritance.DEEP_MERGE.getClass().getName());
+
+ ConfigInheritance inh = k.getInheritanceByContext(InheritanceContext.RUNTIME_MANAGEMENT);
+ Assert.assertEquals(inh, BasicConfigInheritance.DEEP_MERGE);
+ }
+
+ @Test
+ public void testBasicConfigInheritance_2016_10() throws Exception {
+ doReadConfigInheritance("basic-2016-10", "wj5s8u9h73");
+
+ checkNewAppNonInheritingKey1(rebindedApp);
+
+ Asserts.assertStringContains(origMemento, "isReinherited");
+ Asserts.assertStringDoesNotContain(origMemento, "NEVER_INHERITED");
+ Asserts.assertStringDoesNotContain(origMemento, "NeverInherited");
+
+ // should write it out as NeverInherited
+ Asserts.assertStringDoesNotContain(newMemento, "isReinherited");
+ Asserts.assertStringContains(newMemento, "NeverInherited");
+ }
+
+ @Test
+ public void testReadConfigInheritance_2016_11() throws Exception {
+ doReadConfigInheritance("basic-2016-11", "kmpez5fznt");
+ checkNewAppNonInheritingKey1(rebindedApp);
+
+ String origMementoWithoutLicenseHeader = origMemento.substring(origMemento.indexOf("<entity>"));
+ Asserts.assertEquals(origMementoWithoutLicenseHeader, newMemento);
+ }
+
+ @Test
+ public void testBasicConfigInheritanceProgrammatic() throws Exception {
+ origApp.config().set(key1, "1");
+
+ RebindOptions opts = RebindOptions.create();
+ opts.keepSameInstance = true;
+
+ rebind(opts);
+
+ String entityFile = Streams.readFully(new FileReader(new File(opts.mementoDir, "entities/"+origApp.getApplicationId())));
+ log.info("persisted file with config inheritance programmatic:\n"+entityFile);
+
+ checkNewAppNonInheritingKey1(newApp);
+ }
+
+ protected void checkNewAppNonInheritingKey1(Application app) {
+ // check key
+ EntityAsserts.assertConfigEquals(app, key1, "1");
+
+ // check not inherited
+ TestEntity entity = app.addChild(EntitySpec.create(TestEntity.class));
+ EntityAsserts.assertConfigEquals(entity, key1, null);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/53ae1c61/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindOptions.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindOptions.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindOptions.java
index bfa65d4..2c7514b 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindOptions.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindOptions.java
@@ -37,6 +37,10 @@ import com.google.common.collect.Iterables;
* See {@link RebindTestFixture#rebind(RebindOptions)} and {@link RebindTestUtils#rebind(RebindOptions)}.
*/
public class RebindOptions {
+ /** whether to keep the same instance, rather than make a copy;
+ * if true, this {@link RebindOptions} may be changed in-place when passed to {@link RebindTestUtils#rebind(RebindOptions)} */
+ public boolean keepSameInstance;
+
public boolean checkSerializable;
public boolean terminateOrigManagementContext;
public RebindExceptionHandler exceptionHandler;
@@ -55,6 +59,8 @@ public class RebindOptions {
return new RebindOptions();
}
public static RebindOptions create(RebindOptions options) {
+ if (options.keepSameInstance) return options;
+
RebindOptions result = create();
result.checkSerializable(options.checkSerializable);
result.terminateOrigManagementContext(options.terminateOrigManagementContext);
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/53ae1c61/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
index ec8aae9..41d51c2 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
@@ -29,7 +29,6 @@ import java.util.concurrent.Callable;
import org.apache.brooklyn.api.catalog.BrooklynCatalog;
import org.apache.brooklyn.api.catalog.CatalogItem;
import org.apache.brooklyn.api.entity.Application;
-import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/53ae1c61/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindWithDeserializingClassRenamesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindWithDeserializingClassRenamesTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindWithDeserializingClassRenamesTest.java
index c5e48c9..a66c7d9 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindWithDeserializingClassRenamesTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindWithDeserializingClassRenamesTest.java
@@ -19,18 +19,17 @@
package org.apache.brooklyn.core.mgmt.rebind;
import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
import java.io.File;
-import java.lang.reflect.Method;
import java.util.Map;
import org.apache.brooklyn.config.ConfigInheritance;
import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.BasicConfigInheritance;
import org.apache.brooklyn.core.config.ConfigKeys.InheritanceContext;
import org.apache.brooklyn.core.config.ConfigPredicates;
import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.util.core.ResourceUtils;
import org.apache.brooklyn.util.os.Os;
import org.testng.annotations.Test;
@@ -43,13 +42,13 @@ import com.google.common.io.Files;
public class RebindWithDeserializingClassRenamesTest extends RebindTestFixtureWithApp {
+ /** also see {@link RebindConfigInheritanceTest} */
@Test
- @SuppressWarnings("deprecation")
public void testRebindWillRenameLegacyConfigInheritance() throws Exception {
Map<String, String> expectedTransforms = ImmutableMap.<String, String>builder()
- .put("org.apache.brooklyn.config.ConfigInheritance$None", "org.apache.brooklyn.config.ConfigInheritance$Legacy$None")
- .put("org.apache.brooklyn.config.ConfigInheritance$Always", "org.apache.brooklyn.config.ConfigInheritance$Legacy$Always")
- .put("org.apache.brooklyn.config.ConfigInheritance$Merged", "org.apache.brooklyn.config.ConfigInheritance$Legacy$Merged")
+ .put("org.apache.brooklyn.config.ConfigInheritance$None", BasicConfigInheritance.NOT_REINHERITED.getClass().getName())
+ .put("org.apache.brooklyn.config.ConfigInheritance$Always", BasicConfigInheritance.OVERWRITE.getClass().getName())
+ .put("org.apache.brooklyn.config.ConfigInheritance$Merged", BasicConfigInheritance.DEEP_MERGE.getClass().getName())
.build();
String entityId = "toruf2wxg4";
@@ -58,8 +57,8 @@ public class RebindWithDeserializingClassRenamesTest extends RebindTestFixtureWi
// Orig state contains the old names (and not the new names)
for (Map.Entry<String, String> entry : expectedTransforms.entrySet()) {
- assertTrue(persistedEntity.contains(entry.getKey()));
- assertFalse(persistedEntity.contains(entry.getValue()));
+ Asserts.assertStringContains(persistedEntity, entry.getKey());
+ Asserts.assertStringDoesNotContain(persistedEntity, entry.getValue());
}
File persistedEntityFile = new File(mementoDir, Os.mergePaths("entities", entityId));
@@ -71,8 +70,8 @@ public class RebindWithDeserializingClassRenamesTest extends RebindTestFixtureWi
RebindTestUtils.waitForPersisted(mgmt());
String newPersistedEntity = Joiner.on("\n").join(Files.readLines(persistedEntityFile, Charsets.UTF_8));
for (Map.Entry<String, String> entry : expectedTransforms.entrySet()) {
- assertFalse(newPersistedEntity.contains(entry.getKey()));
- assertTrue(newPersistedEntity.contains(entry.getValue()));
+ Asserts.assertStringDoesNotContain(newPersistedEntity, entry.getKey());
+ Asserts.assertStringContains(newPersistedEntity, entry.getValue());
}
// Check the config keys are as expected
@@ -82,17 +81,13 @@ public class RebindWithDeserializingClassRenamesTest extends RebindTestFixtureWi
ConfigKey<?> keyWithInheritanceAlways = Iterables.find(config.keySet(), ConfigPredicates.nameEqualTo("my.config.inheritanceAlways"));
ConfigKey<?> keyWithInheritanceMerged = Iterables.find(config.keySet(), ConfigPredicates.nameEqualTo("my.config.inheritanceMerged"));
- assertLegacyConfigRuntimInheritanceMode(keyWithInheritanceNone, ConfigInheritance.InheritanceMode.NONE);
- assertLegacyConfigRuntimInheritanceMode(keyWithInheritanceAlways, ConfigInheritance.InheritanceMode.IF_NO_EXPLICIT_VALUE);
- assertLegacyConfigRuntimInheritanceMode(keyWithInheritanceMerged, ConfigInheritance.InheritanceMode.DEEP_MERGE);
+ assertConfigRuntimeInheritanceMode(keyWithInheritanceNone, BasicConfigInheritance.NOT_REINHERITED);
+ assertConfigRuntimeInheritanceMode(keyWithInheritanceAlways, BasicConfigInheritance.OVERWRITE);
+ assertConfigRuntimeInheritanceMode(keyWithInheritanceMerged, BasicConfigInheritance.DEEP_MERGE);
}
- @SuppressWarnings("deprecation")
- private void assertLegacyConfigRuntimInheritanceMode(ConfigKey<?> key, ConfigInheritance.InheritanceMode expected) throws Exception {
+ private void assertConfigRuntimeInheritanceMode(ConfigKey<?> key, ConfigInheritance expected) throws Exception {
ConfigInheritance val = key.getInheritanceByContext().get(InheritanceContext.RUNTIME_MANAGEMENT);
- Method method = val.getClass().getDeclaredMethod("getMode");
- method.setAccessible(true);
- ConfigInheritance.InheritanceMode mode = (ConfigInheritance.InheritanceMode) method.invoke(val);
- assertEquals(mode, expected);
+ assertEquals(val, expected);
}
}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/53ae1c61/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-basic-2016-10-wj5s8u9h73
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-basic-2016-10-wj5s8u9h73 b/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-basic-2016-10-wj5s8u9h73
new file mode 100644
index 0000000..d1bc6ca
--- /dev/null
+++ b/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-basic-2016-10-wj5s8u9h73
@@ -0,0 +1,50 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<entity>
+ <brooklynVersion>0.10.0-SNAPSHOT</brooklynVersion>
+ <type>org.apache.brooklyn.core.test.entity.TestApplicationNoEnrichersImpl</type>
+ <id>wj5s8u9h73</id>
+ <displayName>TestApplicationNoEnrichersImpl:wj5s</displayName>
+ <config>
+ <key1>1</key1>
+ </config>
+ <attributes>
+ <entity.id>wj5s8u9h73</entity.id>
+ <application.id>wj5s8u9h73</application.id>
+ <catalog.id>
+ <null/>
+ </catalog.id>
+ </attributes>
+ <configKeys>
+ <key1>
+ <configKey>
+ <name>key1</name>
+ <type>java.lang.String</type>
+ <reconfigurable>false</reconfigurable>
+ <runtimeInheritance class="org.apache.brooklyn.core.config.BasicConfigInheritance">
+ <isReinherited>false</isReinherited>
+ <conflictResolutionStrategy>overwrite</conflictResolutionStrategy>
+ <useLocalDefaultValue>true</useLocalDefaultValue>
+ </runtimeInheritance>
+ <constraint class="com.google.common.base.Predicates$ObjectPredicate">ALWAYS_TRUE</constraint>
+ </configKey>
+ </key1>
+ </configKeys>
+</entity>
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/53ae1c61/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-basic-2016-11-kmpez5fznt
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-basic-2016-11-kmpez5fznt b/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-basic-2016-11-kmpez5fznt
new file mode 100644
index 0000000..cf635ea
--- /dev/null
+++ b/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-basic-2016-11-kmpez5fznt
@@ -0,0 +1,46 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<entity>
+ <brooklynVersion>0.10.0-SNAPSHOT</brooklynVersion>
+ <type>org.apache.brooklyn.core.test.entity.TestApplicationNoEnrichersImpl</type>
+ <id>kmpez5fznt</id>
+ <displayName>TestApplicationNoEnrichersImpl:kmpe</displayName>
+ <config>
+ <key1>1</key1>
+ </config>
+ <attributes>
+ <entity.id>kmpez5fznt</entity.id>
+ <application.id>kmpez5fznt</application.id>
+ <catalog.id>
+ <null/>
+ </catalog.id>
+ </attributes>
+ <configKeys>
+ <key1>
+ <configKey>
+ <name>key1</name>
+ <type>java.lang.String</type>
+ <reconfigurable>false</reconfigurable>
+ <runtimeInheritance class="org.apache.brooklyn.core.config.BasicConfigInheritance$NeverInherited"/>
+ <constraint class="com.google.common.base.Predicates$ObjectPredicate">ALWAYS_TRUE</constraint>
+ </configKey>
+ </key1>
+ </configKeys>
+</entity>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/53ae1c61/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-prebasic-2016-07-toruf2wxg4
----------------------------------------------------------------------
diff --git a/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-prebasic-2016-07-toruf2wxg4 b/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-prebasic-2016-07-toruf2wxg4
new file mode 100644
index 0000000..7a59b4e
--- /dev/null
+++ b/core/src/test/resources/org/apache/brooklyn/core/mgmt/rebind/config-inheritance-prebasic-2016-07-toruf2wxg4
@@ -0,0 +1,137 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<entity>
+ <brooklynVersion>0.10.0-20160908.1322</brooklynVersion>
+ <type>org.apache.brooklyn.entity.stock.BasicApplicationImpl</type>
+ <id>toruf2wxg4</id>
+ <displayName>Application (toruf2wxg4)</displayName>
+ <tags>
+ <org.apache.brooklyn.core.mgmt.BrooklynTags_-NamedStringTag>
+ <kind>yaml_spec</kind>
+ <contents>services:
+- type: org.apache.brooklyn.entity.stock.BasicApplication</contents>
+ </org.apache.brooklyn.core.mgmt.BrooklynTags_-NamedStringTag>
+ </tags>
+ <config>
+ <my.config.inheritanceNone>myval</my.config.inheritanceNone>
+ <my.config.inheritanceMerged>myval</my.config.inheritanceMerged>
+ <my.config.inheritanceAlways>myval</my.config.inheritanceAlways>
+ </config>
+ <attributes>
+ <service.notUp.indicators>
+ <MutableMap/>
+ </service.notUp.indicators>
+ <entity.id>toruf2wxg4</entity.id>
+ <application.id>toruf2wxg4</application.id>
+ <catalog.id>
+ <null/>
+ </catalog.id>
+ <service.isUp type="boolean">true</service.isUp>
+ <service.problems>
+ <MutableMap/>
+ </service.problems>
+ <service.state type="org.apache.brooklyn.core.entity.lifecycle.Lifecycle">RUNNING</service.state>
+ <service.state.expected>
+ <org.apache.brooklyn.core.entity.lifecycle.Lifecycle_-Transition>
+ <state>RUNNING</state>
+ <timestampUtc>1476100554627</timestampUtc>
+ </org.apache.brooklyn.core.entity.lifecycle.Lifecycle_-Transition>
+ </service.state.expected>
+ </attributes>
+
+ <configKeys>
+ <!-- Hand-crafted config, for testing -->
+ <my.config.inheritanceNone>
+ <configKey>
+ <name>my.config.inheritanceNone</name>
+ <type>java.lang.String</type>
+ <reconfigurable>false</reconfigurable>
+ <parentInheritance class="org.apache.brooklyn.config.ConfigInheritance$None"/>
+ </configKey>
+ </my.config.inheritanceNone>
+ <my.config.inheritanceMerged>
+ <configKey>
+ <name>my.config.inheritanceMerged</name>
+ <type>java.lang.String</type>
+ <reconfigurable>false</reconfigurable>
+ <parentInheritance class="org.apache.brooklyn.config.ConfigInheritance$Merged"/>
+ </configKey>
+ </my.config.inheritanceMerged>
+ <my.config.inheritanceAlways>
+ <configKey>
+ <name>my.config.inheritanceAlways</name>
+ <type>java.lang.String</type>
+ <reconfigurable>false</reconfigurable>
+ <parentInheritance class="org.apache.brooklyn.config.ConfigInheritance$Always"/>
+ </configKey>
+ </my.config.inheritanceAlways>
+ </configKeys>
+
+ <attributeKeys>
+ <service.notUp.indicators>
+ <attributeSensor>
+ <typeToken class="org.apache.brooklyn.core.entity.Attributes$1" resolves-to="com.google.common.reflect.TypeToken$SimpleTypeToken">
+ <runtimeType class="com.google.common.reflect.Types$ParameterizedTypeImpl">
+ <argumentsList>
+ <java-class>java.lang.String</java-class>
+ <java-class>java.lang.Object</java-class>
+ </argumentsList>
+ <rawType>java.util.Map</rawType>
+ </runtimeType>
+ </typeToken>
+ <name>service.notUp.indicators</name>
+ <description>A map of namespaced indicators that the service is not up</description>
+ <persistence>REQUIRED</persistence>
+ </attributeSensor>
+ </service.notUp.indicators>
+ <service.problems>
+ <attributeSensor>
+ <typeToken class="org.apache.brooklyn.core.entity.Attributes$3" resolves-to="com.google.common.reflect.TypeToken$SimpleTypeToken">
+ <runtimeType class="com.google.common.reflect.Types$ParameterizedTypeImpl">
+ <argumentsList>
+ <java-class>java.lang.String</java-class>
+ <java-class>java.lang.Object</java-class>
+ </argumentsList>
+ <rawType>java.util.Map</rawType>
+ </runtimeType>
+ </typeToken>
+ <name>service.problems</name>
+ <description>A map of namespaced indicators of problems with a service</description>
+ <persistence>REQUIRED</persistence>
+ </attributeSensor>
+ </service.problems>
+ <service.state>
+ <attributeSensor>
+ <type>org.apache.brooklyn.core.entity.lifecycle.Lifecycle</type>
+ <name>service.state</name>
+ <description>Actual lifecycle state of the service</description>
+ <persistence>REQUIRED</persistence>
+ </attributeSensor>
+ </service.state>
+ <service.state.expected>
+ <attributeSensor>
+ <type>org.apache.brooklyn.core.entity.lifecycle.Lifecycle$Transition</type>
+ <name>service.state.expected</name>
+ <description>Last controlled change to service state, indicating what the expected state should be</description>
+ <persistence>REQUIRED</persistence>
+ </attributeSensor>
+ </service.state.expected>
+ </attributeKeys>
+</entity>
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/53ae1c61/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 5b96a7b..3100c8c 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
@@ -26,6 +26,7 @@ import javax.annotation.Nullable;
import org.apache.brooklyn.config.ConfigInheritances.BasicConfigValueAtContainer;
import org.apache.brooklyn.util.collections.CollectionMerger;
+import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.exceptions.ReferenceWithError;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.text.Strings;
@@ -47,11 +48,11 @@ public interface ConfigInheritance extends Serializable {
DEEP_MERGE
}
- /** @deprecated since 0.10.0 see implementations of this interface */ @Deprecated
+ /** @deprecated since 0.10.0 see implementations of this interface (look for NOT_REINHERITED, or possibly NEVER_REINHERITED) */ @Deprecated
public static final ConfigInheritance NONE = new Legacy.None();
- /** @deprecated since 0.10.0 see implementations of this interface */ @Deprecated
+ /** @deprecated since 0.10.0 see implementations of this interface (look for OVERWRITE) */ @Deprecated
public static final ConfigInheritance ALWAYS = new Legacy.Always();
- /** @deprecated since 0.10.0 see implementations of this interface */ @Deprecated
+ /** @deprecated since 0.10.0 see implementations of this interface (look for the same name, DEEP_MERGE) */ @Deprecated
public static final ConfigInheritance DEEP_MERGE = new Legacy.Merged();
/** @deprecated since 0.10.0 more complex inheritance conditions now require other methods */
@@ -133,6 +134,16 @@ public interface ConfigInheritance extends Serializable {
throw new IllegalArgumentException("Invalid config-inheritance '"+val+"' (legal values are none, always or merge)");
}
}
+ private static Map<ConfigInheritance,ConfigInheritance> REPLACEMENTS = MutableMap.of();
+ /** used to assist in migration to new classes */
+ public static void registerReplacement(ConfigInheritance old, ConfigInheritance replacement) {
+ REPLACEMENTS.put(old, replacement);
+ }
+ private static ConfigInheritance orReplacement(ConfigInheritance orig) {
+ ConfigInheritance repl = REPLACEMENTS.get(orig);
+ if (repl!=null) return repl;
+ return orig;
+ }
private abstract static class LegacyAbstractConversion implements ConfigInheritance {
@Override
@@ -200,18 +211,30 @@ public interface ConfigInheritance extends Serializable {
public InheritanceMode getMode() {
return InheritanceMode.IF_NO_EXPLICIT_VALUE;
}
+ @SuppressWarnings("unused") // standard deserialization method
+ private ConfigInheritance readResolve() {
+ return orReplacement(ConfigInheritance.ALWAYS);
+ }
}
private static class None extends LegacyAbstractConversion {
@Override
public InheritanceMode getMode() {
return InheritanceMode.NONE;
}
+ @SuppressWarnings("unused") // standard deserialization method
+ private ConfigInheritance readResolve() {
+ return orReplacement(ConfigInheritance.NONE);
+ }
}
private static class Merged extends LegacyAbstractConversion {
@Override
public InheritanceMode getMode() {
return InheritanceMode.DEEP_MERGE;
}
+ @SuppressWarnings("unused") // standard deserialization method
+ private ConfigInheritance readResolve() {
+ return orReplacement(ConfigInheritance.DEEP_MERGE);
+ }
}
}