Add (some) tests of rebind of previously persisted state.
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/63f4a941 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/63f4a941 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/63f4a941 Branch: refs/heads/master Commit: 63f4a9415901fece4b63fc0cd676b7812959ea9d Parents: b5ca71b Author: Geoff Macartney <[email protected]> Authored: Mon Oct 3 10:13:30 2016 +0100 Committer: Geoff Macartney <[email protected]> Committed: Thu Apr 20 11:20:36 2017 +0100 ---------------------------------------------------------------------- .../brooklyn/catalog/CatalogYamlRebindTest.java | 65 ++++++++++++++++++-- .../core/mgmt/rebind/dto/AbstractMemento.java | 42 +++++++++++-- .../rebind/transformer/CompoundTransformer.java | 3 +- 3 files changed, 99 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/63f4a941/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java index e6aff50..ff0c794 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java @@ -39,6 +39,8 @@ import javax.xml.transform.stream.StreamResult; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoPersister; +import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData; +import org.apache.brooklyn.api.objs.BrooklynObjectType; import org.apache.brooklyn.api.policy.Policy; import org.apache.brooklyn.api.sensor.Enricher; import org.apache.brooklyn.api.typereg.RegisteredType; @@ -51,7 +53,9 @@ import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest; import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore; import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore; import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore.StoreObjectAccessor; +import org.apache.brooklyn.core.mgmt.rebind.RebindExceptionHandlerImpl; import org.apache.brooklyn.core.mgmt.rebind.RebindOptions; +import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer; import org.apache.brooklyn.core.test.policy.TestEnricher; import org.apache.brooklyn.core.test.policy.TestPolicy; import org.apache.brooklyn.entity.stock.BasicEntity; @@ -103,7 +107,7 @@ public class CatalogYamlRebindTest extends AbstractYamlRebindTest { LIBRARY, PREFIX } - + private Boolean defaultEnablementOfFeatureAutoFixatalogRefOnRebind; @BeforeMethod(alwaysRun=true) @@ -162,8 +166,61 @@ public class CatalogYamlRebindTest extends AbstractYamlRebindTest { } @Test(dataProvider = "dataProvider") + public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, boolean useOsgi) throws Exception { + testRebindWithCatalogAndAppUsingOptions(mode, useOsgi, RebindOptions.create()); + } + + @Test(dataProvider = "dataProvider") + public void testRebindWithCatalogAndAppRebindCatalogItemIds(RebindWithCatalogTestMode mode, boolean useOsgi) throws Exception { + testRebindWithCatalogAndAppUsingOptions(mode, useOsgi, rebindCatalogItemIds()); + } + + private RebindOptions rebindCatalogItemIds() { + CompoundTransformer transformer = CompoundTransformer.builder() + .xmlReplaceItem("//catalogItemSuperIds", "<catalogItemId><xsl:value-of select=\"string\"/></catalogItemId>") + .build(); + return applyStateTransformer(transformer); + } + + private RebindOptions applyStateTransformer(final CompoundTransformer transformer) { + return RebindOptions.create() + .stateTransformer(new Function<BrooklynMementoPersister, Void>() { + @Override public Void apply(BrooklynMementoPersister input) { + + BrooklynMementoRawData transformed = null; + try { + transformed = transformer.transform((BrooklynMementoPersisterToObjectStore) input, RebindExceptionHandlerImpl.builder().build()); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + getLogger().warn(Strings.join(new Object[]{ + "Caught'", e.getMessage(), "' when transforming '", input.getBackingStoreDescription() + }, ""), e); + } + + PersistenceObjectStore objectStore = ((BrooklynMementoPersisterToObjectStore)input).getObjectStore(); + for (BrooklynObjectType type : BrooklynObjectType.values()) { + final List<String> contents = objectStore.listContentsWithSubPath(type.getSubPathName()); + for (String path : contents) { + StoreObjectAccessor accessor = objectStore.newAccessor(path); + String memento = checkNotNull(accessor.get(), path); + String replacement = transformed.getObjectsOfType(type).get(idFromPath(type, path)); + getLogger().trace("Replacing {} with {}", memento, replacement); + accessor.put(replacement); + } + } + + return null; + }}); + } + + private String idFromPath(BrooklynObjectType type, String path) { + // the replace underscore with colon below handles file names of catalog items like "catalog/my.catalog.app.id.load_0.1.0" + return path.substring(type.getSubPathName().length()+1).replace('_', ':'); + } + + @SuppressWarnings({ "deprecation", "unused" }) - public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, OsgiMode osgiMode) throws Exception { + public void testRebindWithCatalogAndAppUsingOptions(RebindWithCatalogTestMode mode, boolean useOsgi, RebindOptions options) throws Exception { if (osgiMode != OsgiMode.NONE) { TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); } @@ -298,7 +355,7 @@ public class CatalogYamlRebindTest extends AbstractYamlRebindTest { // Rebind if (mode == RebindWithCatalogTestMode.STRIP_DEPRECATION_AND_ENABLEMENT_FROM_CATALOG_ITEM) { // Edit the persisted state to remove the "deprecated" and "enablement" tags for our catalog items - rebind(RebindOptions.create() + rebind(RebindOptions.create(options) .stateTransformer(new Function<BrooklynMementoPersister, Void>() { @Override public Void apply(BrooklynMementoPersister input) { PersistenceObjectStore objectStore = ((BrooklynMementoPersisterToObjectStore)input).getObjectStore(); @@ -313,7 +370,7 @@ public class CatalogYamlRebindTest extends AbstractYamlRebindTest { return null; }})); } else { - rebind(); + rebind(options); } // Ensure app is still there, and that it is usable - e.g. "stop" effector functions as expected http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/63f4a941/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java index 5feb0af..cf3a033 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java @@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import org.apache.brooklyn.util.collections.MutableList; public abstract class AbstractMemento implements Memento, Serializable { @@ -46,7 +47,9 @@ public abstract class AbstractMemento implements Memento, Serializable { protected String type; protected Class<?> typeClass; protected String displayName; - protected List<String> catalogItemSuperIds; + // catalogItemId is retained to support rebind of previously persisted state (prior to catalogItemSuperIds) + protected String catalogItemId; + protected List<String> catalogItemSuperIds = MutableList.of(); protected Map<String, Object> customFields = Maps.newLinkedHashMap(); protected List<Object> tags = Lists.newArrayList(); protected Map<String,Set<String>> relations = Maps.newLinkedHashMap(); @@ -65,14 +68,28 @@ public abstract class AbstractMemento implements Memento, Serializable { type = other.getType(); typeClass = other.getTypeClass(); displayName = other.getDisplayName(); - catalogItemSuperIds = other.getCatalogItemSuperIds(); + setCatalogItemIds(other.getCatalogItemSuperIds(), other.getCatalogItemId()); customFields.putAll(other.getCustomFields()); tags.addAll(other.getTags()); relations.putAll(other.getRelations()); uniqueTag = other.getUniqueTag(); return self(); } - + + private void setCatalogItemIds(List<String> otherItemSuperIds, String otherItemId) { + if (isEmpty(otherItemSuperIds) && otherItemId == null) { + catalogItemSuperIds = MutableList.of(); + } else if (isEmpty(otherItemSuperIds) && otherItemId != null) { + catalogItemSuperIds = MutableList.of(otherItemId); + } else { + catalogItemSuperIds = MutableList.copyOf(otherItemSuperIds); + } + } + + private boolean isEmpty(List<String> ids) { + return ids == null || ids.isEmpty(); + } + /** * @deprecated since 0.7.0; use config/attributes so generic persistence will work, rather than requiring "custom fields" */ @@ -86,7 +103,9 @@ public abstract class AbstractMemento implements Memento, Serializable { private String type; private String id; private String displayName; - private List<String> catalogItemSuperIds; + // catalogItemId is retained to support rebind of previously persisted state (prior to catalogItemSuperIds) + protected String catalogItemId; + private List<String> catalogItemSuperIds = MutableList.of(); private List<Object> tags; private Map<String,Set<String>> relations; @@ -116,7 +135,18 @@ public abstract class AbstractMemento implements Memento, Serializable { // "fields" is not included as a field here, so that it is serialized after selected subclass fields // but the method declared here simplifies how it is connected in via builder etc protected abstract void setCustomFields(Map<String, Object> fields); - + + // deals with value created by deserialization of state persisted with <catalogItemId> + private void normalizeCatalogItemIds() { + if (catalogItemSuperIds == null) { + catalogItemSuperIds = MutableList.of(); + } + if (catalogItemSuperIds.isEmpty() && catalogItemId != null) { + catalogItemSuperIds = MutableList.of(catalogItemId); + catalogItemId = null; + } + } + @Override public void injectTypeClass(Class<?> clazz) { this.typeClass = clazz; @@ -149,11 +179,13 @@ public abstract class AbstractMemento implements Memento, Serializable { @Override public String getCatalogItemId() { + normalizeCatalogItemIds(); return Iterables.getFirst(getCatalogItemSuperIds(), null); } @Override public List<String> getCatalogItemSuperIds() { + normalizeCatalogItemIds(); return catalogItemSuperIds; } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/63f4a941/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java index 59d7fe6..c9bf703 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Set; import org.apache.brooklyn.api.mgmt.rebind.RebindExceptionHandler; +import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoPersister; import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData; import org.apache.brooklyn.api.objs.BrooklynObjectType; import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore; @@ -188,8 +189,6 @@ public class CompoundTransformer { * <string>two</string> * </catalogItemSuperIds> * </pre> - * </p><p> - * * </p> * This provides a programmatic way to change the catalogItemID. */ public Builder changeCatalogItemId(String oldSymbolicName, String oldVersion,
