From 5d0fe63cec36a8f478b4e666e0cb769462232fe5 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 14 Sep 2016 14:44:14 +0100 Subject: [PATCH 01/35] Osgi loader change --- .../brooklyn/core/catalog/internal/CatalogUtils.java | 8 ++++++++ .../BrooklynClassLoadingContextSequential.java | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index 8306b71bd2..8b7555bc76 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -19,6 +19,7 @@ package org.apache.brooklyn.core.catalog.internal; import java.util.Collection; +import java.util.Iterator; import javax.annotation.Nullable; @@ -171,6 +172,13 @@ public static void installLibraries(ManagementContext managementContext, @Nullab public static String getCatalogItemIdFromLoader(BrooklynClassLoadingContext loader) { if (loader instanceof OsgiBrooklynClassLoadingContext) { return ((OsgiBrooklynClassLoadingContext)loader).getCatalogItemId(); + } else if (loader instanceof BrooklynClassLoadingContextSequential) { + final Iterator iterator = ((BrooklynClassLoadingContextSequential) loader).getPrimaries().iterator(); + if (iterator.hasNext()) { + BrooklynClassLoadingContext osgiLoader = iterator.next(); + return getCatalogItemIdFromLoader(osgiLoader); + } + else return null; } else { return null; } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/BrooklynClassLoadingContextSequential.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/BrooklynClassLoadingContextSequential.java index 989cacc64c..ee55ae9b93 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/BrooklynClassLoadingContextSequential.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/BrooklynClassLoadingContextSequential.java @@ -38,7 +38,7 @@ public final class BrooklynClassLoadingContextSequential extends AbstractBrooklynClassLoadingContext { private static final Logger log = LoggerFactory.getLogger(BrooklynClassLoadingContextSequential.class); - + private final List primaries = MutableList.of(); // secondaries used to put java classloader last private final Set secondaries = MutableSet.of(); @@ -132,5 +132,8 @@ public boolean equals(Object obj) { if (!Objects.equal(secondaries, ((BrooklynClassLoadingContextSequential)obj).secondaries)) return false; return true; } - + + public List getPrimaries() { + return primaries; + } } From 7e88322634490f7d29a9cd9f9977a2b9a111e6a3 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 19 Sep 2016 14:22:43 +0100 Subject: [PATCH 02/35] Add nested catalog item ids to AbstractBrooklynObjectSpec. --- .../internal/AbstractBrooklynObjectSpec.java | 44 +++++++++++++++++-- .../brooklyn/spi/creation/CampResolver.java | 2 +- .../catalog/CatalogYamlEntityTest.java | 4 +- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java index c3d45af0ad..95f791bb9b 100644 --- a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java +++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java @@ -22,9 +22,12 @@ import java.io.Serializable; import java.lang.reflect.Modifier; +import java.util.ArrayDeque; import java.util.Collections; +import java.util.Deque; import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.Set; import org.apache.brooklyn.api.mgmt.EntityManager; @@ -65,7 +68,7 @@ public abstract class AbstractBrooklynObjectSpec type; private String displayName; - private String catalogItemId; + private Deque catalogItemIdStack = new ArrayDeque<>(); private Set tags = MutableSet.of(); private List> parameters = ImmutableList.of(); @@ -103,7 +106,23 @@ public SpecT displayName(String val) { // if that behaviour is desired, the child should be refactored to be its own item in the catalog BOM // (or TODO we add a separate field to record other catalog item IDs that could be applied for searching, see below) public SpecT catalogItemId(String val) { - catalogItemId = val; + catalogItemIdStack.clear(); + return nestCatalogItemId(val); + } + + /** + * Adds (stacks) the catalog item id of a wrapping specification. + * Does nothing if the value is null. + * + * Used when we to collect nested item ID's so that *all* can be searched. + * e.g. if R3 references R2 which references R1 any one of these might supply config keys + * referencing resources or types in their local bundles. + */ + @Beta + public SpecT nestCatalogItemId(String val) { + if (null != val) { + catalogItemIdStack.addFirst(val); + } return self(); } // TODO in many places (callers to this method) we prefer a wrapper item ID; @@ -119,7 +138,7 @@ public SpecT catalogItemIdIfNotNull(String val) { return self(); } - + public SpecT tag(Object tag) { tags.add(tag); return self(); @@ -192,7 +211,24 @@ public final String getDisplayName() { } public final String getCatalogItemId() { - return catalogItemId; + if (catalogItemIdStack.size() != 0) { + return catalogItemIdStack.getFirst(); + } + return null; + } + + /** + * Get immutable list of ids of this object's catalog item and its nested catalog items. + * e.g. if the catalog item is defined as + *
+     *     items:
+     *     - id: X
+     *       item: Y
+     * 
+ * then the list will contain X, Y. + */ + public final List getNestedCatalogItemIds() { + return ImmutableList.copyOf(catalogItemIdStack); } public final Set getTags() { diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java index d8c4194d94..39f77e0c19 100644 --- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java +++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java @@ -115,7 +115,7 @@ public CampResolver(ManagementContext mgmt, RegisteredType type, RegisteredTypeL throw new IllegalStateException("Creating spec from "+item+", got "+spec.getType()+" which is incompatible with expected "+expectedType); } - spec.catalogItemIdIfNotNull(item.getId()); + spec.nestCatalogItemId(item.getId()); if (!spec.getFlags().containsKey("iconUrl") && item.getIconUrl()!=null) { spec.configure("iconUrl", item.getIconUrl()); } diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java index 5e31142c5a..dff66898ad 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java @@ -636,8 +636,8 @@ public void testCatalogItemIdInReferencedItems() throws Exception { Entity app = createAndStartApplication(yaml); Entity entity = app.getChildren().iterator().next(); - // Fails - assertEquals(entity.getCatalogItemId(), ver(symbolicNameInner)); + assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); + // TODO check nested ids deleteCatalogEntity(symbolicNameInner); deleteCatalogEntity(symbolicNameOuter); From 8c4427299f77de91258d8d653d8d6d1e75644328 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 20 Sep 2016 11:16:36 +0100 Subject: [PATCH 03/35] Add catalog item super id support. --- .../internal/AbstractBrooklynObjectSpec.java | 4 +- .../brooklyn/api/objs/BrooklynObject.java | 13 ++++++ .../core/catalog/internal/CatalogItemDo.java | 16 ++++++++ .../internal/CatalogItemDtoAbstract.java | 2 + .../core/catalog/internal/CatalogUtils.java | 4 +- .../access/PortForwardManagerClient.java | 7 ++++ .../core/mgmt/rebind/RebindIteration.java | 1 + .../core/objs/AbstractBrooklynObject.java | 41 +++++++++++++++++-- .../core/objs/AbstractEntityAdjunct.java | 8 ++-- .../core/objs/BrooklynObjectInternal.java | 4 ++ .../objs/proxy/InternalEntityFactory.java | 5 ++- .../objs/proxy/InternalLocationFactory.java | 2 +- .../objs/proxy/InternalPolicyFactory.java | 4 +- .../util/core/ClassLoaderUtilsTest.java | 2 +- 14 files changed, 96 insertions(+), 17 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java index 95f791bb9b..048a44014b 100644 --- a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java +++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java @@ -218,7 +218,7 @@ public final String getCatalogItemId() { } /** - * Get immutable list of ids of this object's catalog item and its nested catalog items. + * An immutable list of ids of this object's catalog item and its defining catalog items. * e.g. if the catalog item is defined as *
      *     items:
@@ -227,7 +227,7 @@ public final String getCatalogItemId() {
      * 
* then the list will contain X, Y. */ - public final List getNestedCatalogItemIds() { + public final List getCatalogItemSuperIds() { return ImmutableList.copyOf(catalogItemIdStack); } diff --git a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java index b42bc58fc4..61672881e2 100644 --- a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java +++ b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.api.objs; +import java.util.List; import java.util.Map; import java.util.Set; @@ -57,6 +58,18 @@ public interface BrooklynObject extends Identifiable, Configurable { * Callers can set an explicit catalog item ID if inferencing is not correct. */ String getCatalogItemId(); + + /** + * An immutable list of ids of this object's catalog item and its defining catalog items. + * e.g. if the catalog item is defined as + *
+     *     items:
+     *     - id: X
+     *       item: Y
+     * 
+ * then the list will contain X, Y. + */ + List getCatalogItemSuperIds(); /** * Tags are arbitrary objects which can be attached to an entity for subsequent reference. diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java index 1766ad7636..6699e3965b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java @@ -19,6 +19,7 @@ package org.apache.brooklyn.core.catalog.internal; import java.util.Collection; +import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -130,6 +131,21 @@ public void setCatalogItemId(String id) { itemDto.setCatalogItemId(id); } + @Override + public void setCatalogItemIds(List ids) { + itemDto.setCatalogItemIds(ids); + } + + @Override + public List getCatalogItemSuperIds() { + return itemDto.getCatalogItemSuperIds(); + } + + @Override + public void nestCatalogItemId(String id) { + itemDto.nestCatalogItemId(id); + } + @Override public String getJavaType() { return itemDto.getJavaType(); diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java index df0d2e47be..41ed6a132a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java @@ -45,6 +45,8 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Sets; +// TODO add support for nested catalog items, implement nestCatalogItemId in terms of symbolicName/Version +// TODO also getCatalogItemSuperIds. public abstract class CatalogItemDtoAbstract extends AbstractBrooklynObject implements CatalogItem { private static Logger LOG = LoggerFactory.getLogger(CatalogItemDtoAbstract.class); diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index 8b7555bc76..42e8766090 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -20,9 +20,11 @@ import java.util.Collection; import java.util.Iterator; +import java.util.ListIterator; import javax.annotation.Nullable; +import com.google.common.collect.Lists; import org.apache.brooklyn.api.catalog.BrooklynCatalog; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle; @@ -191,7 +193,7 @@ public static void setCatalogItemIdOnAddition(Entity entity, BrooklynObject item if (log.isDebugEnabled()) BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(entity), "Catalog item addition: "+entity+" from "+entity.getCatalogItemId()+" applying its catalog item ID to "+itemBeingAdded); - ((BrooklynObjectInternal)itemBeingAdded).setCatalogItemId(entity.getCatalogItemId()); + ((BrooklynObjectInternal)itemBeingAdded).setCatalogItemIds(entity.getCatalogItemSuperIds()); } else { if (!itemBeingAdded.getCatalogItemId().equals(entity.getCatalogItemId())) { // not a problem, but something to watch out for diff --git a/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java b/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java index b0baa01eb3..1fb6ef53aa 100644 --- a/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java +++ b/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java @@ -19,6 +19,7 @@ package org.apache.brooklyn.core.location.access; import java.util.Collection; +import java.util.List; import java.util.Map; import org.apache.brooklyn.api.entity.Entity; @@ -26,6 +27,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.config.ConfigKey.HasConfigKey; +import org.apache.brooklyn.core.location.AbstractLocation; import org.apache.brooklyn.util.exceptions.Exceptions; import com.google.common.base.Preconditions; @@ -386,6 +388,11 @@ public String getCatalogItemId() { return getDelegate().getCatalogItemId(); } + @Override + public List getCatalogItemSuperIds() { + return getDelegate().getCatalogItemSuperIds(); + } + @Override public TagSupport tags() { return getDelegate().tags(); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index 6df82320dd..0585f9b6c6 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -931,6 +931,7 @@ protected Entity newEntity(EntityMementoManifest entityManifest) { protected void setCatalogItemId(BrooklynObject item, String catalogItemId) { if (catalogItemId!=null) { + // TODO add support for nested catalog superids here. ((BrooklynObjectInternal)item).setCatalogItemId(catalogItemId); } } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java index d435135424..fdfc624983 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java @@ -18,10 +18,22 @@ */ package org.apache.brooklyn.core.objs; +import java.util.ArrayDeque; import java.util.Collections; +import java.util.Deque; +import java.util.List; import java.util.Map; import java.util.Set; +import com.google.common.collect.ImmutableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + import org.apache.brooklyn.api.internal.ApiObjectsFactory; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.core.entity.AbstractEntity; @@ -50,7 +62,7 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal { @SetFromFlag("id") private String id = Identifiers.makeRandomLowercaseId(10); - private String catalogItemId; + private Deque catalogItemIdStack = new ArrayDeque<>(); /** callers (only in TagSupport) should synchronize on this for all access */ @SetFromFlag("tags") @@ -83,7 +95,7 @@ public AbstractBrooklynObject(Map properties) { // correct behaviour should be to inherit context's search path, perhaps, though maybe that's better done as spec? // in any case, should not define it as _the_ catalog item ID; also see assignment based on parent // in CatalogUtils.setCatalogItemIdOnAddition - catalogItemId = ApiObjectsFactory.get().getCatalogItemIdFromContext(); + setCatalogItemId(ApiObjectsFactory.get().getCatalogItemIdFromContext()); // rely on sub-class to call configure(properties), because otherwise its fields will not have been initialised } @@ -190,12 +202,33 @@ public String getId() { @Override public void setCatalogItemId(String id) { - this.catalogItemId = id; + catalogItemIdStack.clear(); + nestCatalogItemId(id); + } + + @Override + public void setCatalogItemIds(List ids) { + catalogItemIdStack.clear(); + catalogItemIdStack.addAll(ids); + } + + @Override + public void nestCatalogItemId(String id) { + if (null != id) { + catalogItemIdStack.addFirst(id); + } + } + + public List getCatalogItemSuperIds() { + return ImmutableList.copyOf(catalogItemIdStack); } @Override public String getCatalogItemId() { - return catalogItemId; + if (catalogItemIdStack.size() != 0) { + return catalogItemIdStack.getFirst(); + } + return null; } protected void onTagsChanged() { diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java index 21956f871b..c9bdc35311 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java @@ -288,7 +288,7 @@ protected void onConfigChanging(ConfigKey key, Object val) { doReconfigureConfig(key, (T)val); } } - + @Override protected void onConfigChanged(ConfigKey key, Object val) { onChanged(); @@ -308,7 +308,7 @@ public void refreshInheritedConfigOfChildren() { protected ExecutionContext getContext() { return AbstractEntityAdjunct.this.execution; } - + @Override protected AbstractConfigMapImpl getConfigsInternal() { return configsInternal; @@ -342,7 +342,7 @@ protected K getRequiredConfig(ConfigKey key) { public T setConfig(ConfigKey key, T val) { return config().set(key, val); } - + /** * Invoked whenever a config change is applied after management is started. * Default implementation throws an exception to disallow the change. @@ -379,7 +379,7 @@ public void setEntity(EntityLocal entity) { this.entity = entity; this.execution = ((EntityInternal) entity).getExecutionContext(); if (entity!=null && getCatalogItemId() == null) { - setCatalogItemId(entity.getCatalogItemId()); + setCatalogItemIds(entity.getCatalogItemSuperIds()); } } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java index 3fc2c99be2..4dcbf1aee3 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java @@ -18,6 +18,7 @@ */ package org.apache.brooklyn.core.objs; +import java.util.List; import java.util.Map; import org.apache.brooklyn.api.mgmt.rebind.RebindSupport; @@ -37,6 +38,9 @@ public interface BrooklynObjectInternal extends BrooklynObject, Rebindable { void setCatalogItemId(String id); + void setCatalogItemIds(List id); + + void nestCatalogItemId(String id); // subclasses typically apply stronger typing @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java index 6090c5b490..77dfcf4e91 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java @@ -33,6 +33,7 @@ import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.entity.EntityTypeRegistry; import org.apache.brooklyn.api.entity.Group; +import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.location.LocationSpec; import org.apache.brooklyn.api.objs.SpecParameter; import org.apache.brooklyn.api.policy.Policy; @@ -246,7 +247,7 @@ protected T loadUnitializedEntity(final T entity, final Entit ((AbstractEntity)entity).setDisplayName(spec.getDisplayName()); if (spec.getCatalogItemId()!=null) { - ((AbstractEntity)entity).setCatalogItemId(spec.getCatalogItemId()); + ((AbstractEntity)entity).setCatalogItemIds(spec.getCatalogItemSuperIds()); } entity.tags().addTags(spec.getTags()); @@ -344,7 +345,7 @@ public void run() { // are already accessible through the REST API. LocationSpec taggedSpec = LocationSpec.create(locationSpec) .tag(BrooklynTags.newOwnerEntityTag(entity.getId())); - ((AbstractEntity)entity).addLocations(MutableList.of( + ((AbstractEntity)entity).addLocations(MutableList.of( managementContext.getLocationManager().createLocation(taggedSpec))); } ((AbstractEntity)entity).addLocations(spec.getLocations()); diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java index 4ba06588e4..57098b3873 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java @@ -118,7 +118,7 @@ public T createLocation(LocationSpec spec) { ((AbstractLocation)loc).setDisplayName(spec.getDisplayName()); if (spec.getCatalogItemId()!=null) { - ((AbstractLocation)loc).setCatalogItemId(spec.getCatalogItemId()); + ((AbstractLocation)loc).setCatalogItemIds(spec.getCatalogItemSuperIds()); } loc.tags().addTags(spec.getTags()); diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java index 2fc91ef819..fd444a0196 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java @@ -107,7 +107,7 @@ public T createPolicy(PolicySpec spec) { ((AbstractPolicy)pol).setDisplayName(spec.getDisplayName()); } if (spec.getCatalogItemId()!=null) { - ((AbstractPolicy)pol).setCatalogItemId(spec.getCatalogItemId()); + ((AbstractPolicy)pol).setCatalogItemIds(spec.getCatalogItemSuperIds()); } pol.tags().addTags(spec.getTags()); @@ -148,7 +148,7 @@ public T createEnricher(EnricherSpec spec) { ((AbstractEnricher)enricher).setDisplayName(spec.getDisplayName()); if (spec.getCatalogItemId()!=null) { - ((AbstractEnricher)enricher).setCatalogItemId(spec.getCatalogItemId()); + ((AbstractEnricher)enricher).setCatalogItemIds(spec.getCatalogItemSuperIds()); } enricher.tags().addTags(spec.getTags()); diff --git a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java index cee97ee5ab..a6e75e29b3 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java @@ -325,7 +325,7 @@ protected Entity createSimpleEntity(String bundleUrl, Class clazz) { .plan("{\"services\":[{\"type\": \"" + clazz.getName() + "\"}]}") .build(); mgmt.getCatalog().addItem(item); - ((EntityInternal)entity).setCatalogItemId(item.getId()); + ((EntityInternal)entity).setCatalogItemIds(item.getCatalogItemSuperIds()); return entity; } From a9e961855f4e5874939602bc969ca87f537a0031 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 20 Sep 2016 15:51:47 +0100 Subject: [PATCH 04/35] Fixes to get CatalogYamlEntityTest.testCatalogItemIdInReferencedItems working. Haven't re-run all unit tests yet. --- .../brooklyn/api/internal/AbstractBrooklynObjectSpec.java | 8 +++++++- .../brooklyn/camp/brooklyn/ConfigInheritanceYamlTest.java | 1 + .../camp/brooklyn/catalog/CatalogYamlEntityTest.java | 6 +++++- .../apache/brooklyn/core/mgmt/EntityManagementUtils.java | 3 +-- .../core/typereg/AbstractTypePlanTransformer.java | 2 +- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java index 048a44014b..d7442febd7 100644 --- a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java +++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java @@ -110,6 +110,12 @@ public SpecT catalogItemId(String val) { return nestCatalogItemId(val); } + public SpecT catalogItemIds(List ids) { + catalogItemIdStack.clear(); + catalogItemIdStack.addAll(ids); + return self(); + } + /** * Adds (stacks) the catalog item id of a wrapping specification. * Does nothing if the value is null. @@ -120,7 +126,7 @@ public SpecT catalogItemId(String val) { */ @Beta public SpecT nestCatalogItemId(String val) { - if (null != val) { + if (null != val && (catalogItemIdStack.isEmpty() || !catalogItemIdStack.element().equals(val))) { catalogItemIdStack.addFirst(val); } return self(); 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 89f282b262..458c5cabcb 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 @@ -42,6 +42,7 @@ import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.entity.TestEntityImpl; import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess; +import org.apache.brooklyn.entity.software.base.SoftwareProcess; import org.apache.brooklyn.entity.stock.BasicApplication; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool; diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java index dff66898ad..4e6cfb8bec 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java @@ -37,6 +37,7 @@ import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.entity.TestEntityImpl; import org.apache.brooklyn.core.typereg.RegisteredTypes; +import org.apache.brooklyn.entity.software.base.SoftwareProcess; import org.apache.brooklyn.entity.stock.BasicApplication; import org.apache.brooklyn.entity.stock.BasicEntity; import org.apache.brooklyn.util.exceptions.Exceptions; @@ -634,10 +635,13 @@ public void testCatalogItemIdInReferencedItems() throws Exception { " - serviceType: "+ver(symbolicNameOuter); Entity app = createAndStartApplication(yaml); + Entity entity = app.getChildren().iterator().next(); assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); - // TODO check nested ids + assertEquals(entity.getCatalogItemSuperIds().size(), 2); + assertEquals(entity.getCatalogItemSuperIds().get(0), ver(symbolicNameOuter)); + assertEquals(entity.getCatalogItemSuperIds().get(1), ver(symbolicNameInner)); deleteCatalogEntity(symbolicNameInner); deleteCatalogEntity(symbolicNameOuter); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java index cfee58f6cf..70ce4fb271 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java @@ -259,8 +259,7 @@ private static void mergeWrapperParentSpecToChildEntity(EntitySpec result = createSpec(type, context); // see notes on catalogItemIdIfNotNull - result.catalogItemIdIfNotNull(type.getId()); + result.nestCatalogItemId(type.getId()); return result; } catch (Exception e) { throw Exceptions.propagate(e); } } From 39dc1ccdf539a4453889f91ad1d3d6cde11abaf7 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 21 Sep 2016 11:46:35 +0100 Subject: [PATCH 05/35] Test with a 'catalog sandwich'. The purpose of this test is to illustrate that the full stack of nested catalog items is not searched for classloaders. --- .../catalog/CatalogYamlEntityTest.java | 100 +++++++++++++----- .../core/mgmt/osgi/OsgiStandaloneTest.java | 2 + .../brooklyn/util/osgi/OsgiTestResources.java | 2 + 3 files changed, 80 insertions(+), 24 deletions(-) diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java index 4e6cfb8bec..a61725024b 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java @@ -18,6 +18,9 @@ */ package org.apache.brooklyn.camp.brooklyn.catalog; +import static org.apache.brooklyn.util.osgi.OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_MESSAGE_RESOURCE; +import static org.apache.commons.io.FileUtils.getFile; +import static org.apache.commons.io.FileUtils.readFileToString; import static com.google.common.base.Preconditions.checkNotNull; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -34,13 +37,20 @@ import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.entity.BrooklynConfigKeys; +import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest; import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.entity.TestEntityImpl; import org.apache.brooklyn.core.typereg.RegisteredTypes; import org.apache.brooklyn.entity.software.base.SoftwareProcess; +import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess; import org.apache.brooklyn.entity.stock.BasicApplication; import org.apache.brooklyn.entity.stock.BasicEntity; +import org.apache.brooklyn.test.support.TestResourceUnavailableException; +import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.osgi.OsgiTestResources; +import org.apache.commons.io.FileUtils; import org.testng.Assert; import org.testng.annotations.Test; @@ -50,6 +60,15 @@ public class CatalogYamlEntityTest extends AbstractYamlTest { + private static final String SIMPLE_ENTITY_TYPE = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY; + private static final String MORE_ENTITIES_POM_PROPERTIES_PATH = + "META-INF/maven/org.apache.brooklyn.test.resources.osgi/brooklyn-test-osgi-more-entities/pom.properties"; + + @Override + protected boolean disableOsgi() { + return false; + } + @Test public void testAddCatalogItemVerySimple() throws Exception { String symbolicName = "my.catalog.app.id.load"; @@ -57,7 +76,7 @@ public void testAddCatalogItemVerySimple() throws Exception { RegisteredType item = mgmt().getTypeRegistry().get(symbolicName, TEST_VERSION); String planYaml = RegisteredTypes.getImplementationDataStringForSpec(item); - assertTrue(planYaml.indexOf("services:")>=0, "expected 'services:' block: "+item+"\n"+planYaml); + assertTrue(planYaml.contains("services:"), "expected 'services:' block: "+item+"\n"+planYaml); deleteCatalogEntity(symbolicName); } @@ -178,7 +197,7 @@ public void testLaunchApplicationUnversionedCatalogReference() throws Exception public void testLaunchApplicationWithCatalogReferencingOtherCatalog() throws Exception { String referencedSymbolicName = "my.catalog.app.id.referenced"; String referrerSymbolicName = "my.catalog.app.id.referring"; - + addCatalogItems( "brooklyn.catalog:", " name: My Catalog App", @@ -192,10 +211,10 @@ public void testLaunchApplicationWithCatalogReferencingOtherCatalog() throws Exc " - id: " + referrerSymbolicName, " item:", " type: " + ver(referencedSymbolicName, TEST_VERSION)); - + RegisteredType referrer = mgmt().getTypeRegistry().get(referrerSymbolicName, TEST_VERSION); String planYaml = RegisteredTypes.getImplementationDataStringForSpec(referrer); - Assert.assertTrue(planYaml.indexOf("services")>=0, "expected services in: "+planYaml); + Assert.assertTrue(planYaml.contains("services"), "expected services in: "+planYaml); Entity app = createAndStartApplication("services:", "- type: " + ver(referrerSymbolicName, TEST_VERSION)); @@ -229,7 +248,7 @@ public void testLaunchApplicationWithCatalogReferencingOtherCatalogInTwoSteps() public void testLaunchApplicationChildWithCatalogReferencingOtherCatalog() throws Exception { String referencedSymbolicName = "my.catalog.app.id.child.referenced"; String referrerSymbolicName = "my.catalog.app.id.child.referring"; - + addCatalogEntity(IdAndVersion.of(referencedSymbolicName, TEST_VERSION), TestEntity.class.getName()); addCatalogItems( @@ -242,7 +261,7 @@ public void testLaunchApplicationChildWithCatalogReferencingOtherCatalog() throw " - type: " + BasicEntity.class.getName(), " brooklyn.children:", " - type: " + ver(referencedSymbolicName, TEST_VERSION)); - + Entity app = createAndStartApplication( "services:", "- type: "+BasicEntity.class.getName(), @@ -358,7 +377,7 @@ public void testForcedUpdatingItem() { public void testCreateSpecFromCatalogItem() { String id = "my.catalog.app.id.create_spec"; addCatalogEntity(IdAndVersion.of(id, TEST_VERSION), TestEntity.class.getName()); - + BrooklynTypeRegistry catalog = mgmt().getTypeRegistry(); RegisteredType item = catalog.get(id, TEST_VERSION); EntitySpec spec = catalog.createSpec(item, null, EntitySpec.class); @@ -366,7 +385,7 @@ public void testCreateSpecFromCatalogItem() { AbstractBrooklynObjectSpec spec2 = catalog.createSpec(item, null, null); Assert.assertNotNull(spec2); } - + @Test public void testMissingTypeDoesNotRecurse() { String symbolicName = "my.catalog.app.id.basic"; @@ -382,8 +401,8 @@ public void testMissingTypeDoesNotRecurse() { @Test public void testVersionedTypeDoesNotRecurse() throws Exception { - // Alternatively, we could change this to tell foo:v2 reference foo:v1, but that feels - // like a bad idea! + // Alternatively, we could change this to tell foo:v2 reference foo:v1, but that feels + // like a bad idea! String symbolicName = "my.catalog.app.id.basic"; addCatalogEntity(IdAndVersion.of(symbolicName, TEST_VERSION), TestEntity.class.getName()); @@ -400,7 +419,7 @@ public void testVersionedTypeDoesNotRecurse() throws Exception { public void testIndirectRecursionFails() throws Exception { String callerSymbolicName = "my.catalog.app.id.caller"; String calleeSymbolicName = "my.catalog.app.id.callee"; - + // Need to have a stand alone caller first so we can create an item to depend on it. // After that replace it/insert a new version which completes the cycle addCatalogEntity(IdAndVersion.of(callerSymbolicName, TEST_VERSION + "-pre"), TestEntity.class.getName()); @@ -422,7 +441,7 @@ public void testChildItemsDoNotRecurse() throws Exception { // Need to have a stand alone caller first so we can create an item to depend on it. // After that replace it/insert a new version which completes the cycle - + addCatalogEntity(IdAndVersion.of(callerSymbolicName, TEST_VERSION + "-pre"), TestEntity.class.getName()); addCatalogEntity(IdAndVersion.of(calleeSymbolicName, TEST_VERSION), callerSymbolicName); @@ -498,7 +517,7 @@ public void testExplicitFlagsAppliesToCatalogItem() throws Exception { Entity testEntity = Iterables.getOnlyElement(app.getChildren()); assertEquals(testEntity.config().get(TestEntity.CONF_NAME), val); } - + @Test public void testConfigAppliedToCatalogItemImpl() throws Exception { addCatalogEntity("test", TestEntityImpl.class.getName()); @@ -613,11 +632,45 @@ public void testItemWithBrooklynParameters() throws Exception { mgmt().getCatalog().deleteCatalogItem(id, version); } - // The test is disabled as it fails. The entity will get assigned the outer-most catalog - // item which doesn't have the necessary libraries with visibility to the entity's classpath - // When loading resources from inside the entity then we will use the wrong BCLCS. A workaround - // has been implemented which explicitly adds the entity's class loader to the fallbacks. - @Test(groups="WIP") + @Test + public void testDeepCatalogItemCanLoadResources() throws Exception { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); + + String symbolicNameInner = "my.catalog.app.id.inner"; + String symbolicNameFiller = "my.catalog.app.id.filler"; + String symbolicNameOuter = "my.catalog.app.id.outer"; + addCatalogItems( + "brooklyn.catalog:", + " version: " + TEST_VERSION, + " items:", + " - id: " + symbolicNameInner, + " name: My Catalog App", + " brooklyn.libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, + " item: " + SIMPLE_ENTITY_TYPE, + " - id: " + symbolicNameFiller, + " name: Filler App", + " brooklyn.libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_URL, + " item: " + symbolicNameInner, + " - id: " + symbolicNameOuter, + " item: " + symbolicNameFiller); + + String yaml = "name: " + symbolicNameOuter + "\n" + + "services: \n" + + " - serviceType: "+ver(symbolicNameOuter); + Entity app = createAndStartApplication(yaml); + Entity entity = app.getChildren().iterator().next(); + + final String catalogBom = ResourceUtils.create(entity).getResourceAsString("classpath://" + MORE_ENTITIES_POM_PROPERTIES_PATH); + assertTrue(catalogBom.contains("artifactId=brooklyn-test-osgi-more-entities")); + + deleteCatalogEntity(symbolicNameOuter); + deleteCatalogEntity(symbolicNameFiller); + deleteCatalogEntity(symbolicNameInner); + } + + @Test public void testCatalogItemIdInReferencedItems() throws Exception { String symbolicNameInner = "my.catalog.app.id.inner"; String symbolicNameOuter = "my.catalog.app.id.outer"; @@ -637,7 +690,6 @@ public void testCatalogItemIdInReferencedItems() throws Exception { Entity app = createAndStartApplication(yaml); Entity entity = app.getChildren().iterator().next(); - assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); assertEquals(entity.getCatalogItemSuperIds().size(), 2); assertEquals(entity.getCatalogItemSuperIds().get(0), ver(symbolicNameOuter)); @@ -650,10 +702,10 @@ public void testCatalogItemIdInReferencedItems() throws Exception { private void registerAndLaunchAndAssertSimpleEntity(String symbolicName, String serviceType) throws Exception { registerAndLaunchAndAssertSimpleEntity(symbolicName, serviceType, serviceType); } - + private void registerAndLaunchAndAssertSimpleEntity(String symbolicName, String serviceType, String expectedType) throws Exception { addCatalogEntity(IdAndVersion.of(symbolicName, TEST_VERSION), serviceType); - + Entity app = createAndStartApplication( "services:", "- type: "+ver(symbolicName, TEST_VERSION)); @@ -667,11 +719,11 @@ private void registerAndLaunchAndAssertSimpleEntity(String symbolicName, String public static class IdAndVersion { public final String id; public final String version; - + public static IdAndVersion of(String id, String version) { return new IdAndVersion(id, version); } - + public IdAndVersion(String id, String version) { this.id = checkNotNull(id, "id"); this.version = checkNotNull(version, "version"); @@ -681,7 +733,7 @@ public IdAndVersion(String id, String version) { private void addCatalogEntity(String symbolicName, String entityType) { addCatalogEntity(IdAndVersion.of(symbolicName, TEST_VERSION), entityType); } - + private void addCatalogEntity(IdAndVersion idAndVersion, String serviceType) { addCatalogItems( "brooklyn.catalog:", diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiStandaloneTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiStandaloneTest.java index 35429f136b..15b9ae90fc 100644 --- a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiStandaloneTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiStandaloneTest.java @@ -50,7 +50,9 @@ public class OsgiStandaloneTest extends OsgiTestBase { public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH; public static final String BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FULL = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FULL; + public static final String BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH; public static final String BROOKLYN_TEST_OSGI_ENTITIES_URL = "classpath:"+BROOKLYN_TEST_OSGI_ENTITIES_PATH; + public static final String BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_URL = "classpath:"+BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH; public static final String BROOKLYN_TEST_OSGI_ENTITIES_NAME = "org.apache.brooklyn.test.resources.osgi.brooklyn-test-osgi-entities"; public static final String BROOKLYN_TEST_OSGI_ENTITIES_VERSION = "0.1.0"; diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java b/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java index 39ae99c80d..b778dc94f5 100644 --- a/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java +++ b/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java @@ -44,6 +44,8 @@ public class OsgiTestResources { public static final String BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FULL = "org.apache.brooklyn.test.resources.osgi."+BROOKLYN_TEST_OSGI_ENTITIES_SYMBOLIC_NAME_FINAL_PART; public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = "/brooklyn/osgi/brooklyn-test-osgi-entities.jar"; + public static final String BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH = "/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar"; + public static final String BROOKLYN_TEST_OSGI_ENTITIES_MESSAGE_RESOURCE = "/org/apache/brooklyn/test/osgi/resources/message.txt"; public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_APPLICATION = "org.apache.brooklyn.test.osgi.entities.SimpleApplication"; public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY = "org.apache.brooklyn.test.osgi.entities.SimpleEntity"; public static final String BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_POLICY = "org.apache.brooklyn.test.osgi.entities.SimplePolicy"; From 47c5580e9ea9b5cfb6a42c84428c641dbe88f244 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 21 Sep 2016 16:36:49 +0100 Subject: [PATCH 06/35] Do resource lookup from nested catalog ids. Fixes testDeepCatalogItemCanLoadResources. --- .../internal/AbstractManagementContext.java | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java index 89d5b3c67a..42c9c14a77 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java @@ -131,20 +131,18 @@ private static DataGridFactory loadDataGridFactory(BrooklynProperties properties public BrooklynClassLoadingContext apply(@Nullable Object input) { if (input instanceof EntityInternal) { EntityInternal internal = (EntityInternal)input; - if (internal.getCatalogItemId() != null) { - RegisteredType item = internal.getManagementContext().getTypeRegistry().get(internal.getCatalogItemId()); - - if (item != null) { - BrooklynClassLoadingContext itemLoader = CatalogUtils.newClassLoadingContext(internal.getManagementContext(), item); - // Falls back to the entity's class loader - JavaBrooklynClassLoadingContext entityLoader = JavaBrooklynClassLoadingContext.create(input.getClass().getClassLoader()); - BrooklynClassLoadingContext seqLoader = new BrooklynClassLoadingContextSequential(internal.getManagementContext(), itemLoader, entityLoader); - return seqLoader; - } else { - log.error("Can't find catalog item " + internal.getCatalogItemId() + - " used for instantiating entity " + internal + - ". Falling back to application classpath."); + final List catalogItemSuperIds = internal.getCatalogItemSuperIds(); + if (catalogItemSuperIds.size() > 0) { + BrooklynClassLoadingContextSequential seqLoader = new BrooklynClassLoadingContextSequential(internal.getManagementContext()); + for (String catalogItemId : catalogItemSuperIds) { + addCatalogItemContext(internal, seqLoader, catalogItemId); } + // TODO what if not all items were found? need to consider what the right behaviour is. + // TODO for now take the course of using whatever items we *did* find + if (seqLoader.getPrimaries().size() != catalogItemSuperIds.size()) { + log.error("Couldn't find all catalog items used for instantiating entity " + internal); + } + return seqLoader; } return apply(internal.getManagementSupport()); } @@ -158,6 +156,19 @@ public BrooklynClassLoadingContext apply(@Nullable Object input) { }); } + private static void addCatalogItemContext(EntityInternal entity, BrooklynClassLoadingContextSequential loader, String catalogItemId) { + RegisteredType item = entity.getManagementContext().getTypeRegistry().get(catalogItemId); + + if (item != null) { + BrooklynClassLoadingContext itemLoader = CatalogUtils.newClassLoadingContext(entity.getManagementContext(), item); + loader.add(itemLoader); + } else { + log.error("Can't find catalog item " + catalogItemId + + " used for instantiating entity " + entity + + ". Falling back to application classpath."); + } + } + private final AtomicLong totalEffectorInvocationCount = new AtomicLong(); protected DeferredBrooklynProperties configMap; From a5c697822aeb6d7975aab7138d2ac6628f60c5f9 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Fri, 23 Sep 2016 11:53:09 +0100 Subject: [PATCH 07/35] Use entity classloader as well as specified libraries. See https://github.com/apache/brooklyn-server/pull/338#discussion_r80220390. --- .../core/mgmt/internal/AbstractManagementContext.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java index 42c9c14a77..a92a07b745 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java @@ -133,7 +133,8 @@ public BrooklynClassLoadingContext apply(@Nullable Object input) { EntityInternal internal = (EntityInternal)input; final List catalogItemSuperIds = internal.getCatalogItemSuperIds(); if (catalogItemSuperIds.size() > 0) { - BrooklynClassLoadingContextSequential seqLoader = new BrooklynClassLoadingContextSequential(internal.getManagementContext()); + BrooklynClassLoadingContextSequential seqLoader = + new BrooklynClassLoadingContextSequential(internal.getManagementContext()); for (String catalogItemId : catalogItemSuperIds) { addCatalogItemContext(internal, seqLoader, catalogItemId); } @@ -142,6 +143,9 @@ public BrooklynClassLoadingContext apply(@Nullable Object input) { if (seqLoader.getPrimaries().size() != catalogItemSuperIds.size()) { log.error("Couldn't find all catalog items used for instantiating entity " + internal); } + JavaBrooklynClassLoadingContext entityLoader = + JavaBrooklynClassLoadingContext.create(input.getClass().getClassLoader()); + seqLoader.add(entityLoader); return seqLoader; } return apply(internal.getManagementSupport()); From 42b4c3e0cc4ab268115f5c7231c6adbbe68e4aca Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 26 Sep 2016 16:03:17 +0100 Subject: [PATCH 08/35] Implement getCatalogItemSuperIds in CatalogItemDtoAbstract. As noted at https://github.com/apache/brooklyn-server/pull/338#discussion_r79871837 --- .../core/catalog/internal/CatalogItemDtoAbstract.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java index 41ed6a132a..82a210f596 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Set; @@ -104,6 +105,11 @@ public String getCatalogItemId() { return CatalogUtils.getVersionedId(getSymbolicName(), getVersion()); } + @Override + public List getCatalogItemSuperIds() { + return ImmutableList.of(getCatalogItemId()); + } + @Override public String getJavaType() { if (javaType != null) return javaType; From 3e05d39a3b5567a81d7f835362e2eb2326c830b5 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 26 Sep 2016 16:49:50 +0100 Subject: [PATCH 09/35] Add (disabled) rebind test for deep catalog item nesting. This fails with the following exception: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: Failure rebinding: problem creating ENTITY zmm0lmrzll of type org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl: Unable to load org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl from []: Invalid class: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl: ClassNotFoundException: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl at org.apache.brooklyn.util.exceptions.Exceptions.propagate(Exceptions.java:129) at org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl.rebind(RebindManagerImpl.java:513) at org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils.rebindAll(RebindTestUtils.java:446) at org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils.rebind(RebindTestUtils.java:328) at org.apache.brooklyn.core.mgmt.rebind.RebindTestFixture.rebind(RebindTestFixture.java:281) at org.apache.brooklyn.camp.brooklyn.AbstractYamlRebindTest.rebind(AbstractYamlRebindTest.java:86) at org.apache.brooklyn.core.mgmt.rebind.RebindTestFixture.rebind(RebindTestFixture.java:217) at org.apache.brooklyn.camp.brooklyn.RebindOsgiTest.testReboundDeepCatalogItemCanLoadResources(RebindOsgiTest.java:201) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84) at org.testng.internal.Invoker.invokeMethod(Invoker.java:714) at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901) at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231) at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127) at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111) at org.testng.TestRunner.privateRun(TestRunner.java:767) at org.testng.TestRunner.run(TestRunner.java:617) at org.testng.SuiteRunner.runTest(SuiteRunner.java:348) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:343) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:305) at org.testng.SuiteRunner.run(SuiteRunner.java:254) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224) at org.testng.TestNG.runSuitesLocally(TestNG.java:1149) at org.testng.TestNG.run(TestNG.java:1057) at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72) at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:124) Caused by: java.util.concurrent.ExecutionException: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: Failure rebinding: problem creating ENTITY zmm0lmrzll of type org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl: Unable to load org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl from []: Invalid class: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl: ClassNotFoundException: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl at java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.util.concurrent.FutureTask.get(FutureTask.java:192) at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture.java:63) at org.apache.brooklyn.util.core.task.BasicTask.get(BasicTask.java:361) at org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl.rebind(RebindManagerImpl.java:511) ... 29 more Caused by: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: Failure rebinding: problem creating ENTITY zmm0lmrzll of type org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl: Unable to load org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl from []: Invalid class: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl: ClassNotFoundException: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl at org.apache.brooklyn.util.exceptions.Exceptions.create(Exceptions.java:430) at org.apache.brooklyn.core.mgmt.rebind.RebindExceptionHandlerImpl.onDoneImpl(RebindExceptionHandlerImpl.java:497) at org.apache.brooklyn.core.mgmt.rebind.RebindExceptionHandlerImpl.onDone(RebindExceptionHandlerImpl.java:413) at org.apache.brooklyn.core.mgmt.rebind.RebindIteration.run(RebindIteration.java:268) at org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl.rebindImpl(RebindManagerImpl.java:558) at org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl$3.call(RebindManagerImpl.java:508) at org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl$3.call(RebindManagerImpl.java:506) at org.apache.brooklyn.util.core.task.BasicExecutionManager$SubmissionCallable.call(BasicExecutionManager.java:519) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.IllegalStateException: problem creating ENTITY zmm0lmrzll of type org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl at org.apache.brooklyn.core.mgmt.rebind.RebindExceptionHandlerImpl.onCreateFailed(RebindExceptionHandlerImpl.java:265) at org.apache.brooklyn.core.mgmt.rebind.RebindIteration.instantiateLocationsAndEntities(RebindIteration.java:459) at org.apache.brooklyn.core.mgmt.rebind.RebindIteration.doRun(RebindIteration.java:240) at org.apache.brooklyn.core.mgmt.rebind.InitialFullRebindIteration.doRun(InitialFullRebindIteration.java:69) at org.apache.brooklyn.core.mgmt.rebind.RebindIteration.run(RebindIteration.java:266) ... 8 more Caused by: java.lang.IllegalStateException: Unable to load org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl from []: Invalid class: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl: ClassNotFoundException: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl at org.apache.brooklyn.util.guava.IllegalStateExceptionSupplier.get(IllegalStateExceptionSupplier.java:40) at org.apache.brooklyn.util.guava.IllegalStateExceptionSupplier.get(IllegalStateExceptionSupplier.java:26) at org.apache.brooklyn.util.guava.Maybe$Absent.getException(Maybe.java:327) at org.apache.brooklyn.util.guava.Maybe$Absent.get(Maybe.java:321) at org.apache.brooklyn.core.mgmt.classloading.AbstractBrooklynClassLoadingContext.loadClass(AbstractBrooklynClassLoadingContext.java:55) at org.apache.brooklyn.core.mgmt.rebind.RebindIteration$BrooklynObjectInstantiator.load(RebindIteration.java:954) at org.apache.brooklyn.core.mgmt.rebind.RebindIteration$BrooklynObjectInstantiator.newEntity(RebindIteration.java:874) at org.apache.brooklyn.core.mgmt.rebind.RebindIteration.instantiateLocationsAndEntities(RebindIteration.java:454) ... 11 more Caused by: org.apache.brooklyn.util.exceptions.PropagatedRuntimeException: Unable to load org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl from []: Invalid class: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl: ClassNotFoundException: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl at org.apache.brooklyn.util.exceptions.Exceptions.create(Exceptions.java:430) at org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential.tryLoadClass(BrooklynClassLoadingContextSequential.java:88) at org.apache.brooklyn.core.mgmt.classloading.AbstractBrooklynClassLoadingContext.tryLoadClass(AbstractBrooklynClassLoadingContext.java:61) ... 15 more Caused by: java.lang.IllegalStateException: Invalid class: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl at org.apache.brooklyn.util.guava.IllegalStateExceptionSupplier.get(IllegalStateExceptionSupplier.java:40) at org.apache.brooklyn.util.guava.IllegalStateExceptionSupplier.get(IllegalStateExceptionSupplier.java:26) at org.apache.brooklyn.util.guava.Maybe$Absent.getException(Maybe.java:327) at org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential.tryLoadClass(BrooklynClassLoadingContextSequential.java:85) ... 16 more Caused by: java.lang.ClassNotFoundException: org.apache.brooklyn.test.osgi.entities.SimpleEntityImpl at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at org.apache.brooklyn.util.javalang.AggregateClassLoader.findClass(AggregateClassLoader.java:135) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext.tryLoadClass0(JavaBrooklynClassLoadingContext.java:101) at org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext.tryLoadClass(JavaBrooklynClassLoadingContext.java:84) at org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential.tryLoadClass(BrooklynClassLoadingContextSequential.java:81) ... 16 more --- .../camp/brooklyn/RebindOsgiTest.java | 54 +++++++++++++++++++ .../catalog/CatalogYamlEntityTest.java | 1 - 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java index fe071a5ba5..37c15e468b 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java @@ -22,6 +22,7 @@ import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; import java.io.File; import java.util.List; @@ -43,6 +44,7 @@ import org.apache.brooklyn.core.sensor.Sensors; import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.test.support.TestResourceUnavailableException; +import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.core.osgi.Osgis; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.guava.Maybe; @@ -76,6 +78,8 @@ public class RebindOsgiTest extends AbstractYamlRebindTest { private static final String OSGI_OBJECT_TYPE = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_OBJECT; private static final String OSGI_ENTITY_CONFIG_NAME = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY_CONFIG_NAME; private static final String OSGI_ENTITY_SENSOR_NAME = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY_SENSOR_NAME; + private static final String MORE_ENTITIES_POM_PROPERTIES_PATH = + "META-INF/maven/org.apache.brooklyn.test.resources.osgi/brooklyn-test-osgi-more-entities/pom.properties"; private List bundleUrlsToInstallOnRebind; @@ -159,6 +163,56 @@ public void testValInEntity(Object val, boolean useOsgi) throws Exception { assertEquals(newEntity.config().get(TestEntity.CONF_OBJECT), val); } + + @Test(groups = "Broken") + public void testReboundDeepCatalogItemCanLoadResources() throws Exception { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH); + + String symbolicNameInner = "my.catalog.app.id.inner"; + String symbolicNameFiller = "my.catalog.app.id.filler"; + String symbolicNameOuter = "my.catalog.app.id.outer"; + String appVersion = "0.1.0"; + + String appCatalogFormat = Joiner.on("\n").join( + "brooklyn.catalog:", + " version: " + TEST_VERSION, + " items:", + " - id: " + symbolicNameInner, + " name: My Catalog App", + " brooklyn.libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, + " item: " + OSGI_ENTITY_TYPE, + " - id: " + symbolicNameFiller, + " name: Filler App", + " brooklyn.libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_URL, + " item: " + symbolicNameInner, + " - id: " + symbolicNameOuter, + " item: " + symbolicNameFiller); + + // Create the catalog items + addCatalogItems(String.format(appCatalogFormat, appVersion)); + + String yaml = "name: " + symbolicNameOuter + "\n" + + "services: \n" + + " - serviceType: "+ver(symbolicNameOuter); + origApp = (StartableApplication) createAndStartApplication(yaml); + + // Rebind + rebind(); + + Entity newEntity = Iterables.getOnlyElement(newApp.getChildren()); + + final String catalogBom = ResourceUtils.create(newEntity) + .getResourceAsString("classpath://" + MORE_ENTITIES_POM_PROPERTIES_PATH); + assertTrue(catalogBom.contains("artifactId=brooklyn-test-osgi-more-entities")); + + deleteCatalogEntity(symbolicNameOuter); + deleteCatalogEntity(symbolicNameFiller); + deleteCatalogEntity(symbolicNameInner); + } + @Test public void testValInEntityFromOtherBundle() throws Exception { TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OSGI_BUNDLE_PATH); diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java index a61725024b..cc26c22715 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java @@ -634,7 +634,6 @@ public void testItemWithBrooklynParameters() throws Exception { @Test public void testDeepCatalogItemCanLoadResources() throws Exception { - TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); String symbolicNameInner = "my.catalog.app.id.inner"; String symbolicNameFiller = "my.catalog.app.id.filler"; From 4c7ca74f6a0a2092d5c7c6cdc6e711ab5fb5f75c Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 27 Sep 2016 11:21:46 +0100 Subject: [PATCH 10/35] Add support for catalogItemSuperIds to rebind. Fixes testReboundDeepCatalogItemCanLoadResources. --- .../mementos/BrooklynMementoManifest.java | 30 +++-- .../api/mgmt/rebind/mementos/Memento.java | 33 +++-- .../camp/brooklyn/RebindOsgiTest.java | 6 +- .../core/catalog/internal/CatalogUtils.java | 30 ++++- .../internal/AbstractManagementContext.java | 25 +--- ...BrooklynMementoPersisterToObjectStore.java | 58 ++++++-- .../core/mgmt/rebind/RebindIteration.java | 125 +++++++++--------- .../core/mgmt/rebind/dto/AbstractMemento.java | 16 ++- .../dto/BrooklynMementoManifestImpl.java | 5 +- .../rebind/dto/EntityMementoManifestImpl.java | 17 ++- .../mgmt/rebind/dto/MementosGenerators.java | 7 +- .../brooklyn/util/core/xstream/XmlUtil.java | 26 ++-- 12 files changed, 229 insertions(+), 149 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java index a96601ff49..d3c3cc3d98 100644 --- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java +++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java @@ -20,6 +20,7 @@ import java.io.Serializable; import java.util.Collection; +import java.util.List; import java.util.Map; import org.apache.brooklyn.api.objs.Identifiable; @@ -32,30 +33,31 @@ public interface BrooklynMementoManifest extends Serializable { public interface EntityMementoManifest extends Identifiable{ @Override - public String getId(); - public String getType(); - public String getParent(); - public String getCatalogItemId(); + String getId(); + String getType(); + String getParent(); + String getCatalogItemId(); + List getCatalogItemSuperIds(); } - public String getPlaneId(); + String getPlaneId(); - public Map getEntityIdToManifest(); + Map getEntityIdToManifest(); - public Map getLocationIdToType(); + Map getLocationIdToType(); - public Map getPolicyIdToType(); + Map getPolicyIdToType(); - public Map getEnricherIdToType(); + Map getEnricherIdToType(); - public Map getFeedIdToType(); + Map getFeedIdToType(); - public CatalogItemMemento getCatalogItemMemento(String id); + CatalogItemMemento getCatalogItemMemento(String id); - public Collection getCatalogItemIds(); + Collection getCatalogItemIds(); - public Map getCatalogItemMementos(); + Map getCatalogItemMementos(); - public boolean isEmpty(); + boolean isEmpty(); } diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java index 5911f2844d..d45df06e8d 100644 --- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java +++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java @@ -20,6 +20,7 @@ import java.io.Serializable; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Set; @@ -43,11 +44,19 @@ public interface Memento extends Serializable { String getId(); - public String getType(); - - public String getCatalogItemId(); - - public String getDisplayName(); + String getType(); + + /** + * The principal catalog item id. + */ + String getCatalogItemId(); + + /** + * Catalog Item Ids of all defining catalog items. + */ + List getCatalogItemSuperIds(); + + String getDisplayName(); /** * A (weakly-typed) property set for this memento. @@ -62,11 +71,11 @@ public interface Memento extends Serializable { * @deprecated since 0.7.0; use config/attributes so generic persistence will work, rather than requiring "custom fields" */ @Deprecated - public Map getCustomFields(); + Map getCustomFields(); - public String toVerboseString(); + String toVerboseString(); - public void injectTypeClass(Class clazz); + void injectTypeClass(Class clazz); /** * Returns the injected type class, or null if not injected. @@ -74,12 +83,12 @@ public interface Memento extends Serializable { * This is useful for ensuring the correct classloader is used (e.g. for {@link EntityMemento} * previously calling {@code EntityTypes.getDefinedSensors(getType())}. */ - public Class getTypeClass(); + Class getTypeClass(); - public Collection getTags(); + Collection getTags(); - public Map> getRelations(); + Map> getRelations(); /** Null for {@link Entity}, but important for adjuncts; see {@link EntityAdjunct#getUniqueTag()} */ - public String getUniqueTag(); + String getUniqueTag(); } diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java index 37c15e468b..b50e38a4ed 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java @@ -46,10 +46,12 @@ import org.apache.brooklyn.test.support.TestResourceUnavailableException; import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.core.osgi.Osgis; +import org.apache.brooklyn.util.core.xstream.XmlUtil; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.javalang.Reflections; import org.apache.brooklyn.util.osgi.OsgiTestResources; +import org.apache.brooklyn.util.text.Strings; import org.jclouds.compute.domain.OsFamily; import org.osgi.framework.Bundle; import org.osgi.framework.launch.Framework; @@ -65,6 +67,8 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import javax.xml.xpath.XPathConstants; + public class RebindOsgiTest extends AbstractYamlRebindTest { @SuppressWarnings("unused") @@ -164,7 +168,7 @@ public void testValInEntity(Object val, boolean useOsgi) throws Exception { } - @Test(groups = "Broken") + @Test public void testReboundDeepCatalogItemCanLoadResources() throws Exception { TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH); diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index 42e8766090..85244551f7 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -20,11 +20,10 @@ import java.util.Collection; import java.util.Iterator; -import java.util.ListIterator; +import java.util.List; import javax.annotation.Nullable; -import com.google.common.collect.Lists; import org.apache.brooklyn.api.catalog.BrooklynCatalog; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle; @@ -334,6 +333,33 @@ public static void setDisabled(ManagementContext mgmt, String symbolicName, Stri mgmt.getCatalog().persist(item); } + public static BrooklynClassLoadingContextSequential newClassLoadingContextForCatalogItems( + ManagementContext managementContext, List catalogItemIds) { + + BrooklynClassLoadingContextSequential seqLoader = + new BrooklynClassLoadingContextSequential(managementContext); + for (String catalogItemId : catalogItemIds) { + addCatalogItemContext(managementContext, seqLoader, catalogItemId); + } + // TODO what if not all items were found? need to consider what the right behaviour is. + // TODO for now take the course of using whatever items we *did* find + if (seqLoader.getPrimaries().size() != catalogItemIds.size()) { + log.warn("Couldn't find all catalog items used for instantiating entity " + managementContext); + } + return seqLoader; + } + + private static void addCatalogItemContext(ManagementContext managementContext, BrooklynClassLoadingContextSequential loader, String catalogItemId) { + RegisteredType item = managementContext.getTypeRegistry().get(catalogItemId); + + if (item != null) { + BrooklynClassLoadingContext itemLoader = newClassLoadingContext(managementContext, item); + loader.add(itemLoader); + } else { + // TODO review what to do here + log.debug("Can't find catalog item " + catalogItemId); + } + } public static String[] bundleIds(Bundle bundle) { return new String[] { diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java index a92a07b745..36ba8d1ed8 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static java.lang.String.format; +import static org.apache.brooklyn.core.catalog.internal.CatalogUtils.newClassLoadingContextForCatalogItems; import java.net.URI; import java.net.URL; @@ -50,7 +51,6 @@ import org.apache.brooklyn.api.mgmt.rebind.RebindManager; import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry; -import org.apache.brooklyn.api.typereg.RegisteredType; import org.apache.brooklyn.config.StringConfigMap; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; import org.apache.brooklyn.core.catalog.internal.CatalogInitialization; @@ -134,15 +134,7 @@ public BrooklynClassLoadingContext apply(@Nullable Object input) { final List catalogItemSuperIds = internal.getCatalogItemSuperIds(); if (catalogItemSuperIds.size() > 0) { BrooklynClassLoadingContextSequential seqLoader = - new BrooklynClassLoadingContextSequential(internal.getManagementContext()); - for (String catalogItemId : catalogItemSuperIds) { - addCatalogItemContext(internal, seqLoader, catalogItemId); - } - // TODO what if not all items were found? need to consider what the right behaviour is. - // TODO for now take the course of using whatever items we *did* find - if (seqLoader.getPrimaries().size() != catalogItemSuperIds.size()) { - log.error("Couldn't find all catalog items used for instantiating entity " + internal); - } + newClassLoadingContextForCatalogItems(internal.getManagementContext(), catalogItemSuperIds); JavaBrooklynClassLoadingContext entityLoader = JavaBrooklynClassLoadingContext.create(input.getClass().getClassLoader()); seqLoader.add(entityLoader); @@ -160,19 +152,6 @@ public BrooklynClassLoadingContext apply(@Nullable Object input) { }); } - private static void addCatalogItemContext(EntityInternal entity, BrooklynClassLoadingContextSequential loader, String catalogItemId) { - RegisteredType item = entity.getManagementContext().getTypeRegistry().get(catalogItemId); - - if (item != null) { - BrooklynClassLoadingContext itemLoader = CatalogUtils.newClassLoadingContext(entity.getManagementContext(), item); - loader.add(itemLoader); - } else { - log.error("Can't find catalog item " + catalogItemId + - " used for instantiating entity " + entity + - ". Falling back to application classpath."); - } - } - private final AtomicLong totalEffectorInvocationCount = new AtomicLong(); protected DeferredBrooklynProperties configMap; diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java index a89a52825e..019ac86497 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java @@ -35,7 +35,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.annotation.Nullable; +import javax.xml.xpath.XPathConstants; +import com.google.common.collect.ImmutableList; import org.apache.brooklyn.api.mgmt.rebind.PersistenceExceptionHandler; import org.apache.brooklyn.api.mgmt.rebind.RebindExceptionHandler; import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMemento; @@ -57,6 +59,7 @@ import org.apache.brooklyn.core.mgmt.rebind.PeriodicDeltaChangeListener; import org.apache.brooklyn.core.mgmt.rebind.dto.BrooklynMementoImpl; import org.apache.brooklyn.core.mgmt.rebind.dto.BrooklynMementoManifestImpl; +import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.collections.MutableSet; import org.apache.brooklyn.util.core.xstream.XmlUtil; @@ -77,6 +80,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; +import org.w3c.dom.NodeList; /** Implementation of the {@link BrooklynMementoPersister} backed by a pluggable * {@link PersistenceObjectStore} such as a file system or a jclouds object store */ @@ -324,8 +328,47 @@ public void visit(BrooklynObjectType type, String id, String contentsSubpath) th return result; } + private static class XPathHelper { + private String contents; + private String prefix; + + public XPathHelper(String contents, String prefix) { + this.contents = contents; + this.prefix = prefix; + } + + private String get(String innerPath) { + return (String) XmlUtil.xpathHandlingIllegalChars(contents, prefix+innerPath); + } + private List getStringList(String innerPath) { + List result = MutableList.of(); + final NodeList nodeList = + (NodeList) XmlUtil.xpathHandlingIllegalChars(contents, prefix + innerPath + "/string", XPathConstants.NODESET); + for(int c = 0 ; c < nodeList.getLength() ; c++) { + result.add(nodeList.item(c).getFirstChild().getNodeValue()); + } + return result; + } + } + + // We must be able to cope with XML serialized with either a single "catalogItemId" + // or a list "catalogItemSuperIds" of catalog item ids. Only one should be encountered + // but in any case prefer the list of ids. + private ImmutableList getCatalogItemIds(XPathHelper x) { + final MutableList list = MutableList.of(); + final List catalogItemSuperIds = x.getStringList("catalogItemSuperIds"); + final String catalogItemId = Strings.emptyToNull(x.get("catalogItemId")); + if (!catalogItemSuperIds.isEmpty()) { + list.addAll(catalogItemSuperIds); + } else if (catalogItemId != null) { + list.add(catalogItemId); + } + return ImmutableList.copyOf(list); + } + @Override - public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mementoData, final RebindExceptionHandler exceptionHandler) throws IOException { + public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mementoData, + final RebindExceptionHandler exceptionHandler) throws IOException { if (mementoData==null) mementoData = loadMementoRawData(exceptionHandler); @@ -336,19 +379,10 @@ public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mement Visitor visitor = new Visitor() { @Override public void visit(BrooklynObjectType type, String objectId, final String contents) throws Exception { - final String prefix = "/"+type.toCamelCase()+"/"; - - class XPathHelper { - private String get(String innerPath) { - return (String) XmlUtil.xpathHandlingIllegalChars(contents, prefix+innerPath); - } - } - XPathHelper x = new XPathHelper(); - + XPathHelper x = new XPathHelper(contents, "/"+type.toCamelCase()+"/"); switch (type) { case ENTITY: - builder.entity(x.get("id"), x.get("type"), - Strings.emptyToNull(x.get("parent")), Strings.emptyToNull(x.get("catalogItemId"))); + builder.entity(x.get("id"), x.get("type"), Strings.emptyToNull(x.get("parent")), getCatalogItemIds(x)); break; case LOCATION: case POLICY: diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index 0585f9b6c6..0054a1953c 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -30,6 +30,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import com.google.common.collect.ImmutableList; import org.apache.brooklyn.api.catalog.BrooklynCatalog; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.entity.Application; @@ -794,9 +795,9 @@ protected void noteErrors(final RebindExceptionHandler exceptionHandler, Excepti } } - protected String findCatalogItemId(ClassLoader cl, Map entityIdToManifest, EntityMementoManifest entityManifest) { - if (entityManifest.getCatalogItemId() != null) { - return entityManifest.getCatalogItemId(); + protected List findCatalogItemIds(ClassLoader cl, Map entityIdToManifest, EntityMementoManifest entityManifest) { + if (!entityManifest.getCatalogItemSuperIds().isEmpty()) { + return entityManifest.getCatalogItemSuperIds(); } if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND)) { @@ -806,12 +807,12 @@ protected String findCatalogItemId(ClassLoader cl, Map { protected final Class clazz; - protected final String catalogItemId; + protected final List catalogItemIds; - protected LoadedClass(Class clazz, String catalogItemId) { + protected LoadedClass(Class clazz, List catalogItemIds) { this.clazz = clazz; - this.catalogItemId = catalogItemId; + this.catalogItemIds = catalogItemIds; } } @@ -882,13 +883,12 @@ protected BrooklynObjectInstantiator(ClassLoader classLoader, RebindContextImpl protected Entity newEntity(EntityMementoManifest entityManifest) { String entityId = entityManifest.getId(); - String catalogItemId = findCatalogItemId(classLoader, mementoManifest.getEntityIdToManifest(), entityManifest); + List catalogItemIds = findCatalogItemIds(classLoader, mementoManifest.getEntityIdToManifest(), entityManifest); String entityType = entityManifest.getType(); - - LoadedClass loaded = load(Entity.class, entityType, catalogItemId, entityId); + + LoadedClass loaded = load(Entity.class, entityType, catalogItemIds, entityId); Class entityClazz = loaded.clazz; - String transformedCatalogItemId = loaded.catalogItemId; - + Entity entity; if (InternalFactory.isNewStyle(entityClazz)) { @@ -924,63 +924,46 @@ protected Entity newEntity(EntityMementoManifest entityManifest) { ((AbstractEntity)entity).setManagementContext(managementContext); managementContext.prePreManage(entity); } - - setCatalogItemId(entity, transformedCatalogItemId); + + setCatalogItemIds(entity, loaded.catalogItemIds); + return entity; } - protected void setCatalogItemId(BrooklynObject item, String catalogItemId) { - if (catalogItemId!=null) { - // TODO add support for nested catalog superids here. - ((BrooklynObjectInternal)item).setCatalogItemId(catalogItemId); - } + protected void setCatalogItemIds(BrooklynObject object, List superIds) { + ((BrooklynObjectInternal)object).setCatalogItemIds(superIds); } + protected LoadedClass load(Class bType, Memento memento) { - return load(bType, memento.getType(), memento.getCatalogItemId(), memento.getId()); + return load(bType, memento.getType(), memento.getCatalogItemSuperIds(), memento.getId()); } @SuppressWarnings("unchecked") - protected LoadedClass load(Class bType, String jType, String catalogItemId, String contextSuchAsId) { + protected LoadedClass load(Class bType, String jType, List catalogItemIds, String contextSuchAsId) { checkNotNull(jType, "Type of %s (%s) must not be null", contextSuchAsId, bType.getSimpleName()); - - if (catalogItemId != null) { - CatalogItem catalogItem = rebindContext.lookup().lookupCatalogItem(catalogItemId); - if (catalogItem == null) { - if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_AUTO_FIX_CATALOG_REF_ON_REBIND)) { - // See https://issues.apache.org/jira/browse/BROOKLYN-149 - // This is a dangling reference to the catalog item (which will have been logged by lookupCatalogItem). - // Try loading as any version. - if (CatalogUtils.looksLikeVersionedId(catalogItemId)) { - String symbolicName = CatalogUtils.getSymbolicNameFromVersionedId(catalogItemId); - catalogItem = rebindContext.lookup().lookupCatalogItem(symbolicName); - - if (catalogItem != null) { - LOG.warn("Unable to load catalog item "+catalogItemId+" for "+contextSuchAsId - +" ("+bType.getSimpleName()+"); will auto-upgrade to "+catalogItem.getCatalogItemId()); - catalogItemId = catalogItem.getCatalogItemId(); - } - } - } - } - if (catalogItem != null) { - BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(managementContext, catalogItem); - return new LoadedClass(loader.loadClass(jType, bType), catalogItemId); + + List idsFromReboundCatalog = MutableList.of(); + if (catalogItemIds != null && !catalogItemIds.isEmpty()) { + findCatalogIdsInReboundCatalog(bType, catalogItemIds, contextSuchAsId, idsFromReboundCatalog); + if (!idsFromReboundCatalog.isEmpty()) { + BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContextForCatalogItems(managementContext, idsFromReboundCatalog); + return new LoadedClass(loader.loadClass(jType, bType), catalogItemIds); } else { - LOG.warn("Unable to load catalog item "+catalogItemId+" for "+contextSuchAsId + LOG.warn("Unable to load catalog items "+ catalogItemIds +" for "+contextSuchAsId +" ("+bType.getSimpleName()+"); will try default class loader"); } } try { - return new LoadedClass((Class)loadClass(jType), catalogItemId); + return new LoadedClass((Class)loadClass(jType), idsFromReboundCatalog); } catch (Exception e) { Exceptions.propagateIfFatal(e); LOG.warn("Unable to load "+jType+" using reflections; will try standard context"); } - if (catalogItemId != null) { - throw new IllegalStateException("Unable to load catalog item "+catalogItemId+" for "+contextSuchAsId+", or load class from classpath"); + if (catalogItemIds != null && !catalogItemIds.isEmpty()) { + throw new IllegalStateException("Unable to load catalog item "+ catalogItemIds +" for "+contextSuchAsId+", or load class from classpath"); } else if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND)) { //Try loading from whichever catalog bundle succeeds. BrooklynCatalog catalog = managementContext.getCatalog(); @@ -988,7 +971,7 @@ protected LoadedClass load(Class bTyp BrooklynClassLoadingContext catalogLoader = CatalogUtils.newClassLoadingContext(managementContext, item); Maybe> catalogClass = catalogLoader.tryLoadClass(jType); if (catalogClass.isPresent()) { - return new LoadedClass((Class) catalogClass.get(), catalogItemId); + return new LoadedClass((Class) catalogClass.get(), catalogItemIds); } } throw new IllegalStateException("No catalogItemId specified for "+contextSuchAsId+" and can't load class (" + jType + ") from either classpath or catalog items"); @@ -997,6 +980,31 @@ protected LoadedClass load(Class bTyp } } + private void findCatalogIdsInReboundCatalog(Class bType, List catalogItemIds, String contextSuchAsId, List idsToUse) { + for (String catalogItemId : catalogItemIds) { + CatalogItem catalogItem = rebindContext.lookup().lookupCatalogItem(catalogItemId); + if (catalogItem == null) { + if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_AUTO_FIX_CATALOG_REF_ON_REBIND)) { + // See https://issues.apache.org/jira/browse/BROOKLYN-149 + // This is a dangling reference to the catalog item (which will have been logged by lookupCatalogItem). + // Try loading as any version. + if (CatalogUtils.looksLikeVersionedId(catalogItemId)) { + String symbolicName = CatalogUtils.getSymbolicNameFromVersionedId(catalogItemId); + catalogItem = rebindContext.lookup().lookupCatalogItem(symbolicName); + + if (catalogItem != null) { + LOG.warn("Unable to load catalog item "+ catalogItemIds +" for "+contextSuchAsId + +" ("+bType.getSimpleName()+"); will auto-upgrade to "+catalogItem.getCatalogItemId()); + idsToUse.add(catalogItem.getCatalogItemId()); + } + } + } + } else { + idsToUse.add(catalogItemId); + } + } + } + protected Class loadClass(String jType) throws ClassNotFoundException { try { return reflections.loadClass(jType); @@ -1051,9 +1059,8 @@ protected Location newLocation(String locationId, String locationType) { */ protected Policy newPolicy(PolicyMemento memento) { String id = memento.getId(); - LoadedClass loaded = load(Policy.class, memento.getType(), memento.getCatalogItemId(), id); + LoadedClass loaded = load(Policy.class, memento.getType(), memento.getCatalogItemSuperIds(), id); Class policyClazz = loaded.clazz; - String transformedCatalogItemId = loaded.catalogItemId; Policy policy; if (InternalFactory.isNewStyle(policyClazz)) { @@ -1077,7 +1084,7 @@ protected Policy newPolicy(PolicyMemento memento) { policy = invokeConstructor(null, policyClazz, new Object[] {flags}); } - setCatalogItemId(policy, transformedCatalogItemId); + setCatalogItemIds(policy, memento.getCatalogItemSuperIds()); return policy; } @@ -1088,7 +1095,6 @@ protected Enricher newEnricher(EnricherMemento memento) { String id = memento.getId(); LoadedClass loaded = load(Enricher.class, memento); Class enricherClazz = loaded.clazz; - String transformedCatalogItemId = loaded.catalogItemId; Enricher enricher; if (InternalFactory.isNewStyle(enricherClazz)) { @@ -1112,7 +1118,7 @@ protected Enricher newEnricher(EnricherMemento memento) { enricher = invokeConstructor(reflections, enricherClazz, new Object[] {flags}); } - setCatalogItemId(enricher, transformedCatalogItemId); + setCatalogItemIds(enricher, memento.getCatalogItemSuperIds()); return enricher; } @@ -1123,7 +1129,6 @@ protected Feed newFeed(FeedMemento memento) { String id = memento.getId(); LoadedClass loaded = load(Feed.class, memento); Class feedClazz = loaded.clazz; - String transformedCatalogItemId = loaded.catalogItemId; Feed feed; if (InternalFactory.isNewStyle(feedClazz)) { @@ -1136,7 +1141,7 @@ protected Feed newFeed(FeedMemento memento) { throw new IllegalStateException("rebind of feed without no-arg constructor unsupported: id="+id+"; type="+feedClazz); } - setCatalogItemId(feed, transformedCatalogItemId); + setCatalogItemIds(feed, memento.getCatalogItemSuperIds()); return feed; } 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 6fae7f5852..5feb0af57f 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 @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Set; +import com.google.common.collect.Iterables; import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento; import org.apache.brooklyn.core.BrooklynVersion; import org.apache.brooklyn.core.config.Sanitizer; @@ -45,7 +46,7 @@ protected static abstract class Builder> { protected String type; protected Class typeClass; protected String displayName; - protected String catalogItemId; + protected List catalogItemSuperIds; protected Map customFields = Maps.newLinkedHashMap(); protected List tags = Lists.newArrayList(); protected Map> relations = Maps.newLinkedHashMap(); @@ -64,7 +65,7 @@ public B from(Memento other) { type = other.getType(); typeClass = other.getTypeClass(); displayName = other.getDisplayName(); - catalogItemId = other.getCatalogItemId(); + catalogItemSuperIds = other.getCatalogItemSuperIds(); customFields.putAll(other.getCustomFields()); tags.addAll(other.getTags()); relations.putAll(other.getRelations()); @@ -85,7 +86,7 @@ public B customFields(Map vals) { private String type; private String id; private String displayName; - private String catalogItemId; + private List catalogItemSuperIds; private List tags; private Map> relations; @@ -105,7 +106,7 @@ protected AbstractMemento(Builder builder) { type = builder.type; typeClass = builder.typeClass; displayName = builder.displayName; - catalogItemId = builder.catalogItemId; + catalogItemSuperIds = builder.catalogItemSuperIds; setCustomFields(builder.customFields); tags = toPersistedList(builder.tags); relations = toPersistedMap(builder.relations); @@ -148,7 +149,12 @@ public String getDisplayName() { @Override public String getCatalogItemId() { - return catalogItemId; + return Iterables.getFirst(getCatalogItemSuperIds(), null); + } + + @Override + public List getCatalogItemSuperIds() { + return catalogItemSuperIds; } @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java index 664ddfe660..a4a7ecc963 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java @@ -21,6 +21,7 @@ import java.io.Serializable; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoManifest; @@ -55,8 +56,8 @@ public Builder planeId(String planeId) { public Builder brooklynVersion(String val) { brooklynVersion = val; return this; } - public Builder entity(String id, String type, String parent, String catalogItemId) { - entityIdToManifest.put(id, new EntityMementoManifestImpl(id, type, parent, catalogItemId)); + public Builder entity(String id, String type, String parent, List catalogItemIds) { + entityIdToManifest.put(id, new EntityMementoManifestImpl(id, type, parent, catalogItemIds)); return this; } public Builder location(String id, String type) { diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java index accf7419d3..0f20526020 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java @@ -18,19 +18,23 @@ */ package org.apache.brooklyn.core.mgmt.rebind.dto; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoManifest.EntityMementoManifest; +import java.util.List; + public class EntityMementoManifestImpl implements EntityMementoManifest { private String id; private String type; private String parentId; - private String catalogItemId; + private List catalogItemIds; - public EntityMementoManifestImpl(String id, String type, String parentId, String catalogItemId) { + public EntityMementoManifestImpl(String id, String type, String parentId, List catalogItemIds) { this.id = id; this.type = type; this.parentId = parentId; - this.catalogItemId = catalogItemId; + this.catalogItemIds = ImmutableList.copyOf(catalogItemIds); } @Override @@ -50,7 +54,12 @@ public String getParent() { @Override public String getCatalogItemId() { - return catalogItemId; + return Iterables.getFirst(catalogItemIds, null); + } + + @Override + public List getCatalogItemSuperIds() { + return catalogItemIds; } } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java index da54080b82..305467f6a3 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java @@ -182,7 +182,7 @@ public static BasicEntityMemento.Builder newEntityMementoBuilder(Entity entityRa builder.isTopLevelApp = (entity instanceof Application && entity.getParent() == null); builder.configKeys.addAll(entity.getEntityType().getConfigKeys()); - + Map, ?> localConfig = entity.config().getAllLocalRaw(); for (Map.Entry, ?> entry : localConfig.entrySet()) { ConfigKey key = checkNotNull(entry.getKey(), localConfig); @@ -448,11 +448,12 @@ private static void populateBrooklynObjectMementoBuilder(BrooklynObject instance } OsgiClassPrefixer prefixer = new OsgiClassPrefixer(); Optional typePrefix = prefixer.getPrefix(instance.getClass()); - + builder.id = instance.getId(); builder.displayName = instance.getDisplayName(); - builder.catalogItemId = instance.getCatalogItemId(); + builder.catalogItemSuperIds = instance.getCatalogItemSuperIds(); builder.type = (typePrefix.isPresent() ? typePrefix.get() : "") + instance.getClass().getName(); + builder.type = instance.getClass().getName(); builder.typeClass = instance.getClass(); if (instance instanceof EntityAdjunct) { builder.uniqueTag = ((EntityAdjunct)instance).getUniqueTag(); diff --git a/core/src/main/java/org/apache/brooklyn/util/core/xstream/XmlUtil.java b/core/src/main/java/org/apache/brooklyn/util/core/xstream/XmlUtil.java index 82b4867fda..8c4cc3d38e 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/xstream/XmlUtil.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/xstream/XmlUtil.java @@ -81,18 +81,22 @@ public static Object xpath(String xml, String xpath, QName returnType) { throw Exceptions.propagate(e); } } - - /** - * Executes the given xpath on the given xml. If this fails becaues the xml is invalid - * (e.g. contains ""), then it will attempt to escape such illegal characters - * and try again. Note that the *escaped* values may be contained in the returned result! - * The escaping used is the prefix "BR_UNICODE_"; if that string is already in the xml, - * then it will replace that with "NOT_BR_UNICODE_". - */ - @Beta + public static Object xpathHandlingIllegalChars(String xml, String xpath) { + return xpathHandlingIllegalChars(xml, xpath, XPathConstants.STRING); + } + + /** + * Executes the given xpath on the given xml. If this fails becaues the xml is invalid + * (e.g. contains ""), then it will attempt to escape such illegal characters + * and try again. Note that the *escaped* values may be contained in the returned result! + * The escaping used is the prefix "BR_UNICODE_"; if that string is already in the xml, + * then it will replace that with "NOT_BR_UNICODE_". + */ + @Beta + public static Object xpathHandlingIllegalChars(String xml, String xpath, QName returnType) { try { - return xpath(xml, xpath); + return xpath(xml, xpath, returnType); } catch (Exception e) { SAXException saxe = Exceptions.getFirstThrowableOfType(e, SAXException.class); if (saxe != null && saxe.toString().contains("&#")) { @@ -101,7 +105,7 @@ public static Object xpathHandlingIllegalChars(String xml, String xpath) { Escaper escaper = new Escaper(); String xmlCleaned = escaper.escape(xml); try { - Object result = xpath(xmlCleaned, xpath); + Object result = xpath(xmlCleaned, xpath, returnType); if (result instanceof String) { return escaper.unescape((String)result); } else { From d26e705c2611049d8f60b7128fd2540fe13b97f7 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Thu, 29 Sep 2016 15:21:17 +0100 Subject: [PATCH 11/35] Fix ActivePartialRebindVersionTest breakage from previous change. --- .../rebind/transformer/CompoundTransformer.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) 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 74b8bb05c3..59d7fe6690 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 @@ -179,21 +179,31 @@ public Builder renameField(String clazz, String oldVal, String newVal) { } /** Changes the contents of an XML tag 'catalogItemId' where the * old text matches oldSymbolicName and optionally oldVersion - * to have newSymbolicName and newVersion. + * to have newSymbolicName and newVersion. *

+ * Also changes contents of elements within a list of 'catalogItemSuperIds' e.g. + *

+         *     <catalogItemSuperIds>
+         *        <string>one</string>
+         *        <string>two</string>
+         *     </catalogItemSuperIds>
+         * 
+ *

+ * + *

* This provides a programmatic way to change the catalogItemID. */ public Builder changeCatalogItemId(String oldSymbolicName, String oldVersion, String newSymbolicName, String newVersion) { if (oldVersion==null) return changeCatalogItemId(oldSymbolicName, newSymbolicName, newVersion); // warnings use underscore notation because that's what CompoundTransformerLoader uses - return xmlReplaceItem("catalogItemId/text()[.='"+ + return xmlReplaceItem("*[self::catalogItemId|parent::catalogItemSuperIds]/text()[.='"+ Preconditions.checkNotNull(oldSymbolicName, "old_symbolic_name")+":"+Preconditions.checkNotNull(oldVersion, "old_version")+"']", Preconditions.checkNotNull(newSymbolicName, "new_symbolic_name")+":"+Preconditions.checkNotNull(newVersion, "new_version")); } /** As {@link #changeCatalogItemId(String, String, String, String)} matching any old version. */ public Builder changeCatalogItemId(String oldSymbolicName, String newSymbolicName, String newVersion) { - return xmlReplaceItem("catalogItemId/text()[starts-with(.,'"+Preconditions.checkNotNull(oldSymbolicName, "old_symbolic_name")+":')]", + return xmlReplaceItem("*[self::catalogItemId|parent::catalogItemSuperIds]/text()[starts-with(.,'"+Preconditions.checkNotNull(oldSymbolicName, "old_symbolic_name")+":')]", Preconditions.checkNotNull(newSymbolicName, "new_symbolic_name")+":"+Preconditions.checkNotNull(newVersion, "new_version")); } From 0bb7eb4a6b1a9603c25fe97aab91110bf556d1c6 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Thu, 29 Sep 2016 18:06:15 +0100 Subject: [PATCH 12/35] Fix testRebindWithCatalogAndApp with mode == DELETE_CATALOG. --- .../core/mgmt/rebind/RebindIteration.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index 0054a1953c..dc47c2d6ac 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -31,6 +31,7 @@ import java.util.concurrent.atomic.AtomicInteger; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import org.apache.brooklyn.api.catalog.BrooklynCatalog; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.entity.Application; @@ -843,8 +844,9 @@ protected List findCatalogItemIds(ClassLoader cl, Map LoadedClass load(Class bTyp List idsFromReboundCatalog = MutableList.of(); if (catalogItemIds != null && !catalogItemIds.isEmpty()) { findCatalogIdsInReboundCatalog(bType, catalogItemIds, contextSuchAsId, idsFromReboundCatalog); - if (!idsFromReboundCatalog.isEmpty()) { + if (idsFromReboundCatalog.size() == catalogItemIds.size()) { BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContextForCatalogItems(managementContext, idsFromReboundCatalog); return new LoadedClass(loader.loadClass(jType, bType), catalogItemIds); } else { - LOG.warn("Unable to load catalog items "+ catalogItemIds +" for "+contextSuchAsId + LOG.warn("Unable to load all catalog items "+ Iterables.toString(catalogItemIds) +" for "+contextSuchAsId +" ("+bType.getSimpleName()+"); will try default class loader"); } } try { - return new LoadedClass((Class)loadClass(jType), idsFromReboundCatalog); + return new LoadedClass((Class)loadClass(jType), catalogItemIds); } catch (Exception e) { Exceptions.propagateIfFatal(e); LOG.warn("Unable to load "+jType+" using reflections; will try standard context"); } if (catalogItemIds != null && !catalogItemIds.isEmpty()) { - throw new IllegalStateException("Unable to load catalog item "+ catalogItemIds +" for "+contextSuchAsId+", or load class from classpath"); + throw new IllegalStateException("Unable to load catalog items " + Iterables.toString(catalogItemIds) + + " for "+contextSuchAsId+", or load class from classpath"); } else if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND)) { //Try loading from whichever catalog bundle succeeds. BrooklynCatalog catalog = managementContext.getCatalog(); From b5ca71b9dbbb6897abf6ab74bbd570b39f22649b Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Thu, 29 Sep 2016 18:15:16 +0100 Subject: [PATCH 13/35] Fix testRebindWithCatalogAndApp with mode == REPLACE_CATALOG_WITH_NEWER_VERSION. --- .../org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index dc47c2d6ac..a37d7ce7f6 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -950,7 +950,7 @@ protected LoadedClass load(Class bTyp findCatalogIdsInReboundCatalog(bType, catalogItemIds, contextSuchAsId, idsFromReboundCatalog); if (idsFromReboundCatalog.size() == catalogItemIds.size()) { BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContextForCatalogItems(managementContext, idsFromReboundCatalog); - return new LoadedClass(loader.loadClass(jType, bType), catalogItemIds); + return new LoadedClass(loader.loadClass(jType, bType), idsFromReboundCatalog); } else { LOG.warn("Unable to load all catalog items "+ Iterables.toString(catalogItemIds) +" for "+contextSuchAsId +" ("+bType.getSimpleName()+"); will try default class loader"); From 63f4a9415901fece4b63fc0cd676b7812959ea9d Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 3 Oct 2016 10:13:30 +0100 Subject: [PATCH 14/35] Add (some) tests of rebind of previously persisted state. --- .../catalog/CatalogYamlRebindTest.java | 65 +++++++++++++++++-- .../core/mgmt/rebind/dto/AbstractMemento.java | 42 ++++++++++-- .../transformer/CompoundTransformer.java | 3 +- 3 files changed, 99 insertions(+), 11 deletions(-) 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 e6aff50cd7..ff0c794a83 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 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.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 @@ enum OsgiMode { LIBRARY, PREFIX } - + private Boolean defaultEnablementOfFeatureAutoFixatalogRefOnRebind; @BeforeMethod(alwaysRun=true) @@ -162,8 +166,61 @@ public Object[][] dataProvider() { } @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", "") + .build(); + return applyStateTransformer(transformer); + } + + private RebindOptions applyStateTransformer(final CompoundTransformer transformer) { + return RebindOptions.create() + .stateTransformer(new Function() { + @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 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 void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, OsgiMode // 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() { @Override public Void apply(BrooklynMementoPersister input) { PersistenceObjectStore objectStore = ((BrooklynMementoPersisterToObjectStore)input).getObjectStore(); @@ -313,7 +370,7 @@ public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, OsgiMode return null; }})); } else { - rebind(); + rebind(options); } // Ensure app is still there, and that it is usable - e.g. "stop" effector functions as expected 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 5feb0af57f..cf3a033390 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.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 @@ protected static abstract class Builder> { protected String type; protected Class typeClass; protected String displayName; - protected List catalogItemSuperIds; + // catalogItemId is retained to support rebind of previously persisted state (prior to catalogItemSuperIds) + protected String catalogItemId; + protected List catalogItemSuperIds = MutableList.of(); protected Map customFields = Maps.newLinkedHashMap(); protected List tags = Lists.newArrayList(); protected Map> relations = Maps.newLinkedHashMap(); @@ -65,14 +68,28 @@ public B from(Memento other) { 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 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 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 B customFields(Map vals) { private String type; private String id; private String displayName; - private List catalogItemSuperIds; + // catalogItemId is retained to support rebind of previously persisted state (prior to catalogItemSuperIds) + protected String catalogItemId; + private List catalogItemSuperIds = MutableList.of(); private List tags; private Map> relations; @@ -116,7 +135,18 @@ protected AbstractMemento(Builder builder) { // "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 fields); - + + // deals with value created by deserialization of state persisted with + 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 String getDisplayName() { @Override public String getCatalogItemId() { + normalizeCatalogItemIds(); return Iterables.getFirst(getCatalogItemSuperIds(), null); } @Override public List getCatalogItemSuperIds() { + normalizeCatalogItemIds(); return catalogItemSuperIds; } 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 59d7fe6690..c9bf70352d 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.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 Builder renameField(String clazz, String oldVal, String newVal) { * <string>two</string> * </catalogItemSuperIds> * - *

- * *

* This provides a programmatic way to change the catalogItemID. */ public Builder changeCatalogItemId(String oldSymbolicName, String oldVersion, From 759abe589bef812f726ffe6d81d7a0665f9ad388 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 3 Oct 2016 12:03:20 +0100 Subject: [PATCH 15/35] Some code tidy-up. --- .../catalog/CatalogYamlRebindTest.java | 242 +++++++----------- .../transformer/CompoundTransformer.java | 2 +- 2 files changed, 89 insertions(+), 155 deletions(-) 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 ff0c794a83..c92181bdbf 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 @@ -170,26 +170,34 @@ public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, boolean testRebindWithCatalogAndAppUsingOptions(mode, useOsgi, RebindOptions.create()); } + // Re-run the same tests as testRebindWithCatalogAndApp but with the XML updated to mimic state + // persisted before was replaced with . @Test(dataProvider = "dataProvider") public void testRebindWithCatalogAndAppRebindCatalogItemIds(RebindWithCatalogTestMode mode, boolean useOsgi) throws Exception { - testRebindWithCatalogAndAppUsingOptions(mode, useOsgi, rebindCatalogItemIds()); - } - - private RebindOptions rebindCatalogItemIds() { - CompoundTransformer transformer = CompoundTransformer.builder() + final RebindOptions rebindOptions = RebindOptions.create(); + applyCompoundStateTransformer(rebindOptions, CompoundTransformer.builder() .xmlReplaceItem("//catalogItemSuperIds", "") - .build(); - return applyStateTransformer(transformer); + .build()); + testRebindWithCatalogAndAppUsingOptions(mode, useOsgi, rebindOptions); } - private RebindOptions applyStateTransformer(final CompoundTransformer transformer) { - return RebindOptions.create() - .stateTransformer(new Function() { + private void applyCompoundStateTransformer(RebindOptions options, final CompoundTransformer transformer) { + options.stateTransformer(new Function() { @Override public Void apply(BrooklynMementoPersister input) { - BrooklynMementoRawData transformed = null; try { - transformed = transformer.transform((BrooklynMementoPersisterToObjectStore) input, RebindExceptionHandlerImpl.builder().build()); + BrooklynMementoRawData transformed = transformer.transform(input, RebindExceptionHandlerImpl.builder().build()); + PersistenceObjectStore objectStore = ((BrooklynMementoPersisterToObjectStore)input).getObjectStore(); + for (BrooklynObjectType type : BrooklynObjectType.values()) { + final List 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); + } + } } catch (Exception e) { Exceptions.propagateIfFatal(e); getLogger().warn(Strings.join(new Object[]{ @@ -197,18 +205,6 @@ private RebindOptions applyStateTransformer(final CompoundTransformer transforme }, ""), e); } - PersistenceObjectStore objectStore = ((BrooklynMementoPersisterToObjectStore)input).getObjectStore(); - for (BrooklynObjectType type : BrooklynObjectType.values()) { - final List 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; }}); } @@ -231,7 +227,7 @@ public void testRebindWithCatalogAndAppUsingOptions(RebindWithCatalogTestMode mo String appSymbolicName = "my.catalog.app.id.load"; String appVersion = "0.1.0"; - + String appCatalogFormat; if (osgiMode == OsgiMode.LIBRARY) { appCatalogFormat = Joiner.on("\n").join( @@ -277,45 +273,43 @@ public void testRebindWithCatalogAndAppUsingOptions(RebindWithCatalogTestMode mo " - type: " + OSGI_BUNDLE_SYMBOLID_NAME_FULL + ":" + OSGI_SIMPLE_EFFECTOR_TYPE); } else { appCatalogFormat = Joiner.on("\n").join( - "brooklyn.catalog:", - " id: " + appSymbolicName, - " version: %s", - " itemType: entity", - " item:", - " type: "+ BasicEntity.class.getName(), - " brooklyn.enrichers:", - " - type: "+TestEnricher.class.getName(), - " brooklyn.policies:", - " - type: "+TestPolicy.class.getName()); + "brooklyn.catalog:", + " id: " + appSymbolicName, + " version: %s", + " itemType: entity", + " item:", + " type: " + BasicEntity.class.getName(), + " brooklyn.enrichers:", + " - type: " + TestEnricher.class.getName(), + " brooklyn.policies:", + " - type: " + TestPolicy.class.getName()); } String locSymbolicName = "my.catalog.loc.id.load"; String locVersion = "1.0.0"; String locCatalogFormat = Joiner.on("\n").join( - "brooklyn.catalog:", - " id: " + locSymbolicName, - " version: %s", - " itemType: location", - " item:", - " type: localhost"); - + "brooklyn.catalog:", + " id: " + locSymbolicName, + " version: %s", + " itemType: location", + " item:", + " type: localhost"); + // Create the catalog items CatalogItem appItem = Iterables.getOnlyElement(addCatalogItems(String.format(appCatalogFormat, appVersion))); CatalogItem locItem = Iterables.getOnlyElement(addCatalogItems(String.format(locCatalogFormat, locVersion))); - final String appItemId = appItem.getId(); - final String locItemId = locItem.getId(); - + // Create an app, using that catalog item String yaml = "name: simple-app-yaml\n" + - "location: \"brooklyn.catalog:"+CatalogUtils.getVersionedId(locSymbolicName, locVersion)+"\"\n" + - "services: \n" + - "- type: "+CatalogUtils.getVersionedId(appSymbolicName, appVersion); + "location: \"brooklyn.catalog:" + CatalogUtils.getVersionedId(locSymbolicName, locVersion) + "\"\n" + + "services: \n" + + "- type: " + CatalogUtils.getVersionedId(appSymbolicName, appVersion); origApp = (StartableApplication) createAndStartApplication(yaml); Entity origEntity = Iterables.getOnlyElement(origApp.getChildren()); - Policy origPolicy = Iterables.getOnlyElement(origEntity.policies()); - Enricher origEnricher = Iterables.tryFind(origEntity.enrichers(), Predicates.instanceOf(TestEnricher.class)).get(); - assertEquals(origEntity.getCatalogItemId(), appSymbolicName+":"+appVersion); + Iterables.getOnlyElement(origEntity.policies()); + Iterables.tryFind(origEntity.enrichers(), Predicates.instanceOf(TestEnricher.class)).get(); + assertEquals(origEntity.getCatalogItemId(), appSymbolicName + ":" + appVersion); // Depending on test-mode, delete the catalog item, and then rebind switch (mode) { @@ -345,94 +339,80 @@ public void testRebindWithCatalogAndAppUsingOptions(RebindWithCatalogTestMode mo CatalogUtils.setDeprecated(mgmt(), locSymbolicName, locVersion, false); CatalogUtils.setDisabled(mgmt(), appSymbolicName, appVersion, false); CatalogUtils.setDisabled(mgmt(), locSymbolicName, locVersion, false); + // Edit the persisted state to remove the "deprecated" and "enablement" tags for our catalog items + applyCompoundStateTransformer(options, CompoundTransformer.builder() + .xmlReplaceItem("deprecated|disabled", "") + .build()); break; case NO_OP: break; // no-op default: - throw new IllegalStateException("Unknown mode: "+mode); + throw new IllegalStateException("Unknown mode: " + mode); } // 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(options) - .stateTransformer(new Function() { - @Override public Void apply(BrooklynMementoPersister input) { - PersistenceObjectStore objectStore = ((BrooklynMementoPersisterToObjectStore)input).getObjectStore(); - StoreObjectAccessor appItemAccessor = objectStore.newAccessor("catalog/"+Strings.makeValidFilename(appItemId)); - StoreObjectAccessor locItemAccessor = objectStore.newAccessor("catalog/"+Strings.makeValidFilename(locItemId)); - String appItemMemento = checkNotNull(appItemAccessor.get(), "appItem in catalog"); - String locItemMemento = checkNotNull(locItemAccessor.get(), "locItem in catalog"); - String newAppItemMemento = removeFromXml(appItemMemento, ImmutableList.of("catalogItem/deprecated", "catalogItem/disabled")); - String newLocItemMemento = removeFromXml(locItemMemento, ImmutableList.of("catalogItem/deprecated", "catalogItem/disabled")); - appItemAccessor.put(newAppItemMemento); - locItemAccessor.put(newLocItemMemento); - return null; - }})); - } else { - rebind(options); - } + rebind(options); // Ensure app is still there, and that it is usable - e.g. "stop" effector functions as expected Entity newEntity = Iterables.getOnlyElement(newApp.getChildren()); - Policy newPolicy = Iterables.getOnlyElement(newEntity.policies()); - Enricher newEnricher = Iterables.tryFind(newEntity.enrichers(), Predicates.instanceOf(TestEnricher.class)).get(); - assertEquals(newEntity.getCatalogItemId(), appSymbolicName+":"+appVersion); + Iterables.getOnlyElement(newEntity.policies()); + Iterables.tryFind(newEntity.enrichers(), Predicates.instanceOf(TestEnricher.class)).get(); + assertEquals(newEntity.getCatalogItemId(), appSymbolicName + ":" + appVersion); newApp.stop(); assertFalse(Entities.isManaged(newApp)); assertFalse(Entities.isManaged(newEntity)); - + // Ensure catalog item is as expecpted RegisteredType newAppItem = mgmt().getTypeRegistry().get(appSymbolicName, appVersion); RegisteredType newLocItem = mgmt().getTypeRegistry().get(locSymbolicName, locVersion); boolean itemDeployable; switch (mode) { - case DISABLE_CATALOG: - assertTrue(newAppItem.isDisabled()); - assertTrue(newLocItem.isDisabled()); - itemDeployable = false; - break; - case DELETE_CATALOG: - assertNull(newAppItem); - assertNull(newLocItem); - itemDeployable = false; - break; - case DEPRECATE_CATALOG: - assertTrue(newAppItem.isDeprecated()); - assertTrue(newLocItem.isDeprecated()); - itemDeployable = true; - break; - case NO_OP: - case STRIP_DEPRECATION_AND_ENABLEMENT_FROM_CATALOG_ITEM: - case REPLACE_CATALOG_WITH_NEWER_VERSION: - assertNotNull(newAppItem); - assertNotNull(newLocItem); - assertFalse(newAppItem.isDeprecated()); - assertFalse(newAppItem.isDisabled()); - assertFalse(newLocItem.isDeprecated()); - assertFalse(newLocItem.isDisabled()); - itemDeployable = true; - break; - default: - throw new IllegalStateException("Unknown mode: "+mode); + case DISABLE_CATALOG: + assertTrue(newAppItem.isDisabled()); + assertTrue(newLocItem.isDisabled()); + itemDeployable = false; + break; + case DELETE_CATALOG: + assertNull(newAppItem); + assertNull(newLocItem); + itemDeployable = false; + break; + case DEPRECATE_CATALOG: + assertTrue(newAppItem.isDeprecated()); + assertTrue(newLocItem.isDeprecated()); + itemDeployable = true; + break; + case NO_OP: + case STRIP_DEPRECATION_AND_ENABLEMENT_FROM_CATALOG_ITEM: + case REPLACE_CATALOG_WITH_NEWER_VERSION: + assertNotNull(newAppItem); + assertNotNull(newLocItem); + assertFalse(newAppItem.isDeprecated()); + assertFalse(newAppItem.isDisabled()); + assertFalse(newLocItem.isDeprecated()); + assertFalse(newLocItem.isDisabled()); + itemDeployable = true; + break; + default: + throw new IllegalStateException("Unknown mode: " + mode); } // Try to deploy a new app String yaml2 = "name: simple-app-yaml2\n" + - "location: \"brooklyn.catalog:"+CatalogUtils.getVersionedId(locSymbolicName, locVersion)+"\"\n" + - "services: \n" + - "- type: "+CatalogUtils.getVersionedId(appSymbolicName, appVersion); + "location: \"brooklyn.catalog:" + CatalogUtils.getVersionedId(locSymbolicName, locVersion) + "\"\n" + + "services: \n" + + "- type: " + CatalogUtils.getVersionedId(appSymbolicName, appVersion); if (itemDeployable) { StartableApplication app2 = (StartableApplication) createAndStartApplication(yaml2); Entity entity2 = Iterables.getOnlyElement(app2.getChildren()); - assertEquals(entity2.getCatalogItemId(), appSymbolicName+":"+appVersion); + assertEquals(entity2.getCatalogItemId(), appSymbolicName + ":" + appVersion); } else { try { StartableApplication app2 = (StartableApplication) createAndStartApplication(yaml2); - Asserts.shouldHaveFailedPreviously("app2="+app2); + Asserts.shouldHaveFailedPreviously("app2=" + app2); } catch (Exception e) { // only these two modes are allowed; may have different assertions (but don't yet) if (mode == RebindWithCatalogTestMode.DELETE_CATALOG) { @@ -444,50 +424,4 @@ public void testRebindWithCatalogAndAppUsingOptions(RebindWithCatalogTestMode mo } } } - - /** - * Given the "/"-separated path for the elements to be removed, it removes these from the xml - * and returns the transformed XML. - */ - private String removeFromXml(String xml, List elementsToRemove) { - try { - InputSource source = new InputSource(new StringReader(xml)); - Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(source); - - for (String elementToRemove : elementsToRemove) { - Node current = null; - boolean first = true; - for (String tag : elementToRemove.split("/")) { - NodeList matches; - if (first) { - matches = doc.getElementsByTagName(tag); - first = false; - } else { - matches = ((Element)current).getElementsByTagName(tag); - } - if (matches.getLength() > 0) { - current = matches.item(0); - } else { - current = null; - break; - } - } - if (current != null) { - current.getParentNode().removeChild(current); - } - } - - DOMSource domSource = new DOMSource(doc); - StringWriter writer = new StringWriter(); - StreamResult result = new StreamResult(writer); - Transformer transformer = TransformerFactory.newInstance().newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.transform(domSource, result); - - return writer.toString(); - - } catch (Exception e) { - throw Exceptions.propagate(e); - } - } } 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 c9bf70352d..9bc57f9b15 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 @@ -243,7 +243,7 @@ protected CompoundTransformer(Builder builder) { deletions = builder.deletions; } - public BrooklynMementoRawData transform(BrooklynMementoPersisterToObjectStore reader, RebindExceptionHandler exceptionHandler) throws Exception { + public BrooklynMementoRawData transform(BrooklynMementoPersister reader, RebindExceptionHandler exceptionHandler) throws Exception { BrooklynMementoRawData rawData = reader.loadMementoRawData(exceptionHandler); return transform(rawData); } From daaf03989346ad67cdae3ed7256c8dad53add57a Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 5 Oct 2016 11:02:20 +0100 Subject: [PATCH 16/35] Warning on primaries not needed. It's perfectly possible for the catalog item loader to have just the launcher management context in the secondaries. --- .../apache/brooklyn/core/catalog/internal/CatalogUtils.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index 85244551f7..ff393b37b0 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -341,11 +341,6 @@ public static BrooklynClassLoadingContextSequential newClassLoadingContextForCat for (String catalogItemId : catalogItemIds) { addCatalogItemContext(managementContext, seqLoader, catalogItemId); } - // TODO what if not all items were found? need to consider what the right behaviour is. - // TODO for now take the course of using whatever items we *did* find - if (seqLoader.getPrimaries().size() != catalogItemIds.size()) { - log.warn("Couldn't find all catalog items used for instantiating entity " + managementContext); - } return seqLoader; } From 3f986ec9c5340bd1f4dbef9cbdf5e26a27e1f3d7 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 5 Oct 2016 13:40:33 +0100 Subject: [PATCH 17/35] catalogItemIdIfNotNull is no longer used --- .../api/internal/AbstractBrooklynObjectSpec.java | 14 ++------------ .../core/typereg/AbstractTypePlanTransformer.java | 1 - 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java index d7442febd7..c6597822bf 100644 --- a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java +++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java @@ -131,18 +131,8 @@ public SpecT nestCatalogItemId(String val) { } return self(); } - // TODO in many places (callers to this method) we prefer a wrapper item ID; - // that is right, because the wrapper's defn will refer to the wrapped, - // but we might need also to collect the item ID's so that *all* can be searched, see #catalogItemId. - // e.g. if R3 references R2 which references R1 any one of these might supply config keys - // referencing resources or types in their local bundles. - @Beta - public SpecT catalogItemIdIfNotNull(String val) { - if (val!=null) { - catalogItemId(val); - } - return self(); - } + + public SpecT tag(Object tag) { diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java b/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java index dab0c3574b..1227b429e7 100644 --- a/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java +++ b/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java @@ -103,7 +103,6 @@ public Object create(final RegisteredType type, final RegisteredTypeLoadingConte @Override protected Object visitSpec() { try { AbstractBrooklynObjectSpec result = createSpec(type, context); - // see notes on catalogItemIdIfNotNull result.nestCatalogItemId(type.getId()); return result; } catch (Exception e) { throw Exceptions.propagate(e); } From 10afaad79fc0dec595a298cc67e7c18db232ff94 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 5 Oct 2016 22:25:37 +0100 Subject: [PATCH 18/35] Add start of a test framework test for the catalog behaviour. --- .../src/test/yaml/python-webserver.bom | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 camp/camp-brooklyn/src/test/yaml/python-webserver.bom diff --git a/camp/camp-brooklyn/src/test/yaml/python-webserver.bom b/camp/camp-brooklyn/src/test/yaml/python-webserver.bom new file mode 100644 index 0000000000..5fb5261e82 --- /dev/null +++ b/camp/camp-brooklyn/src/test/yaml/python-webserver.bom @@ -0,0 +1,98 @@ +# 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. + +# Tests nested catalog definition. 'python-webserver' is +# an example of an item that is meant to be extended. +# 'my-webserver' is such an extension. +# For test purposes 'my-webserver' makes reference to a +# resource defined in a library included in its parent. + +brooklyn.catalog: + items: + + - id: python-webserver + icon_url: classpath://org/apache/brooklyn/test/osgi/entities/icon.gif + brooklyn.libraries: + - url: https://github.com/apache/brooklyn-server/blob/master/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar?raw=true + item: + type: org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess + brooklyn.config: + install.command: | + # install python if not present + which python || \ + { sudo apt-get update && sudo apt-get install python ; } || \ + { sudo yum update && sudo yum install python ; } || \ + { echo WARNING: cannot install python && exit 1 ; } + + launch.command: | + # launch in background (ensuring no streams open), and record PID to file + nohup python -m SimpleHTTPServer ${PORT:-8020} < /dev/null > output.txt 2>&1 & + echo $! > ${PID_FILE:-pid.txt} + sleep 5 + ps -p `cat ${PID_FILE:-pid.txt}` + if [ $? -ne 0 ] ; then + cat output.txt + echo WARNING: python web server not running + exit 1 + fi + + shell.env: + HOSTNAME: $brooklyn:attributeWhenReady("host.name") + PORT: $brooklyn:config("my.app.port") + + brooklyn.enrichers: + # publish the URL as a sensor; the GUI will pick this up (main.uri) + - type: org.apache.brooklyn.enricher.stock.Transformer + brooklyn.config: + uniqueTag: url-generator + enricher.sourceSensor: host.subnet.hostname + # use the definition from Attributes class, as it has a RendererHint so GUI makes it a link + enricher.targetSensor: $brooklyn:sensor("org.apache.brooklyn.core.entity.Attributes", "main.uri") + enricher.targetValue: + $brooklyn:formatString: + - "http://%s:%s/" + - $brooklyn:attributeWhenReady("host.subnet.hostname") + - $brooklyn:config("my.app.port") + + - id: my-webserver + item: + type: python-webserver + customize.command: | + cp ${INSTALL_DIR}/icon.gif ${RUN_DIR} + # create the web page to serve + cat > index.html << EOF + + + Hello world. +

+ I am ${ENTITY_INFO}, ${MESSAGE:-a Brooklyn sample}. +

+ Created at: `date` +

+ I am running at ${HOSTNAME}, with on-box IP configuration: +

+        `ifconfig | grep inet`
+        
+ + EOF + shell.env: + ENTITY_INFO: $brooklyn:component("this", "") + MESSAGE: $brooklyn:config("my.message") + brooklyn.config: + files.preinstall: + classpath://org/apache/brooklyn/test/osgi/entities/icon.gif: icon.gif + my.app.port: 8020 + my.message: "good to meet you" \ No newline at end of file From 5c37de215b569246ce054d4a0d044548056d507f Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 13 Dec 2016 22:48:26 +0000 Subject: [PATCH 19/35] Fix mistake in merge with master --- .../camp/brooklyn/catalog/CatalogYamlRebindTest.java | 10 +++++----- .../core/mgmt/rebind/dto/MementosGenerators.java | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) 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 c92181bdbf..e39157166b 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 @@ -166,19 +166,19 @@ public Object[][] dataProvider() { } @Test(dataProvider = "dataProvider") - public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, boolean useOsgi) throws Exception { - testRebindWithCatalogAndAppUsingOptions(mode, useOsgi, RebindOptions.create()); + public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, OsgiMode osgiMode) throws Exception { + testRebindWithCatalogAndAppUsingOptions(mode, osgiMode, RebindOptions.create()); } // Re-run the same tests as testRebindWithCatalogAndApp but with the XML updated to mimic state // persisted before was replaced with . @Test(dataProvider = "dataProvider") - public void testRebindWithCatalogAndAppRebindCatalogItemIds(RebindWithCatalogTestMode mode, boolean useOsgi) throws Exception { + public void testRebindWithCatalogAndAppRebindCatalogItemIds(RebindWithCatalogTestMode mode, OsgiMode osgiMode) throws Exception { final RebindOptions rebindOptions = RebindOptions.create(); applyCompoundStateTransformer(rebindOptions, CompoundTransformer.builder() .xmlReplaceItem("//catalogItemSuperIds", "") .build()); - testRebindWithCatalogAndAppUsingOptions(mode, useOsgi, rebindOptions); + testRebindWithCatalogAndAppUsingOptions(mode, osgiMode, rebindOptions); } private void applyCompoundStateTransformer(RebindOptions options, final CompoundTransformer transformer) { @@ -216,7 +216,7 @@ private String idFromPath(BrooklynObjectType type, String path) { @SuppressWarnings({ "deprecation", "unused" }) - public void testRebindWithCatalogAndAppUsingOptions(RebindWithCatalogTestMode mode, boolean useOsgi, RebindOptions options) throws Exception { + public void testRebindWithCatalogAndAppUsingOptions(RebindWithCatalogTestMode mode, OsgiMode osgiMode, RebindOptions options) throws Exception { if (osgiMode != OsgiMode.NONE) { TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java index 305467f6a3..eac89e05fe 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java @@ -453,7 +453,6 @@ private static void populateBrooklynObjectMementoBuilder(BrooklynObject instance builder.displayName = instance.getDisplayName(); builder.catalogItemSuperIds = instance.getCatalogItemSuperIds(); builder.type = (typePrefix.isPresent() ? typePrefix.get() : "") + instance.getClass().getName(); - builder.type = instance.getClass().getName(); builder.typeClass = instance.getClass(); if (instance instanceof EntityAdjunct) { builder.uniqueTag = ((EntityAdjunct)instance).getUniqueTag(); From c60949739d4eaa00ef2647d6aba920b449a5c95b Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 20 Feb 2017 13:45:06 +0000 Subject: [PATCH 20/35] Fix tests after rebase with master --- .../catalog/CatalogOsgiYamlEntityTest.java | 112 ++++++++++++------ .../catalog/CatalogYamlEntityTest.java | 47 +------- .../rebind/RebindConfigInheritanceTest.java | 1 + 3 files changed, 78 insertions(+), 82 deletions(-) diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java index 53b27f1824..102f476727 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java @@ -57,6 +57,8 @@ public class CatalogOsgiYamlEntityTest extends AbstractYamlTest { // The non-osgi tests are much faster to run! private static final String SIMPLE_ENTITY_TYPE = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_ENTITY; + private static final String MORE_ENTITIES_POM_PROPERTIES_PATH = + "META-INF/maven/org.apache.brooklyn.test.resources.osgi/brooklyn-test-osgi-more-entities/pom.properties"; @Override protected boolean disableOsgi() { @@ -743,43 +745,81 @@ public void testIndirectCatalogItemCanLoadResources() throws Exception { deleteCatalogEntity(symbolicNameOuter); } - // The test is disabled as it fails. The entity will get assigned the outer-most catalog - // item which doesn't have the necessary libraries with visibility to the entity's classpath - // When loading resources from inside the entity then we will use the wrong BCLCS. A workaround - // has been implemented which explicitly adds the entity's class loader to the fallbacks. - @Test(groups="WIP") - public void testCatalogItemIdInReferencedItems() throws Exception { - TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); - - String symbolicNameInner = "my.catalog.app.id.inner"; - String symbolicNameOuter = "my.catalog.app.id.outer"; - addCatalogItems( - "brooklyn.catalog:", - " version: " + TEST_VERSION, - " items:", - " - id: " + symbolicNameInner, - " name: My Catalog App", - " description: My description", - " icon_url: classpath://path/to/myicon.jpg", - " libraries:", - " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, - " item: " + SIMPLE_ENTITY_TYPE, - " - id: " + symbolicNameOuter, - " item: " + symbolicNameInner); - - String yaml = "name: " + symbolicNameOuter + "\n" + - "services: \n" + - " - serviceType: "+ver(symbolicNameOuter); - Entity app = createAndStartApplication(yaml); - Entity entity = app.getChildren().iterator().next(); - - // Fails - assertEquals(entity.getCatalogItemId(), ver(symbolicNameInner)); - - deleteCatalogEntity(symbolicNameInner); - deleteCatalogEntity(symbolicNameOuter); - } + @Test + public void testDeepCatalogItemCanLoadResources() throws Exception { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH); + + String symbolicNameInner = "my.catalog.app.id.inner"; + String symbolicNameFiller = "my.catalog.app.id.filler"; + String symbolicNameOuter = "my.catalog.app.id.outer"; + addCatalogItems( + "brooklyn.catalog:", + " version: " + TEST_VERSION, + " items:", + " - id: " + symbolicNameInner, + " name: My Catalog App", + " brooklyn.libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, + " item: " + SIMPLE_ENTITY_TYPE, + " - id: " + symbolicNameFiller, + " name: Filler App", + " brooklyn.libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_URL, + " item: " + symbolicNameInner, + " - id: " + symbolicNameOuter, + " item: " + symbolicNameFiller); + + String yaml = "name: " + symbolicNameOuter + "\n" + + "services: \n" + + " - serviceType: "+ver(symbolicNameOuter); + Entity app = createAndStartApplication(yaml); + Entity entity = app.getChildren().iterator().next(); + + final String catalogBom = ResourceUtils.create(entity).getResourceAsString("classpath://" + MORE_ENTITIES_POM_PROPERTIES_PATH); + assertTrue(catalogBom.contains("artifactId=brooklyn-test-osgi-more-entities")); + + deleteCatalogEntity(symbolicNameOuter); + deleteCatalogEntity(symbolicNameFiller); + deleteCatalogEntity(symbolicNameInner); + } + + @Test + public void testCatalogItemIdInReferencedItems() throws Exception { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); + + String symbolicNameInner = "my.catalog.app.id.inner"; + String symbolicNameOuter = "my.catalog.app.id.outer"; + addCatalogItems( + "brooklyn.catalog:", + " version: " + TEST_VERSION, + " items:", + " - id: " + symbolicNameInner, + " name: My Catalog App", + " description: My description", + " icon_url: classpath://path/to/myicon.jpg", + " brooklyn.libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, + " item: " + SIMPLE_ENTITY_TYPE, + " - id: " + symbolicNameOuter, + " item: " + symbolicNameInner); + + String yaml = "name: " + symbolicNameOuter + "\n" + + "services: \n" + + " - serviceType: "+ver(symbolicNameOuter); + + Entity app = createAndStartApplication(yaml); + + Entity entity = app.getChildren().iterator().next(); + assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); + assertEquals(entity.getCatalogItemSuperIds().size(), 2); + assertEquals(entity.getCatalogItemSuperIds().get(0), ver(symbolicNameOuter)); + assertEquals(entity.getCatalogItemSuperIds().get(1), ver(symbolicNameInner)); + + deleteCatalogEntity(symbolicNameInner); + deleteCatalogEntity(symbolicNameOuter); + } private void registerAndLaunchAndAssertSimpleEntity(String symbolicName, String serviceType) throws Exception { addCatalogOSGiEntity(symbolicName, serviceType); diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java index cc26c22715..d491860074 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java @@ -18,9 +18,6 @@ */ package org.apache.brooklyn.camp.brooklyn.catalog; -import static org.apache.brooklyn.util.osgi.OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_MESSAGE_RESOURCE; -import static org.apache.commons.io.FileUtils.getFile; -import static org.apache.commons.io.FileUtils.readFileToString; import static com.google.common.base.Preconditions.checkNotNull; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -37,20 +34,15 @@ import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.entity.BrooklynConfigKeys; -import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest; import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.entity.TestEntityImpl; import org.apache.brooklyn.core.typereg.RegisteredTypes; -import org.apache.brooklyn.entity.software.base.SoftwareProcess; -import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess; +import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess; import org.apache.brooklyn.entity.stock.BasicApplication; import org.apache.brooklyn.entity.stock.BasicEntity; -import org.apache.brooklyn.test.support.TestResourceUnavailableException; import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.osgi.OsgiTestResources; -import org.apache.commons.io.FileUtils; import org.testng.Assert; import org.testng.annotations.Test; @@ -632,43 +624,6 @@ public void testItemWithBrooklynParameters() throws Exception { mgmt().getCatalog().deleteCatalogItem(id, version); } - @Test - public void testDeepCatalogItemCanLoadResources() throws Exception { - - String symbolicNameInner = "my.catalog.app.id.inner"; - String symbolicNameFiller = "my.catalog.app.id.filler"; - String symbolicNameOuter = "my.catalog.app.id.outer"; - addCatalogItems( - "brooklyn.catalog:", - " version: " + TEST_VERSION, - " items:", - " - id: " + symbolicNameInner, - " name: My Catalog App", - " brooklyn.libraries:", - " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, - " item: " + SIMPLE_ENTITY_TYPE, - " - id: " + symbolicNameFiller, - " name: Filler App", - " brooklyn.libraries:", - " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_URL, - " item: " + symbolicNameInner, - " - id: " + symbolicNameOuter, - " item: " + symbolicNameFiller); - - String yaml = "name: " + symbolicNameOuter + "\n" + - "services: \n" + - " - serviceType: "+ver(symbolicNameOuter); - Entity app = createAndStartApplication(yaml); - Entity entity = app.getChildren().iterator().next(); - - final String catalogBom = ResourceUtils.create(entity).getResourceAsString("classpath://" + MORE_ENTITIES_POM_PROPERTIES_PATH); - assertTrue(catalogBom.contains("artifactId=brooklyn-test-osgi-more-entities")); - - deleteCatalogEntity(symbolicNameOuter); - deleteCatalogEntity(symbolicNameFiller); - deleteCatalogEntity(symbolicNameInner); - } - @Test public void testCatalogItemIdInReferencedItems() throws Exception { String symbolicNameInner = "my.catalog.app.id.inner"; 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 index 06ad60f657..f48a53a5e0 100644 --- 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 @@ -117,6 +117,7 @@ public void testReadConfigInheritance_2016_11() throws Exception { checkNewAppNonInheritingKey1(rebindedApp); String origMementoTidied = origMemento.substring(origMemento.indexOf("")); + origMementoTidied = origMementoTidied.replaceFirst("", "\n "); origMementoTidied = Strings.replaceAllNonRegex(origMementoTidied, "VERSION", BrooklynVersion.get()); Asserts.assertEquals(origMementoTidied, newMemento); } From 78cfeda484002f7a483c81ccd7cd029210688afd Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Mon, 20 Feb 2017 16:58:08 +0000 Subject: [PATCH 21/35] Updates for the following review comments. Working on review comments for catalog-update PR https://github.com/apache/brooklyn-server/pull/338#discussion_r94612120 Unused import in AbstractBrooklynObjectSpec.java - done in merge https://github.com/apache/brooklyn-server/pull/338#discussion_r94752687 Keep for persistence backwards compatibility - surely I take this into account already? See testRebindWithCatalogAndAppRebindCatalogItemIds, and BrooklynMementoPersisterToObjectStore.getCatalogItemIds(). https://github.com/apache/brooklyn-server/pull/338#discussion_r94762969 Not called on xstream deserialize, could be null - take into account in following code. - Introduced getCatalogItemIdStack(). What about the other pre-existing fields that also have initializers? https://github.com/apache/brooklyn-server/pull/338#discussion_r94612579 public SpecT catalogItemId(String val) { Should we deprecate this one? When is this one used vs nestCatalogItemId? I'd think (before looking at the code in details) that this shouldn't be called at all, we should only be "nesting" catalog items. - deprecated https://github.com/apache/brooklyn-server/pull/338/files#r94615424 Don't see this used, do you think we should keep it? - replaced it with protected SpecT catalogItemIdStack(Collection catalogItemIdStack), used in AbstractBrooklynObjectSpec#copyFrom(). https://github.com/apache/brooklyn-server/pull/338/files#r94609346 missing word - fixed https://github.com/apache/brooklyn-server/pull/338/files#r94613348 It's not a mere reference but R3 extending R2, etc. - fixed https://github.com/apache/brooklyn-server/pull/338#discussion_r94618943 public SpecT catalogItemIdIfNotNull(String val) { I'd deprecate it, even if marked as @Beta. - done https://github.com/apache/brooklyn-server/pull/338/files#r94616318 I don't associate "nest" with anything in this context, perhaps stackCatalogItemId would be more appropriate? - changed to "stackCatalogItemId". https://github.com/apache/brooklyn-server/pull/338#discussion_r94616812 public final String getCatalogItemId() { Suggest deprecating this one and creating getOuterCatalogItemId, getInnerCatalogItemId. - created getOuterCatalogItemId; getInner not needed as there is getCatalogItemHierarchy https://github.com/apache/brooklyn-server/pull/338#discussion_r94753362 As a fallback return catalogItemId. - Seems preferable not to retain catalogItemId if we can get away without it, see comment on https://github.com/apache/brooklyn-server/pull/338#discussion_r94752687 above. https://github.com/apache/brooklyn-server/pull/338#discussion_r94617757 Can you add as a clarification - Added. https://github.com/apache/brooklyn-server/pull/338#discussion_r94618204 "Super" (here and same name in other classes) could be misinterpreted - changed name to getCatalogItemHierarchy --- .../internal/AbstractBrooklynObjectSpec.java | 222 +++++++++++------- .../brooklyn/spi/creation/CampResolver.java | 2 +- .../catalog/CatalogOsgiYamlEntityTest.java | 2 +- .../catalog/CatalogOsgiYamlTemplateTest.java | 2 +- .../catalog/CatalogYamlLocationTest.java | 4 +- .../catalog/CatalogYamlTemplateTest.java | 4 +- .../internal/CatalogItemDtoAbstract.java | 2 - .../core/mgmt/EntityManagementUtils.java | 2 +- .../mgmt/persist/XmlMementoSerializer.java | 2 +- .../objs/proxy/InternalEntityFactory.java | 8 +- .../objs/proxy/InternalLocationFactory.java | 4 +- .../objs/proxy/InternalPolicyFactory.java | 8 +- .../typereg/AbstractTypePlanTransformer.java | 2 +- .../rest/transform/LocationTransformer.java | 4 +- 14 files changed, 160 insertions(+), 108 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java index c6597822bf..16b4175097 100644 --- a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java +++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java @@ -23,11 +23,11 @@ import java.io.Serializable; import java.lang.reflect.Modifier; import java.util.ArrayDeque; +import java.util.Collection; import java.util.Collections; import java.util.Deque; import java.util.List; import java.util.Map; -import java.util.Queue; import java.util.Set; import org.apache.brooklyn.api.mgmt.EntityManager; @@ -54,21 +54,21 @@ *

* In addition to the contract defined by the code, * subclasses should provide a public static create(Class) - * method to create an instance of the spec for the target type indicated by the argument. + * method to create an instance of the spec for the target type indicated by the argument. *

* The spec is then passed to type-specific methods, * e.g. {@link EntityManager#createEntity(org.apache.brooklyn.api.entity.EntitySpec)} * to create a managed instance of the target type. */ -public abstract class AbstractBrooklynObjectSpec> implements Serializable { +public abstract class AbstractBrooklynObjectSpec> implements Serializable { private static final long serialVersionUID = 3010955277740333030L; private static final Logger log = LoggerFactory.getLogger(AbstractBrooklynObjectSpec.class); - + private final Class type; private String displayName; - private Deque catalogItemIdStack = new ArrayDeque<>(); + private Deque catalogItemIdStack; private Set tags = MutableSet.of(); private List> parameters = ImmutableList.of(); @@ -79,7 +79,7 @@ protected AbstractBrooklynObjectSpec(Class type) { checkValidType(type); this.type = type; } - + @SuppressWarnings("unchecked") protected SpecT self() { return (SpecT) this; @@ -88,68 +88,95 @@ protected SpecT self() { @Override public String toString() { return MoreObjects.toStringHelper(this).omitNullValues() - .add("type", type) - .add("displayName", displayName) - .toString(); + .add("type", type) + .add("displayName", displayName) + .toString(); } protected abstract void checkValidType(Class type); - + public SpecT displayName(String val) { displayName = val; return self(); } - - /** Set the catalog item ID that defined this object, also used for searching for type and resources referenced */ - // since https://issues.apache.org/jira/browse/BROOKLYN-445 this must no longer be used to indicate - // a caller-context catalog item that should be used for search purposes; - // if that behaviour is desired, the child should be refactored to be its own item in the catalog BOM - // (or TODO we add a separate field to record other catalog item IDs that could be applied for searching, see below) + + /** + * Set the catalog item ID that defined this object, also used for searching for type and resources referenced + * since https://issues.apache.org/jira/browse/BROOKLYN-445 this must no longer be used to indicate + * a caller-context catalog item that should be used for search purposes; + * if that behaviour is desired, the child should be refactored to be its own item in the catalog BOM + * (or TODO we add a separate field to record other catalog item IDs that could be applied for searching, see below) + */ public SpecT catalogItemId(String val) { - catalogItemIdStack.clear(); - return nestCatalogItemId(val); + getCatalogItemIdStack().clear(); + return stackCatalogItemId(val); } - public SpecT catalogItemIds(List ids) { - catalogItemIdStack.clear(); - catalogItemIdStack.addAll(ids); + protected SpecT catalogItemIdStack(Collection catalogItemIdStack) { + this.catalogItemIdStack = null; + getCatalogItemIdStack().addAll(catalogItemIdStack); return self(); } + /** + * @deprecated since 0.11.0, use {@link #stackCatalogItemId(String)} instead + */ + @Deprecated + @Beta + public SpecT catalogItemIdIfNotNull(String val) { + if (val!=null) { + stackCatalogItemId(val); + } + return self(); + } + + private Deque getCatalogItemIdStack() { + if (catalogItemIdStack == null) { + catalogItemIdStack = new ArrayDeque<>(); + } + return catalogItemIdStack; + } + /** * Adds (stacks) the catalog item id of a wrapping specification. * Does nothing if the value is null. - * - * Used when we to collect nested item ID's so that *all* can be searched. - * e.g. if R3 references R2 which references R1 any one of these might supply config keys + *

+ * Used when we want to collect nested item ID's so that *all* can be searched. + * e.g. if R3 extends R2 which extends R1 any one of these might supply config keys * referencing resources or types in their local bundles. */ @Beta - public SpecT nestCatalogItemId(String val) { - if (null != val && (catalogItemIdStack.isEmpty() || !catalogItemIdStack.element().equals(val))) { - catalogItemIdStack.addFirst(val); + public SpecT stackCatalogItemId(String val) { + if (null != val && (getCatalogItemIdStack().isEmpty() || !getCatalogItemIdStack().element().equals(val))) { + getCatalogItemIdStack().addFirst(val); } return self(); } - - public SpecT tag(Object tag) { tags.add(tag); return self(); } - /** adds the given tags */ + /** + * adds the given tags + */ public SpecT tags(Iterable tagsToAdd) { return tagsAdd(tagsToAdd); } - /** adds the given tags */ + + /** + * adds the given tags + */ public SpecT tagsAdd(Iterable tagsToAdd) { Iterables.addAll(this.tags, tagsToAdd); return self(); } - /** replaces tags with the given */ + + /** + * replaces tags with the given + */ public SpecT tagsReplace(Iterable tagsToReplace) { this.tags.clear(); Iterables.addAll(this.tags, tagsToReplace); @@ -166,13 +193,16 @@ public SpecT tagsReplace(Iterable tagsToReplace) { // it is a CatalogConfig or merely a config key, maybe introducing displayable, or even priority // (but note part of the reason for CatalogConfig.priority is that java reflection doesn't preserve field order) . // see also comments on the camp SpecParameterResolver. - + // probably the thing to do is deprecate the ambiguous method in favour of an explicit @Beta public SpecT parameters(Iterable> parameters) { return parametersReplace(parameters); } - /** adds the given parameters, new ones first so they dominate subsequent ones */ + + /** + * adds the given parameters, new ones first so they dominate subsequent ones + */ @Beta public SpecT parametersAdd(Iterable> parameters) { // parameters follows immutable pattern, unlike the other fields @@ -181,11 +211,14 @@ public SpecT parametersAdd(Iterable> parameters) { current.removeAll(params); return parametersReplace(ImmutableList.>builder() - .addAll(params) - .addAll(current) - .build()); + .addAll(params) + .addAll(current) + .build()); } - /** replaces parameters with the given */ + + /** + * replaces parameters with the given + */ @Beta public SpecT parametersReplace(Iterable> parameters) { this.parameters = ImmutableList.copyOf(checkNotNull(parameters, "parameters")); @@ -193,37 +226,47 @@ public SpecT parametersReplace(Iterable> parameters) } /** - * @return The type (often an interface) this spec represents and which will be instantiated from it + * @return The type (often an interface) this spec represents and which will be instantiated from it */ public Class getType() { return type; } - + /** * @return The display name of the object */ public final String getDisplayName() { return displayName; } - + + /** + * @deprecated since 0.11.0, use getOuterCatalogItemId or getInnerCatalogItemIds as appropriate + */ + @Deprecated public final String getCatalogItemId() { - if (catalogItemIdStack.size() != 0) { - return catalogItemIdStack.getFirst(); + return getOuterCatalogItemId(); + } + + public final String getOuterCatalogItemId() { + if (getCatalogItemIdStack().size() != 0) { + return getCatalogItemIdStack().getFirst(); } return null; } - /** - * An immutable list of ids of this object's catalog item and its defining catalog items. - * e.g. if the catalog item is defined as - *
-     *     items:
-     *     - id: X
-     *       item: Y
-     * 
- * then the list will contain X, Y. - */ - public final List getCatalogItemSuperIds() { + + /** + * An immutable list of ids of this object's catalog item and its defining catalog items. + * Wrapping items are first in the list (i.e. wrapping items precede wrapped items), + * for example, if the catalog item is defined as + *
+         *     items:
+         *     - id: X
+         *       item: Y
+         * 
+ * then the list will contain X, Y. + */ + public final List getCatalogItemIdHierarchy() { return ImmutableList.copyOf(catalogItemIdStack); } @@ -231,7 +274,9 @@ public final Set getTags() { return ImmutableSet.copyOf(tags); } - /** A list of configuration options that the entity supports. */ + /** + * A list of configuration options that the entity supports. + */ public final List> getParameters() { //Could be null after rebind if (parameters != null) { @@ -246,38 +291,43 @@ protected final void checkIsNewStyleImplementation(Class implClazz) { try { implClazz.getConstructor(new Class[0]); } catch (NoSuchMethodException e) { - throw new IllegalStateException("Implementation "+implClazz+" must have a no-argument constructor"); + throw new IllegalStateException("Implementation " + implClazz + " must have a no-argument constructor"); } catch (SecurityException e) { throw Exceptions.propagate(e); } - - if (implClazz.isInterface()) throw new IllegalStateException("Implementation "+implClazz+" is an interface, but must be a non-abstract class"); - if (Modifier.isAbstract(implClazz.getModifiers())) throw new IllegalStateException("Implementation "+implClazz+" is abstract, but must be a non-abstract class"); + + if (implClazz.isInterface()) + throw new IllegalStateException("Implementation " + implClazz + " is an interface, but must be a non-abstract class"); + if (Modifier.isAbstract(implClazz.getModifiers())) + throw new IllegalStateException("Implementation " + implClazz + " is abstract, but must be a non-abstract class"); } - + // TODO Duplicates method in BasicEntityTypeRegistry protected final void checkIsImplementation(Class val, Class requiredInterface) { - if (!requiredInterface.isAssignableFrom(val)) throw new IllegalStateException("Implementation "+val+" does not implement "+requiredInterface.getName()); - if (val.isInterface()) throw new IllegalStateException("Implementation "+val+" is an interface, but must be a non-abstract class"); - if (Modifier.isAbstract(val.getModifiers())) throw new IllegalStateException("Implementation "+val+" is abstract, but must be a non-abstract class"); + if (!requiredInterface.isAssignableFrom(val)) + throw new IllegalStateException("Implementation " + val + " does not implement " + requiredInterface.getName()); + if (val.isInterface()) + throw new IllegalStateException("Implementation " + val + " is an interface, but must be a non-abstract class"); + if (Modifier.isAbstract(val.getModifiers())) + throw new IllegalStateException("Implementation " + val + " is abstract, but must be a non-abstract class"); } - + protected SpecT copyFrom(SpecT otherSpec) { return displayName(otherSpec.getDisplayName()) .configure(otherSpec.getConfig()) .configure(otherSpec.getFlags()) .tags(otherSpec.getTags()) - .catalogItemId(otherSpec.getCatalogItemId()) + .catalogItemIdStack(otherSpec.getCatalogItemIdHierarchy()) .parameters(otherSpec.getParameters()); } @Override public boolean equals(Object obj) { - if (obj==null) return false; + if (obj == null) return false; if (!obj.getClass().equals(getClass())) return false; - AbstractBrooklynObjectSpec other = (AbstractBrooklynObjectSpec)obj; + AbstractBrooklynObjectSpec other = (AbstractBrooklynObjectSpec) obj; if (!Objects.equal(getDisplayName(), other.getDisplayName())) return false; - if (!Objects.equal(getCatalogItemId(), other.getCatalogItemId())) return false; + if (!Objects.equal(getCatalogItemIdHierarchy(), other.getCatalogItemIdHierarchy())) return false; if (!Objects.equal(getType(), other.getType())) return false; if (!Objects.equal(getTags(), other.getTags())) return false; if (!Objects.equal(getConfig(), other.getConfig())) return false; @@ -285,30 +335,32 @@ public boolean equals(Object obj) { if (!Objects.equal(getParameters(), other.getParameters())) return false; return true; } - + @Override public int hashCode() { - return Objects.hashCode(getCatalogItemId(), getDisplayName(), getType(), getTags()); + return Objects.hashCode(getCatalogItemIdHierarchy(), getDisplayName(), getType(), getTags()); } - /** strings inserted as flags, config keys inserted as config keys; - * if you want to force one or the other, create a ConfigBag and convert to the appropriate map type */ - public SpecT configure(Map val) { - if (val==null) { - log.warn("Null supplied when configuring "+this); - log.debug("Source for null supplied when configuring "+this, new Throwable("Source for null supplied when configuring "+this)); + /** + * strings inserted as flags, config keys inserted as config keys; + * if you want to force one or the other, create a ConfigBag and convert to the appropriate map type + */ + public SpecT configure(Map val) { + if (val == null) { + log.warn("Null supplied when configuring " + this); + log.debug("Source for null supplied when configuring " + this, new Throwable("Source for null supplied when configuring " + this)); return self(); } - for (Map.Entry entry: val.entrySet()) { - if (entry.getKey()==null) throw new NullPointerException("Null key not permitted"); + for (Map.Entry entry : val.entrySet()) { + if (entry.getKey() == null) throw new NullPointerException("Null key not permitted"); if (entry.getKey() instanceof CharSequence) flags.put(entry.getKey().toString(), entry.getValue()); else if (entry.getKey() instanceof ConfigKey) - config.put((ConfigKey)entry.getKey(), entry.getValue()); + config.put((ConfigKey) entry.getKey(), entry.getValue()); else if (entry.getKey() instanceof HasConfigKey) - config.put(((HasConfigKey)entry.getKey()).getConfigKey(), entry.getValue()); + config.put(((HasConfigKey) entry.getKey()).getConfigKey(), entry.getValue()); else { - log.warn("Spec "+this+" ignoring unknown config key "+entry.getKey()); + log.warn("Spec " + this + " ignoring unknown config key " + entry.getKey()); } } return self(); @@ -318,7 +370,7 @@ public SpecT configure(CharSequence key, Object val) { flags.put(checkNotNull(key, "key").toString(), val); return self(); } - + public SpecT configure(ConfigKey key, V val) { config.put(checkNotNull(key, "key"), val); return self(); @@ -353,11 +405,13 @@ public SpecT removeFlag(String key) { return self(); } - /** Clears the config map, removing any config previously set. */ + /** + * Clears the config map, removing any config previously set. + */ public void clearConfig() { config.clear(); } - + /** * @return Read-only construction flags * @see SetFromFlag declarations on the policy type diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java index 39f77e0c19..9ec8fd8efc 100644 --- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java +++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java @@ -115,7 +115,7 @@ public CampResolver(ManagementContext mgmt, RegisteredType type, RegisteredTypeL throw new IllegalStateException("Creating spec from "+item+", got "+spec.getType()+" which is incompatible with expected "+expectedType); } - spec.nestCatalogItemId(item.getId()); + spec.stackCatalogItemId(item.getId()); if (!spec.getFlags().containsKey("iconUrl") && item.getIconUrl()!=null) { spec.configure("iconUrl", item.getIconUrl()); } diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java index 102f476727..ffc81b5835 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java @@ -708,7 +708,7 @@ public void testCreateOsgiSpecFromRegistry() throws Exception { BrooklynTypeRegistry registry = mgmt().getTypeRegistry(); RegisteredType item = registry.get(symbolicName, TEST_VERSION); AbstractBrooklynObjectSpec spec = registry.createSpec(item, null, null); - assertEquals(spec.getCatalogItemId(), ver(symbolicName)); + assertEquals(spec.getOuterCatalogItemId(), ver(symbolicName)); deleteCatalogEntity(symbolicName); } diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlTemplateTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlTemplateTest.java index 8b2a561934..4ecfcf282b 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlTemplateTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlTemplateTest.java @@ -87,7 +87,7 @@ public void testMetadataOnSpecCreatedFromItem() throws Exception { EntitySpec child = Iterables.getOnlyElement( spec.getChildren() ); Assert.assertEquals(child.getType().getName(), SIMPLE_ENTITY_TYPE); - Assert.assertEquals(child.getCatalogItemId(), "t1:"+TEST_VERSION); + Assert.assertEquals(child.getOuterCatalogItemId(), "t1:"+TEST_VERSION); } private RegisteredType makeItem(String symbolicName, String templateType) { diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java index 01fb484d9d..dc017d386b 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java @@ -176,10 +176,10 @@ public void testTypeInheritance() throws Exception { LocationSpec spec1 = mgmt().getLocationRegistry().getLocationSpec(def1).get(); LocationSpec spec2 = mgmt().getLocationRegistry().getLocationSpec(def2).get(); - assertEquals(spec1.getCatalogItemId(), "loc1:0.1.2"); + assertEquals(spec1.getOuterCatalogItemId(), "loc1:0.1.2"); assertEquals(spec1.getDisplayName(), "My Loc 1"); assertContainsAll(spec1.getFlags(), ImmutableMap.of("mykey1", "myval1", "mykey1b", "myval1b")); - assertEquals(spec2.getCatalogItemId(), "loc2:0.1.2"); + assertEquals(spec2.getOuterCatalogItemId(), "loc2:0.1.2"); assertEquals(spec2.getDisplayName(), "My Loc 2"); assertContainsAll(spec2.getFlags(), ImmutableMap.of("mykey1", "myvalOverridden", "mykey1b", "myval1b", "mykey2", "myval2")); } diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java index cb585e0e18..f128abc04b 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java @@ -208,7 +208,7 @@ public void testMetadataOnSpecCreatedFromItem() throws Exception { EntitySpec child = Iterables.getOnlyElement( spec.getChildren() ); Assert.assertEquals(child.getType().getName(), TestEntity.class.getName()); - Assert.assertEquals(child.getCatalogItemId(), "t1:"+TEST_VERSION); + Assert.assertEquals(child.getOuterCatalogItemId(), "t1:"+TEST_VERSION); } @Test @@ -247,7 +247,7 @@ public void testMetadataOnSpecCreatedFromItemReferencingAnApp() throws Exception Assert.assertEquals(spec.getChildren().size(), 0); Assert.assertEquals(spec.getType(), BasicApplication.class); Assert.assertEquals(ConfigBag.newInstance(spec.getConfig()).getStringKey("foo"), "boo"); - Assert.assertEquals(spec.getCatalogItemId(), "app1r:1"); + Assert.assertEquals(spec.getOuterCatalogItemId(), "app1r:1"); } private RegisteredType addCatalogItem(String symbolicName, String templateType) { diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java index 82a210f596..dac5af823b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java @@ -46,8 +46,6 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Sets; -// TODO add support for nested catalog items, implement nestCatalogItemId in terms of symbolicName/Version -// TODO also getCatalogItemSuperIds. public abstract class CatalogItemDtoAbstract extends AbstractBrooklynObject implements CatalogItem { private static Logger LOG = LoggerFactory.getLogger(CatalogItemDtoAbstract.class); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java index 70ce4fb271..d222151ce6 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java @@ -259,7 +259,7 @@ private static void mergeWrapperParentSpecToChildEntity(EntitySpec spec = (AbstractBrooklynObjectSpec) source; - String catalogItemId = spec.getCatalogItemId(); + String catalogItemId = spec.getOuterCatalogItemId(); if (Strings.isNonBlank(catalogItemId)) { // write this field first, so we can peek at it when we read writer.startNode("catalogItemId"); diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java index 77dfcf4e91..cc1dd8cb3b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java @@ -246,8 +246,8 @@ protected T loadUnitializedEntity(final T entity, final Entit if (spec.getDisplayName()!=null) ((AbstractEntity)entity).setDisplayName(spec.getDisplayName()); - if (spec.getCatalogItemId()!=null) { - ((AbstractEntity)entity).setCatalogItemIds(spec.getCatalogItemSuperIds()); + if (spec.getOuterCatalogItemId()!=null) { + ((AbstractEntity)entity).setCatalogItemIds(spec.getCatalogItemIdHierarchy()); } entity.tags().addTags(spec.getTags()); @@ -274,13 +274,13 @@ protected T loadUnitializedEntity(final T entity, final Entit private void addSpecParameters(EntitySpec spec, EntityDynamicType edType) { // if coming from a catalog item, parsed by CAMP, then the spec list of parameters is canonical, // the parent item has had its config keys set as parameters here with those non-inheritable - // via type definition removed, so wipe those on the EDT to make sure non-inheritable ones are removed; + // via type definition removed, so wipe those on the EDT to make sure non-inheritable ones are removed; // OTOH if item is blank, it was set as a java type, not inheriting it, // and the config keys on the dynamic type are the correct ones to use, and usually there is nothing in spec.parameters, // except what is being added programmatically. // (this logic could get confused if catalog item ID referred to some runtime-inherited context, // but those semantics should no longer be used -- https://issues.apache.org/jira/browse/BROOKLYN-445) - if (Strings.isNonBlank(spec.getCatalogItemId())) { + if (Strings.isNonBlank(spec.getOuterCatalogItemId())) { edType.clearConfigKeys(); } for (SpecParameter param : spec.getParameters()) { diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java index 57098b3873..5a70257fdb 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java @@ -117,8 +117,8 @@ public T createLocation(LocationSpec spec) { if (spec.getDisplayName()!=null) ((AbstractLocation)loc).setDisplayName(spec.getDisplayName()); - if (spec.getCatalogItemId()!=null) { - ((AbstractLocation)loc).setCatalogItemIds(spec.getCatalogItemSuperIds()); + if (spec.getOuterCatalogItemId()!=null) { + ((AbstractLocation)loc).setCatalogItemIds(spec.getCatalogItemIdHierarchy()); } loc.tags().addTags(spec.getTags()); diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java index fd444a0196..11c27ac912 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java @@ -106,8 +106,8 @@ public T createPolicy(PolicySpec spec) { if (spec.getDisplayName()!=null) { ((AbstractPolicy)pol).setDisplayName(spec.getDisplayName()); } - if (spec.getCatalogItemId()!=null) { - ((AbstractPolicy)pol).setCatalogItemIds(spec.getCatalogItemSuperIds()); + if (spec.getOuterCatalogItemId()!=null) { + ((AbstractPolicy)pol).setCatalogItemIds(spec.getCatalogItemIdHierarchy()); } pol.tags().addTags(spec.getTags()); @@ -147,8 +147,8 @@ public T createEnricher(EnricherSpec spec) { if (spec.getDisplayName()!=null) ((AbstractEnricher)enricher).setDisplayName(spec.getDisplayName()); - if (spec.getCatalogItemId()!=null) { - ((AbstractEnricher)enricher).setCatalogItemIds(spec.getCatalogItemSuperIds()); + if (spec.getOuterCatalogItemId()!=null) { + ((AbstractEnricher)enricher).setCatalogItemIds(spec.getCatalogItemIdHierarchy()); } enricher.tags().addTags(spec.getTags()); diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java b/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java index 1227b429e7..46b41d6e6b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java +++ b/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java @@ -103,7 +103,7 @@ public Object create(final RegisteredType type, final RegisteredTypeLoadingConte @Override protected Object visitSpec() { try { AbstractBrooklynObjectSpec result = createSpec(type, context); - result.nestCatalogItemId(type.getId()); + result.stackCatalogItemId(type.getId()); return result; } catch (Exception e) { throw Exceptions.propagate(e); } } diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java index c612c6f409..2ad36080ec 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java @@ -83,7 +83,7 @@ private static LocationSummary newInstance(ManagementContext mgmt, } } - String id = Strings.isNonBlank(optionalExplicitId) ? optionalExplicitId : spec!=null && Strings.isNonBlank(spec.getCatalogItemId()) ? spec.getCatalogItemId() : null; + String id = Strings.isNonBlank(optionalExplicitId) ? optionalExplicitId : spec!=null && Strings.isNonBlank(spec.getOuterCatalogItemId()) ? spec.getOuterCatalogItemId() : null; URI selfUri = serviceUriBuilder(ub, LocationApi.class, "get").build(id); CatalogLocationSummary catalogSummary = null; @@ -100,7 +100,7 @@ private static LocationSummary newInstance(ManagementContext mgmt, return new LocationSummary( id, Strings.isNonBlank(name) ? name : spec!=null ? spec.getDisplayName() : null, - Strings.isNonBlank(specString) ? specString : spec!=null ? spec.getCatalogItemId() : null, + Strings.isNonBlank(specString) ? specString : spec!=null ? spec.getOuterCatalogItemId() : null, null, copyConfig(config, level), catalogSummary, From 1e5ca519224b5cac32abc2d7dcf76d33289c752f Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 21 Feb 2017 09:37:01 +0000 Subject: [PATCH 22/35] Updates for the following review comments. https://github.com/apache/brooklyn-server/pull/338#discussion_r94619869 This is just for persistence backwards compatibility, right? If so mark it as deprecated. - done https://github.com/apache/brooklyn-server/pull/338#discussion_r94620517 Unused. - done https://github.com/apache/brooklyn-server/pull/338#discussion_r94620662 Unused, plus Strings, XmlUtil. - done https://github.com/apache/brooklyn-server/pull/338#discussion_r94753587 At the very least could log at higher level - code at AbstractManagementContext used to log at error. - changed to warn. https://github.com/apache/brooklyn-server/pull/338#discussion_r94756363 Use and return getCatalogItemSuperIds instead. - updated --- .../mementos/BrooklynMementoManifest.java | 10 ++++-- .../api/mgmt/rebind/mementos/Memento.java | 4 ++- .../brooklyn/api/objs/BrooklynObject.java | 2 +- .../brooklyn/ConfigInheritanceYamlTest.java | 1 - .../camp/brooklyn/RebindOsgiTest.java | 4 --- .../catalog/CatalogOsgiYamlEntityTest.java | 6 ++-- .../catalog/CatalogYamlEntityTest.java | 8 ++--- .../core/catalog/internal/CatalogItemDo.java | 4 +-- .../internal/CatalogItemDtoAbstract.java | 2 +- .../core/catalog/internal/CatalogUtils.java | 4 +-- .../access/PortForwardManagerClient.java | 5 ++- .../internal/AbstractManagementContext.java | 3 +- .../core/mgmt/rebind/RebindIteration.java | 36 ++++++++++--------- .../core/mgmt/rebind/dto/AbstractMemento.java | 6 ++-- .../rebind/dto/EntityMementoManifestImpl.java | 2 +- .../mgmt/rebind/dto/MementosGenerators.java | 2 +- .../core/objs/AbstractBrooklynObject.java | 2 +- .../core/objs/AbstractEntityAdjunct.java | 2 +- .../util/core/ClassLoaderUtilsTest.java | 2 +- 19 files changed, 54 insertions(+), 51 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java index d3c3cc3d98..bcf246e2b2 100644 --- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java +++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java @@ -36,8 +36,14 @@ public interface EntityMementoManifest extends Identifiable{ String getId(); String getType(); String getParent(); - String getCatalogItemId(); - List getCatalogItemSuperIds(); + + /** + * deprecated since 0.11.0, use {@link #getCatalogItemHierarchy()} instead + * @return + */ + @Deprecated String getCatalogItemId(); + + List getCatalogItemHierarchy(); } String getPlaneId(); diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java index d45df06e8d..4ca219d783 100644 --- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java +++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java @@ -48,13 +48,15 @@ public interface Memento extends Serializable { /** * The principal catalog item id. + * @deprecated since 0.11.0 - use {@link #getCatalogItemHierarchy()} instead */ + @Deprecated String getCatalogItemId(); /** * Catalog Item Ids of all defining catalog items. */ - List getCatalogItemSuperIds(); + List getCatalogItemHierarchy(); String getDisplayName(); diff --git a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java index 61672881e2..ff49e1be43 100644 --- a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java +++ b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java @@ -69,7 +69,7 @@ public interface BrooklynObject extends Identifiable, Configurable { * * then the list will contain X, Y. */ - List getCatalogItemSuperIds(); + List getCatalogItemHierarchy(); /** * Tags are arbitrary objects which can be attached to an entity for subsequent reference. 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 458c5cabcb..89f282b262 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 @@ -42,7 +42,6 @@ import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.entity.TestEntityImpl; import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess; -import org.apache.brooklyn.entity.software.base.SoftwareProcess; import org.apache.brooklyn.entity.stock.BasicApplication; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool; diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java index b50e38a4ed..07cab6dd6e 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/RebindOsgiTest.java @@ -46,12 +46,10 @@ import org.apache.brooklyn.test.support.TestResourceUnavailableException; import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.core.osgi.Osgis; -import org.apache.brooklyn.util.core.xstream.XmlUtil; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.javalang.Reflections; import org.apache.brooklyn.util.osgi.OsgiTestResources; -import org.apache.brooklyn.util.text.Strings; import org.jclouds.compute.domain.OsFamily; import org.osgi.framework.Bundle; import org.osgi.framework.launch.Framework; @@ -67,8 +65,6 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import javax.xml.xpath.XPathConstants; - public class RebindOsgiTest extends AbstractYamlRebindTest { @SuppressWarnings("unused") diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java index ffc81b5835..dbf9445967 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java @@ -813,9 +813,9 @@ public void testCatalogItemIdInReferencedItems() throws Exception { Entity entity = app.getChildren().iterator().next(); assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); - assertEquals(entity.getCatalogItemSuperIds().size(), 2); - assertEquals(entity.getCatalogItemSuperIds().get(0), ver(symbolicNameOuter)); - assertEquals(entity.getCatalogItemSuperIds().get(1), ver(symbolicNameInner)); + assertEquals(entity.getCatalogItemHierarchy().size(), 2); + assertEquals(entity.getCatalogItemHierarchy().get(0), ver(symbolicNameOuter)); + assertEquals(entity.getCatalogItemHierarchy().get(1), ver(symbolicNameInner)); deleteCatalogEntity(symbolicNameInner); deleteCatalogEntity(symbolicNameOuter); diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java index d491860074..c40f7f8065 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java @@ -37,10 +37,8 @@ import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.entity.TestEntityImpl; import org.apache.brooklyn.core.typereg.RegisteredTypes; -import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess; import org.apache.brooklyn.entity.stock.BasicApplication; import org.apache.brooklyn.entity.stock.BasicEntity; -import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.osgi.OsgiTestResources; import org.testng.Assert; @@ -645,9 +643,9 @@ public void testCatalogItemIdInReferencedItems() throws Exception { Entity entity = app.getChildren().iterator().next(); assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); - assertEquals(entity.getCatalogItemSuperIds().size(), 2); - assertEquals(entity.getCatalogItemSuperIds().get(0), ver(symbolicNameOuter)); - assertEquals(entity.getCatalogItemSuperIds().get(1), ver(symbolicNameInner)); + assertEquals(entity.getCatalogItemHierarchy().size(), 2); + assertEquals(entity.getCatalogItemHierarchy().get(0), ver(symbolicNameOuter)); + assertEquals(entity.getCatalogItemHierarchy().get(1), ver(symbolicNameInner)); deleteCatalogEntity(symbolicNameInner); deleteCatalogEntity(symbolicNameOuter); diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java index 6699e3965b..7cf66354b8 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java @@ -137,8 +137,8 @@ public void setCatalogItemIds(List ids) { } @Override - public List getCatalogItemSuperIds() { - return itemDto.getCatalogItemSuperIds(); + public List getCatalogItemHierarchy() { + return itemDto.getCatalogItemHierarchy(); } @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java index dac5af823b..539b8b187c 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java @@ -104,7 +104,7 @@ public String getCatalogItemId() { } @Override - public List getCatalogItemSuperIds() { + public List getCatalogItemHierarchy() { return ImmutableList.of(getCatalogItemId()); } diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index ff393b37b0..c56a77c334 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -192,7 +192,7 @@ public static void setCatalogItemIdOnAddition(Entity entity, BrooklynObject item if (log.isDebugEnabled()) BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(entity), "Catalog item addition: "+entity+" from "+entity.getCatalogItemId()+" applying its catalog item ID to "+itemBeingAdded); - ((BrooklynObjectInternal)itemBeingAdded).setCatalogItemIds(entity.getCatalogItemSuperIds()); + ((BrooklynObjectInternal)itemBeingAdded).setCatalogItemIds(entity.getCatalogItemHierarchy()); } else { if (!itemBeingAdded.getCatalogItemId().equals(entity.getCatalogItemId())) { // not a problem, but something to watch out for @@ -352,7 +352,7 @@ private static void addCatalogItemContext(ManagementContext managementContext, B loader.add(itemLoader); } else { // TODO review what to do here - log.debug("Can't find catalog item " + catalogItemId); + log.warn("Can't find catalog item " + catalogItemId); } } diff --git a/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java b/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java index 1fb6ef53aa..d5781cd3ad 100644 --- a/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java +++ b/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java @@ -27,7 +27,6 @@ import org.apache.brooklyn.api.sensor.AttributeSensor; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.config.ConfigKey.HasConfigKey; -import org.apache.brooklyn.core.location.AbstractLocation; import org.apache.brooklyn.util.exceptions.Exceptions; import com.google.common.base.Preconditions; @@ -389,8 +388,8 @@ public String getCatalogItemId() { } @Override - public List getCatalogItemSuperIds() { - return getDelegate().getCatalogItemSuperIds(); + public List getCatalogItemHierarchy() { + return getDelegate().getCatalogItemHierarchy(); } @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java index 36ba8d1ed8..9c450480a8 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java @@ -54,7 +54,6 @@ import org.apache.brooklyn.config.StringConfigMap; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; import org.apache.brooklyn.core.catalog.internal.CatalogInitialization; -import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.entity.AbstractEntity; import org.apache.brooklyn.core.entity.EntityInternal; import org.apache.brooklyn.core.entity.drivers.BasicEntityDriverManager; @@ -131,7 +130,7 @@ private static DataGridFactory loadDataGridFactory(BrooklynProperties properties public BrooklynClassLoadingContext apply(@Nullable Object input) { if (input instanceof EntityInternal) { EntityInternal internal = (EntityInternal)input; - final List catalogItemSuperIds = internal.getCatalogItemSuperIds(); + final List catalogItemSuperIds = internal.getCatalogItemHierarchy(); if (catalogItemSuperIds.size() > 0) { BrooklynClassLoadingContextSequential seqLoader = newClassLoadingContextForCatalogItems(internal.getManagementContext(), catalogItemSuperIds); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index a37d7ce7f6..fa0a3afeb9 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -797,24 +797,28 @@ protected void noteErrors(final RebindExceptionHandler exceptionHandler, Excepti } protected List findCatalogItemIds(ClassLoader cl, Map entityIdToManifest, EntityMementoManifest entityManifest) { - if (!entityManifest.getCatalogItemSuperIds().isEmpty()) { - return entityManifest.getCatalogItemSuperIds(); + if (!entityManifest.getCatalogItemHierarchy().isEmpty()) { + return entityManifest.getCatalogItemHierarchy(); } if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND)) { //First check if any of the parent entities has a catalogItemId set. EntityMementoManifest ptr = entityManifest; while (ptr != null) { - if (ptr.getCatalogItemId() != null) { - RegisteredType type = managementContext.getTypeRegistry().get(ptr.getCatalogItemId()); - if (type != null) { - return ImmutableList.of(type.getId()); - } else { - //Couldn't find a catalog item with this id, but return it anyway and - //let the caller deal with the error. - //TODO under what circumstances is this permitted? - return ImmutableList.of(ptr.getCatalogItemId()); + if (ptr.getCatalogItemHierarchy() != null) { + List ids = MutableList.of(); + for (String id : ptr.getCatalogItemHierarchy()) { + RegisteredType type = managementContext.getTypeRegistry().get(id); + if (type != null) { + ids.add(type.getId()); + } else { + //Couldn't find a catalog item with this id, but return it anyway and + //let the caller deal with the error. + //TODO under what circumstances is this permitted? + ids.add(id); + } } + return ids; } if (ptr.getParent() != null) { ptr = entityIdToManifest.get(ptr.getParent()); @@ -938,7 +942,7 @@ protected void setCatalogItemIds(BrooklynObject object, List superIds) { protected LoadedClass load(Class bType, Memento memento) { - return load(bType, memento.getType(), memento.getCatalogItemSuperIds(), memento.getId()); + return load(bType, memento.getType(), memento.getCatalogItemHierarchy(), memento.getId()); } @SuppressWarnings("unchecked") @@ -1062,7 +1066,7 @@ protected Location newLocation(String locationId, String locationType) { */ protected Policy newPolicy(PolicyMemento memento) { String id = memento.getId(); - LoadedClass loaded = load(Policy.class, memento.getType(), memento.getCatalogItemSuperIds(), id); + LoadedClass loaded = load(Policy.class, memento.getType(), memento.getCatalogItemHierarchy(), id); Class policyClazz = loaded.clazz; Policy policy; @@ -1087,7 +1091,7 @@ protected Policy newPolicy(PolicyMemento memento) { policy = invokeConstructor(null, policyClazz, new Object[] {flags}); } - setCatalogItemIds(policy, memento.getCatalogItemSuperIds()); + setCatalogItemIds(policy, memento.getCatalogItemHierarchy()); return policy; } @@ -1121,7 +1125,7 @@ protected Enricher newEnricher(EnricherMemento memento) { enricher = invokeConstructor(reflections, enricherClazz, new Object[] {flags}); } - setCatalogItemIds(enricher, memento.getCatalogItemSuperIds()); + setCatalogItemIds(enricher, memento.getCatalogItemHierarchy()); return enricher; } @@ -1144,7 +1148,7 @@ protected Feed newFeed(FeedMemento memento) { throw new IllegalStateException("rebind of feed without no-arg constructor unsupported: id="+id+"; type="+feedClazz); } - setCatalogItemIds(feed, memento.getCatalogItemSuperIds()); + setCatalogItemIds(feed, memento.getCatalogItemHierarchy()); return feed; } 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 cf3a033390..381c71b774 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 @@ -68,7 +68,7 @@ public B from(Memento other) { type = other.getType(); typeClass = other.getTypeClass(); displayName = other.getDisplayName(); - setCatalogItemIds(other.getCatalogItemSuperIds(), other.getCatalogItemId()); + setCatalogItemIds(other.getCatalogItemHierarchy(), other.getCatalogItemId()); customFields.putAll(other.getCustomFields()); tags.addAll(other.getTags()); relations.putAll(other.getRelations()); @@ -180,11 +180,11 @@ public String getDisplayName() { @Override public String getCatalogItemId() { normalizeCatalogItemIds(); - return Iterables.getFirst(getCatalogItemSuperIds(), null); + return Iterables.getFirst(getCatalogItemHierarchy(), null); } @Override - public List getCatalogItemSuperIds() { + public List getCatalogItemHierarchy() { normalizeCatalogItemIds(); return catalogItemSuperIds; } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java index 0f20526020..5ed107669b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java @@ -58,7 +58,7 @@ public String getCatalogItemId() { } @Override - public List getCatalogItemSuperIds() { + public List getCatalogItemHierarchy() { return catalogItemIds; } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java index eac89e05fe..4a6ba9d645 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java @@ -451,7 +451,7 @@ private static void populateBrooklynObjectMementoBuilder(BrooklynObject instance builder.id = instance.getId(); builder.displayName = instance.getDisplayName(); - builder.catalogItemSuperIds = instance.getCatalogItemSuperIds(); + builder.catalogItemSuperIds = instance.getCatalogItemHierarchy(); builder.type = (typePrefix.isPresent() ? typePrefix.get() : "") + instance.getClass().getName(); builder.typeClass = instance.getClass(); if (instance instanceof EntityAdjunct) { diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java index fdfc624983..b067fe4272 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java @@ -219,7 +219,7 @@ public void nestCatalogItemId(String id) { } } - public List getCatalogItemSuperIds() { + public List getCatalogItemHierarchy() { return ImmutableList.copyOf(catalogItemIdStack); } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java index c9bdc35311..4b21963fc0 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java @@ -379,7 +379,7 @@ public void setEntity(EntityLocal entity) { this.entity = entity; this.execution = ((EntityInternal) entity).getExecutionContext(); if (entity!=null && getCatalogItemId() == null) { - setCatalogItemIds(entity.getCatalogItemSuperIds()); + setCatalogItemIds(entity.getCatalogItemHierarchy()); } } diff --git a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java index a6e75e29b3..21231aaa70 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java @@ -325,7 +325,7 @@ protected Entity createSimpleEntity(String bundleUrl, Class clazz) { .plan("{\"services\":[{\"type\": \"" + clazz.getName() + "\"}]}") .build(); mgmt.getCatalog().addItem(item); - ((EntityInternal)entity).setCatalogItemIds(item.getCatalogItemSuperIds()); + ((EntityInternal)entity).setCatalogItemIds(item.getCatalogItemHierarchy()); return entity; } From 68b94ced5af0a18be08277e9bdb5aff4696a4e80 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 21 Feb 2017 10:17:42 +0000 Subject: [PATCH 23/35] Fall through only if loader fails with the available catalog items. https://github.com/apache/brooklyn-server/pull/338#discussion_r94751531 --- .../brooklyn/core/mgmt/rebind/RebindIteration.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index fa0a3afeb9..3e75700bde 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -952,12 +952,16 @@ protected LoadedClass load(Class bTyp List idsFromReboundCatalog = MutableList.of(); if (catalogItemIds != null && !catalogItemIds.isEmpty()) { findCatalogIdsInReboundCatalog(bType, catalogItemIds, contextSuchAsId, idsFromReboundCatalog); - if (idsFromReboundCatalog.size() == catalogItemIds.size()) { + if (idsFromReboundCatalog.size() != catalogItemIds.size()) { + LOG.warn("Unable to load all catalog items "+ Iterables.toString(catalogItemIds) + +" for "+contextSuchAsId + " (" + bType.getSimpleName()+"); attempting load nevertheless"); + } + try { BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContextForCatalogItems(managementContext, idsFromReboundCatalog); return new LoadedClass(loader.loadClass(jType, bType), idsFromReboundCatalog); - } else { - LOG.warn("Unable to load all catalog items "+ Iterables.toString(catalogItemIds) +" for "+contextSuchAsId - +" ("+bType.getSimpleName()+"); will try default class loader"); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + LOG.warn("Unable to load "+jType+" using loader; will try reflections"); } } From d3a64d985b0ba792bf6bcd079a4f40f8a787ec85 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 21 Feb 2017 10:55:00 +0000 Subject: [PATCH 24/35] Address the following review comments. https://github.com/apache/brooklyn-server/pull/338#discussion_r94756103 Remove/deprecate this method and use getCatalogItemSuperIds instead in callers. - done; also renames "SuperIds" to "Hierarchy" everywhere. --- .../catalog/CatalogYamlRebindTest.java | 4 +- .../core/catalog/internal/CatalogItemDo.java | 4 +- .../core/catalog/internal/CatalogUtils.java | 2 +- .../internal/AbstractManagementContext.java | 6 +-- ...BrooklynMementoPersisterToObjectStore.java | 8 ++-- .../core/mgmt/rebind/RebindIteration.java | 4 +- .../core/mgmt/rebind/dto/AbstractMemento.java | 39 +++++++++++-------- .../rebind/dto/EntityMementoManifestImpl.java | 4 ++ .../mgmt/rebind/dto/MementosGenerators.java | 2 +- .../transformer/CompoundTransformer.java | 10 ++--- .../core/objs/AbstractBrooklynObject.java | 2 +- .../core/objs/AbstractEntityAdjunct.java | 2 +- .../core/objs/BrooklynObjectInternal.java | 2 +- .../objs/proxy/InternalEntityFactory.java | 2 +- .../objs/proxy/InternalLocationFactory.java | 2 +- .../objs/proxy/InternalPolicyFactory.java | 4 +- .../rebind/RebindConfigInheritanceTest.java | 2 +- .../util/core/ClassLoaderUtilsTest.java | 2 +- 18 files changed, 55 insertions(+), 46 deletions(-) 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 e39157166b..08616fc705 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 @@ -171,12 +171,12 @@ public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, OsgiMode } // Re-run the same tests as testRebindWithCatalogAndApp but with the XML updated to mimic state - // persisted before was replaced with . + // persisted before was replaced with . @Test(dataProvider = "dataProvider") public void testRebindWithCatalogAndAppRebindCatalogItemIds(RebindWithCatalogTestMode mode, OsgiMode osgiMode) throws Exception { final RebindOptions rebindOptions = RebindOptions.create(); applyCompoundStateTransformer(rebindOptions, CompoundTransformer.builder() - .xmlReplaceItem("//catalogItemSuperIds", "") + .xmlReplaceItem("//catalogItemHierarchy", "") .build()); testRebindWithCatalogAndAppUsingOptions(mode, osgiMode, rebindOptions); } diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java index 7cf66354b8..42cdb42b88 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java @@ -132,8 +132,8 @@ public void setCatalogItemId(String id) { } @Override - public void setCatalogItemIds(List ids) { - itemDto.setCatalogItemIds(ids); + public void setCatalogItemIdHierarchy(List ids) { + itemDto.setCatalogItemIdHierarchy(ids); } @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index c56a77c334..367d6eec06 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -192,7 +192,7 @@ public static void setCatalogItemIdOnAddition(Entity entity, BrooklynObject item if (log.isDebugEnabled()) BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(entity), "Catalog item addition: "+entity+" from "+entity.getCatalogItemId()+" applying its catalog item ID to "+itemBeingAdded); - ((BrooklynObjectInternal)itemBeingAdded).setCatalogItemIds(entity.getCatalogItemHierarchy()); + ((BrooklynObjectInternal)itemBeingAdded).setCatalogItemIdHierarchy(entity.getCatalogItemHierarchy()); } else { if (!itemBeingAdded.getCatalogItemId().equals(entity.getCatalogItemId())) { // not a problem, but something to watch out for diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java index 9c450480a8..177102867f 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java @@ -130,10 +130,10 @@ private static DataGridFactory loadDataGridFactory(BrooklynProperties properties public BrooklynClassLoadingContext apply(@Nullable Object input) { if (input instanceof EntityInternal) { EntityInternal internal = (EntityInternal)input; - final List catalogItemSuperIds = internal.getCatalogItemHierarchy(); - if (catalogItemSuperIds.size() > 0) { + final List catalogItemHierarchy = internal.getCatalogItemHierarchy(); + if (catalogItemHierarchy.size() > 0) { BrooklynClassLoadingContextSequential seqLoader = - newClassLoadingContextForCatalogItems(internal.getManagementContext(), catalogItemSuperIds); + newClassLoadingContextForCatalogItems(internal.getManagementContext(), catalogItemHierarchy); JavaBrooklynClassLoadingContext entityLoader = JavaBrooklynClassLoadingContext.create(input.getClass().getClassLoader()); seqLoader.add(entityLoader); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java index 019ac86497..1be1c2c688 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java @@ -352,14 +352,14 @@ private List getStringList(String innerPath) { } // We must be able to cope with XML serialized with either a single "catalogItemId" - // or a list "catalogItemSuperIds" of catalog item ids. Only one should be encountered + // or a list "catalogItemHierarchy" of catalog item ids. Only one should be encountered // but in any case prefer the list of ids. private ImmutableList getCatalogItemIds(XPathHelper x) { final MutableList list = MutableList.of(); - final List catalogItemSuperIds = x.getStringList("catalogItemSuperIds"); + final List catalogItemHierarchy = x.getStringList("catalogItemHierarchy"); final String catalogItemId = Strings.emptyToNull(x.get("catalogItemId")); - if (!catalogItemSuperIds.isEmpty()) { - list.addAll(catalogItemSuperIds); + if (!catalogItemHierarchy.isEmpty()) { + list.addAll(catalogItemHierarchy); } else if (catalogItemId != null) { list.add(catalogItemId); } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index 3e75700bde..1f23330dd5 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -936,8 +936,8 @@ protected Entity newEntity(EntityMementoManifest entityManifest) { return entity; } - protected void setCatalogItemIds(BrooklynObject object, List superIds) { - ((BrooklynObjectInternal)object).setCatalogItemIds(superIds); + protected void setCatalogItemIds(BrooklynObject object, List idHierarchy) { + ((BrooklynObjectInternal)object).setCatalogItemIdHierarchy(idHierarchy); } 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 381c71b774..5a68b6a435 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 @@ -47,9 +47,9 @@ protected static abstract class Builder> { protected String type; protected Class typeClass; protected String displayName; - // catalogItemId is retained to support rebind of previously persisted state (prior to catalogItemSuperIds) + // catalogItemId is retained to support rebind of previously persisted state (prior to catalogItemHierarchy) protected String catalogItemId; - protected List catalogItemSuperIds = MutableList.of(); + protected List catalogItemHierarchy = MutableList.of(); protected Map customFields = Maps.newLinkedHashMap(); protected List tags = Lists.newArrayList(); protected Map> relations = Maps.newLinkedHashMap(); @@ -68,7 +68,7 @@ public B from(Memento other) { type = other.getType(); typeClass = other.getTypeClass(); displayName = other.getDisplayName(); - setCatalogItemIds(other.getCatalogItemHierarchy(), other.getCatalogItemId()); + setCatalogItemIdHierarchy(other.getCatalogItemHierarchy(), other.getCatalogItemId()); customFields.putAll(other.getCustomFields()); tags.addAll(other.getTags()); relations.putAll(other.getRelations()); @@ -76,13 +76,13 @@ public B from(Memento other) { return self(); } - private void setCatalogItemIds(List otherItemSuperIds, String otherItemId) { - if (isEmpty(otherItemSuperIds) && otherItemId == null) { - catalogItemSuperIds = MutableList.of(); - } else if (isEmpty(otherItemSuperIds) && otherItemId != null) { - catalogItemSuperIds = MutableList.of(otherItemId); + private void setCatalogItemIdHierarchy(List otherItemIdHierarchy, String otherItemId) { + if (isEmpty(otherItemIdHierarchy) && otherItemId == null) { + catalogItemHierarchy = MutableList.of(); + } else if (isEmpty(otherItemIdHierarchy) && otherItemId != null) { + catalogItemHierarchy = MutableList.of(otherItemId); } else { - catalogItemSuperIds = MutableList.copyOf(otherItemSuperIds); + catalogItemHierarchy = MutableList.copyOf(otherItemIdHierarchy); } } @@ -103,9 +103,14 @@ public B customFields(Map vals) { private String type; private String id; private String displayName; - // catalogItemId is retained to support rebind of previously persisted state (prior to catalogItemSuperIds) + + @Deprecated + /** + @deprecated since 0.11.0; retained to support rebind of previously persisted state (prior to catalogItemHierarchy) + */ protected String catalogItemId; - private List catalogItemSuperIds = MutableList.of(); + + private List catalogItemHierarchy = MutableList.of(); private List tags; private Map> relations; @@ -125,7 +130,7 @@ protected AbstractMemento(Builder builder) { type = builder.type; typeClass = builder.typeClass; displayName = builder.displayName; - catalogItemSuperIds = builder.catalogItemSuperIds; + catalogItemHierarchy = builder.catalogItemHierarchy; setCustomFields(builder.customFields); tags = toPersistedList(builder.tags); relations = toPersistedMap(builder.relations); @@ -138,11 +143,11 @@ protected AbstractMemento(Builder builder) { // deals with value created by deserialization of state persisted with private void normalizeCatalogItemIds() { - if (catalogItemSuperIds == null) { - catalogItemSuperIds = MutableList.of(); + if (catalogItemHierarchy == null) { + catalogItemHierarchy = MutableList.of(); } - if (catalogItemSuperIds.isEmpty() && catalogItemId != null) { - catalogItemSuperIds = MutableList.of(catalogItemId); + if (catalogItemHierarchy.isEmpty() && catalogItemId != null) { + catalogItemHierarchy = MutableList.of(catalogItemId); catalogItemId = null; } } @@ -186,7 +191,7 @@ public String getCatalogItemId() { @Override public List getCatalogItemHierarchy() { normalizeCatalogItemIds(); - return catalogItemSuperIds; + return catalogItemHierarchy; } @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java index 5ed107669b..28c2a7e13f 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java @@ -52,6 +52,10 @@ public String getParent() { return parentId; } + /** + * @deprecated since 0.11.0, use {@link #getCatalogItemHierarchy()} instead + */ + @Deprecated @Override public String getCatalogItemId() { return Iterables.getFirst(catalogItemIds, null); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java index 4a6ba9d645..06f567c9ec 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java @@ -451,7 +451,7 @@ private static void populateBrooklynObjectMementoBuilder(BrooklynObject instance builder.id = instance.getId(); builder.displayName = instance.getDisplayName(); - builder.catalogItemSuperIds = instance.getCatalogItemHierarchy(); + builder.catalogItemHierarchy = instance.getCatalogItemHierarchy(); builder.type = (typePrefix.isPresent() ? typePrefix.get() : "") + instance.getClass().getName(); builder.typeClass = instance.getClass(); if (instance instanceof EntityAdjunct) { 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 9bc57f9b15..ece0cdfd32 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 @@ -182,12 +182,12 @@ public Builder renameField(String clazz, String oldVal, String newVal) { * old text matches oldSymbolicName and optionally oldVersion * to have newSymbolicName and newVersion. *

- * Also changes contents of elements within a list of 'catalogItemSuperIds' e.g. + * Also changes contents of elements within a list of 'catalogItemHierarchy' e.g. *

-         *     <catalogItemSuperIds>
+         *     <catalogItemHierarchy>
          *        <string>one</string>
          *        <string>two</string>
-         *     </catalogItemSuperIds>
+         *     </catalogItemHierarchy>
          * 
*

* This provides a programmatic way to change the catalogItemID. */ @@ -196,13 +196,13 @@ public Builder changeCatalogItemId(String oldSymbolicName, String oldVersion, if (oldVersion==null) return changeCatalogItemId(oldSymbolicName, newSymbolicName, newVersion); // warnings use underscore notation because that's what CompoundTransformerLoader uses - return xmlReplaceItem("*[self::catalogItemId|parent::catalogItemSuperIds]/text()[.='"+ + return xmlReplaceItem("*[self::catalogItemId|parent::catalogItemHierarchy]/text()[.='"+ Preconditions.checkNotNull(oldSymbolicName, "old_symbolic_name")+":"+Preconditions.checkNotNull(oldVersion, "old_version")+"']", Preconditions.checkNotNull(newSymbolicName, "new_symbolic_name")+":"+Preconditions.checkNotNull(newVersion, "new_version")); } /** As {@link #changeCatalogItemId(String, String, String, String)} matching any old version. */ public Builder changeCatalogItemId(String oldSymbolicName, String newSymbolicName, String newVersion) { - return xmlReplaceItem("*[self::catalogItemId|parent::catalogItemSuperIds]/text()[starts-with(.,'"+Preconditions.checkNotNull(oldSymbolicName, "old_symbolic_name")+":')]", + return xmlReplaceItem("*[self::catalogItemId|parent::catalogItemHierarchy]/text()[starts-with(.,'"+Preconditions.checkNotNull(oldSymbolicName, "old_symbolic_name")+":')]", Preconditions.checkNotNull(newSymbolicName, "new_symbolic_name")+":"+Preconditions.checkNotNull(newVersion, "new_version")); } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java index b067fe4272..9ba131c5cb 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java @@ -207,7 +207,7 @@ public void setCatalogItemId(String id) { } @Override - public void setCatalogItemIds(List ids) { + public void setCatalogItemIdHierarchy(List ids) { catalogItemIdStack.clear(); catalogItemIdStack.addAll(ids); } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java index 4b21963fc0..260c210219 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java @@ -379,7 +379,7 @@ public void setEntity(EntityLocal entity) { this.entity = entity; this.execution = ((EntityInternal) entity).getExecutionContext(); if (entity!=null && getCatalogItemId() == null) { - setCatalogItemIds(entity.getCatalogItemHierarchy()); + setCatalogItemIdHierarchy(entity.getCatalogItemHierarchy()); } } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java index 4dcbf1aee3..4c05ed6116 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java @@ -38,7 +38,7 @@ public interface BrooklynObjectInternal extends BrooklynObject, Rebindable { void setCatalogItemId(String id); - void setCatalogItemIds(List id); + void setCatalogItemIdHierarchy(List id); void nestCatalogItemId(String id); diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java index cc1dd8cb3b..a80d12a9fe 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java @@ -247,7 +247,7 @@ protected T loadUnitializedEntity(final T entity, final Entit ((AbstractEntity)entity).setDisplayName(spec.getDisplayName()); if (spec.getOuterCatalogItemId()!=null) { - ((AbstractEntity)entity).setCatalogItemIds(spec.getCatalogItemIdHierarchy()); + ((AbstractEntity)entity).setCatalogItemIdHierarchy(spec.getCatalogItemIdHierarchy()); } entity.tags().addTags(spec.getTags()); diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java index 5a70257fdb..de6a0bd678 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java @@ -118,7 +118,7 @@ public T createLocation(LocationSpec spec) { ((AbstractLocation)loc).setDisplayName(spec.getDisplayName()); if (spec.getOuterCatalogItemId()!=null) { - ((AbstractLocation)loc).setCatalogItemIds(spec.getCatalogItemIdHierarchy()); + ((AbstractLocation)loc).setCatalogItemIdHierarchy(spec.getCatalogItemIdHierarchy()); } loc.tags().addTags(spec.getTags()); diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java index 11c27ac912..776cfef2d8 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java @@ -107,7 +107,7 @@ public T createPolicy(PolicySpec spec) { ((AbstractPolicy)pol).setDisplayName(spec.getDisplayName()); } if (spec.getOuterCatalogItemId()!=null) { - ((AbstractPolicy)pol).setCatalogItemIds(spec.getCatalogItemIdHierarchy()); + ((AbstractPolicy)pol).setCatalogItemIdHierarchy(spec.getCatalogItemIdHierarchy()); } pol.tags().addTags(spec.getTags()); @@ -148,7 +148,7 @@ public T createEnricher(EnricherSpec spec) { ((AbstractEnricher)enricher).setDisplayName(spec.getDisplayName()); if (spec.getOuterCatalogItemId()!=null) { - ((AbstractEnricher)enricher).setCatalogItemIds(spec.getCatalogItemIdHierarchy()); + ((AbstractEnricher)enricher).setCatalogItemIdHierarchy(spec.getCatalogItemIdHierarchy()); } enricher.tags().addTags(spec.getTags()); 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 index f48a53a5e0..b340d2ae7e 100644 --- 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 @@ -117,7 +117,7 @@ public void testReadConfigInheritance_2016_11() throws Exception { checkNewAppNonInheritingKey1(rebindedApp); String origMementoTidied = origMemento.substring(origMemento.indexOf("")); - origMementoTidied = origMementoTidied.replaceFirst("", "\n "); + origMementoTidied = origMementoTidied.replaceFirst("", "\n "); origMementoTidied = Strings.replaceAllNonRegex(origMementoTidied, "VERSION", BrooklynVersion.get()); Asserts.assertEquals(origMementoTidied, newMemento); } diff --git a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java index 21231aaa70..a9686d5f72 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java @@ -325,7 +325,7 @@ protected Entity createSimpleEntity(String bundleUrl, Class clazz) { .plan("{\"services\":[{\"type\": \"" + clazz.getName() + "\"}]}") .build(); mgmt.getCatalog().addItem(item); - ((EntityInternal)entity).setCatalogItemIds(item.getCatalogItemHierarchy()); + ((EntityInternal)entity).setCatalogItemIdHierarchy(item.getCatalogItemHierarchy()); return entity; } From 9369a42fb9cf016cd5c118014c23e09e6085271b Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 21 Feb 2017 12:08:13 +0000 Subject: [PATCH 25/35] Review comment. Remove confusing default value. https://github.com/apache/brooklyn-server/pull/338#discussion_r94762563 --- .../apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 5a68b6a435..876ab24e5e 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 @@ -49,7 +49,7 @@ protected static abstract class Builder> { protected String displayName; // catalogItemId is retained to support rebind of previously persisted state (prior to catalogItemHierarchy) protected String catalogItemId; - protected List catalogItemHierarchy = MutableList.of(); + protected List catalogItemHierarchy; protected Map customFields = Maps.newLinkedHashMap(); protected List tags = Lists.newArrayList(); protected Map> relations = Maps.newLinkedHashMap(); @@ -110,7 +110,7 @@ public B customFields(Map vals) { */ protected String catalogItemId; - private List catalogItemHierarchy = MutableList.of(); + private List catalogItemHierarchy; private List tags; private Map> relations; From 584efcc4e5845c372d8519f3d073c938b9516ebe Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 22 Feb 2017 16:43:30 +0000 Subject: [PATCH 26/35] Delete original change from 0ab9b37b55fce9eaf3eef319ea2fc77e41e7ba8e https://github.com/apache/brooklyn-server/pull/338#discussion_r94621436 The change was done during the early investigation of the issue. The nested-item tests work without it. --- .../brooklyn/core/catalog/internal/CatalogUtils.java | 8 -------- .../core/resolve/entity/JavaEntitySpecResolver.java | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index 367d6eec06..15aafd77b5 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -19,7 +19,6 @@ package org.apache.brooklyn.core.catalog.internal; import java.util.Collection; -import java.util.Iterator; import java.util.List; import javax.annotation.Nullable; @@ -173,13 +172,6 @@ public static void installLibraries(ManagementContext managementContext, @Nullab public static String getCatalogItemIdFromLoader(BrooklynClassLoadingContext loader) { if (loader instanceof OsgiBrooklynClassLoadingContext) { return ((OsgiBrooklynClassLoadingContext)loader).getCatalogItemId(); - } else if (loader instanceof BrooklynClassLoadingContextSequential) { - final Iterator iterator = ((BrooklynClassLoadingContextSequential) loader).getPrimaries().iterator(); - if (iterator.hasNext()) { - BrooklynClassLoadingContext osgiLoader = iterator.next(); - return getCatalogItemIdFromLoader(osgiLoader); - } - else return null; } else { return null; } diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/entity/JavaEntitySpecResolver.java b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/JavaEntitySpecResolver.java index 243f6b4c53..6657727c62 100644 --- a/core/src/main/java/org/apache/brooklyn/core/resolve/entity/JavaEntitySpecResolver.java +++ b/core/src/main/java/org/apache/brooklyn/core/resolve/entity/JavaEntitySpecResolver.java @@ -87,7 +87,7 @@ private EntitySpec resolveInternal(String localType, BrooklynClassLoadingCont .additionalInterfaces(additionalInterfaceClazzes); spec = rawSpec; } - spec.catalogItemId(CatalogUtils.getCatalogItemIdFromLoader(loader)); + spec.stackCatalogItemId(CatalogUtils.getCatalogItemIdFromLoader(loader)); return spec; } From 3257c846dd21d1b1dada9c480ef7f6e68f3bd03c Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 8 Mar 2017 12:17:57 +0000 Subject: [PATCH 27/35] Use newClassLoadingContextForCatalogItems where possible. https://github.com/apache/brooklyn-server/pull/338/files#r94623208 Use in org.apache.brooklyn.util.core.ClassLoaderUtils#load org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore#getCustomClassLoaderForBrooklynObject org.apache.brooklyn.core.catalog.internal.JavaCatalogToSpecTransformer#createCatalogSpec Not doing XmlMementoSerializer as it is calling newClassLoadingContext(ManagementContext mgmt, RegisteredType item) rather than newClassLoadingContext(ManagementContext mgmt, CatalogItem item), and the hierarchy is not available on RegisteredType. --- .../JavaCatalogToSpecTransformer.java | 2 +- ...BrooklynMementoPersisterToObjectStore.java | 10 ++++-- .../brooklyn/util/core/ClassLoaderUtils.java | 36 ++++++++++++------- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java index 4e15d243cb..a990c2f878 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java @@ -81,7 +81,7 @@ public > SpecT c // java types were deprecated before we added osgi support so this isn't necessary, // but it doesn't hurt (and if we re-instate a class+bundle approach for RegisteredType // we will want to do this) - type = CatalogUtils.newClassLoadingContext(mgmt, item).loadClass(javaType); + type = CatalogUtils.newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemHierarchy()).loadClass(javaType); } catch (Exception e) { Exceptions.propagateIfFatal(e); throw new IllegalStateException("Unable to load old-style java catalog item type " + javaType + " for item " + item, e); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java index 1be1c2c688..d9cafdc7c4 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java @@ -173,7 +173,8 @@ protected MementoSerializer getSerializerWithCustomClassLoader(LookupCon return result; } - @Nullable protected ClassLoader getCustomClassLoaderForBrooklynObject(LookupContext lookupContext, BrooklynObjectType type, String objectId) { + @Nullable protected ClassLoader getCustomClassLoaderForBrooklynObject(LookupContext lookupContext, + BrooklynObjectType type, String objectId) { BrooklynObject item = lookupContext.peek(type, objectId); String catalogItemId = (item == null) ? null : item.getCatalogItemId(); // TODO enrichers etc aren't yet known -- would need to backtrack to the entity to get them from bundles @@ -185,10 +186,13 @@ protected MementoSerializer getSerializerWithCustomClassLoader(LookupCon RegisteredType catalogItem = lookupContext.lookupManagementContext().getTypeRegistry().get(catalogItemId); if (catalogItem == null) { // TODO do we need to only log once, rather than risk log.warn too often? I think this only happens on rebind, so ok. - LOG.warn("Unable to load catalog item "+catalogItemId+" for custom class loader of "+type+" "+objectId+"; will use default class loader"); + LOG.warn("Unable to load catalog item "+catalogItemId + +" for custom class loader of " + type + " " + objectId + "; will use default class loader"); return null; } else { - return ClassLoaderFromBrooklynClassLoadingContext.of(CatalogUtils.newClassLoadingContext(lookupContext.lookupManagementContext(), catalogItem)); + return ClassLoaderFromBrooklynClassLoadingContext.of( + CatalogUtils.newClassLoadingContextForCatalogItems(lookupContext.lookupManagementContext(), + item.getCatalogItemHierarchy())); } } diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java index afb45baa73..d26296956d 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java @@ -63,7 +63,8 @@ public class ClassLoaderUtils { */ static final String WHITE_LIST_KEY = "org.apache.brooklyn.classloader.fallback.bundles"; static final String CLASS_NAME_DELIMITER = ":"; - private static final String WHITE_LIST_DEFAULT = "org\\.apache\\.brooklyn\\..*:" + OsgiUtils.toOsgiVersion(BrooklynVersion.get()); + private static final String WHITE_LIST_DEFAULT = + "org\\.apache\\.brooklyn\\..*:" + OsgiUtils.toOsgiVersion(BrooklynVersion.get()); // Class.forName gets the class loader from the calling class. // We don't have access to the same reflection API so need to pass it explicitly. @@ -122,7 +123,8 @@ protected ClassLoader getValidClassLoader(ClassLoader cl) { *
    *
  • {@code }, such as {@code com.google.common.net.HostAndPort} *
  • {@code :}, such as {@code com.google.guava:com.google.common.net.HostAndPort} - *
  • {@code ::}, such as {@code com.google.guava:16.0.1:com.google.common.net.HostAndPort} + *
  • {@code ::}, such as + * {@code com.google.guava:16.0.1:com.google.common.net.HostAndPort} *
* * The classloading order is as follows: @@ -153,7 +155,8 @@ public Class loadClass(String name) throws ClassNotFoundException { if (cls.isPresent()) { return cls.get(); } else { - throw new ClassNotFoundException("Class " + name + " not found on the application class path, nor in the bundle white list.", getReturnException(cls)); + throw new ClassNotFoundException("Class " + name + + " not found on the application class path, nor in the bundle white list.", getReturnException(cls)); } } @@ -161,7 +164,8 @@ public Class loadClass(String symbolicName, @Nullable String version, String try { return tryLoadFromBundle(ClassLoaderDispatcher.INSTANCE, symbolicName, version, className).get(); } catch (IllegalStateException e) { - throw new ClassNotFoundException("Class " + className + " could not be loaded from bundle " + toBundleString(symbolicName, version), e); + throw new ClassNotFoundException("Class " + className + " could not be loaded from bundle " + + toBundleString(symbolicName, version), e); } } @@ -176,7 +180,8 @@ public URL getResource(String name) { } /** - * Finds all the resources with the given name. Aborts going through subsequent fallbacks when it finds at least one resource. + * Finds all the resources with the given name. + * Aborts going through subsequent fallbacks when it finds at least one resource. * @see {@link #loadClass(String)} for loading order * * @return empty {@link Iterable} when no resources find @@ -198,7 +203,8 @@ protected Maybe load(String name, LoaderDispatcher dispatcher) { if (looksLikeBundledClassName(name)) { String[] arr = name.split(CLASS_NAME_DELIMITER); if (arr.length > 3) { - throw new IllegalStateException("'" + name + "' doesn't look like a class name and contains too many colons to be parsed as bundle:version:class triple."); + throw new IllegalStateException("'" + name + + "' doesn't look like a class name and contains too many colons to be parsed as bundle:version:class triple."); } else if (arr.length == 3) { symbolicName = arr[0]; version = arr[1]; @@ -208,7 +214,8 @@ protected Maybe load(String name, LoaderDispatcher dispatcher) { version = null; className = arr[1]; } else { - throw new IllegalStateException("'" + name + "' contains a bundle:version:class delimiter, but only one of those specified"); + throw new IllegalStateException("'" + name + + "' contains a bundle:version:class delimiter, but only one of those specified"); } } else { symbolicName = null; @@ -247,13 +254,15 @@ private Maybe loadClass(String name, LoaderDispatcher dispatcher, Stri if (catalogItemId != null) { CatalogItem item = CatalogUtils.getCatalogItemOptionalVersion(mgmt, catalogItemId); if (item != null) { - BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item); + BrooklynClassLoadingContext loader = + CatalogUtils.newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemHierarchy()); cls = dispatcher.tryLoadFrom(loader, className); if (cls.isPresent()) { return cls; } } else { - log.warn("Entity " + entity + " refers to non-existent catalog item " + catalogItemId + ". Trying to load class " + name); + log.warn("Entity " + entity + " refers to non-existent catalog item " + catalogItemId + + ". Trying to load class " + name); } } } @@ -278,7 +287,8 @@ private Maybe loadClass(String name, LoaderDispatcher dispatcher, Stri return Maybe.absentNull(); } - protected Maybe tryLoadFromBundle(LoaderDispatcher dispatcher, String symbolicName, String version, String name) { + protected Maybe tryLoadFromBundle(LoaderDispatcher dispatcher, String symbolicName, String version, + String name) { Framework framework = getFramework(); if (framework != null) { Maybe bundle = Osgis.bundleFinder(framework) @@ -286,7 +296,8 @@ protected Maybe tryLoadFromBundle(LoaderDispatcher dispatcher, String .version(OsgiUtils.toOsgiVersion(version)) .find(); if (bundle.isAbsent()) { - throw new IllegalStateException("Bundle " + toBundleString(symbolicName, version) + " not found to load " + name); + throw new IllegalStateException("Bundle " + toBundleString(symbolicName, version) + + " not found to load " + name); } return dispatcher.tryLoadFrom(bundle.get(), name); } else { @@ -364,7 +375,8 @@ protected WhiteListBundlePredicate createBundleMatchingPredicate() { String symbolicName = arr[0]; String version = null; if (arr.length > 2) { - throw new IllegalStateException("Class loading fallback bundle white list '" + whiteList + "' not in the expected format [:]."); + throw new IllegalStateException("Class loading fallback bundle white list '" + whiteList + + "' not in the expected format [:]."); } else if (arr.length == 2) { version = arr[1]; } From b61f972e9f4197c64ebe37a69f1631db9febb220 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Wed, 8 Mar 2017 15:41:56 +0000 Subject: [PATCH 28/35] Return a generic context from newClassLoadingContextForCatalogItems https://github.com/apache/brooklyn-server/pull/338#discussion_r94751965 --- .../core/catalog/internal/CatalogUtils.java | 22 +++++++++---------- .../JavaCatalogToSpecTransformer.java | 6 ++++- .../internal/AbstractManagementContext.java | 4 +++- ...BrooklynMementoPersisterToObjectStore.java | 13 +++++++---- .../core/mgmt/rebind/RebindIteration.java | 5 ++++- .../brooklyn/util/core/ClassLoaderUtils.java | 6 +++-- 6 files changed, 36 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index 15aafd77b5..4bb11fd37a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -141,6 +141,17 @@ public static BrooklynClassLoadingContext newClassLoadingContext(@Nullable Manag return result; } + public static BrooklynClassLoadingContext newClassLoadingContextForCatalogItems( + ManagementContext managementContext, List catalogItemIds) { + + BrooklynClassLoadingContextSequential seqLoader = + new BrooklynClassLoadingContextSequential(managementContext); + for (String catalogItemId : catalogItemIds) { + addCatalogItemContext(managementContext, seqLoader, catalogItemId); + } + return seqLoader; + } + /** * Registers all bundles with the management context's OSGi framework. */ @@ -325,17 +336,6 @@ public static void setDisabled(ManagementContext mgmt, String symbolicName, Stri mgmt.getCatalog().persist(item); } - public static BrooklynClassLoadingContextSequential newClassLoadingContextForCatalogItems( - ManagementContext managementContext, List catalogItemIds) { - - BrooklynClassLoadingContextSequential seqLoader = - new BrooklynClassLoadingContextSequential(managementContext); - for (String catalogItemId : catalogItemIds) { - addCatalogItemContext(managementContext, seqLoader, catalogItemId); - } - return seqLoader; - } - private static void addCatalogItemContext(ManagementContext managementContext, BrooklynClassLoadingContextSequential loader, String catalogItemId) { RegisteredType item = managementContext.getTypeRegistry().get(catalogItemId); diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java index a990c2f878..bf698e869f 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java @@ -26,9 +26,11 @@ import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.api.policy.Policy; import org.apache.brooklyn.api.policy.PolicySpec; import org.apache.brooklyn.api.typereg.RegisteredType; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential; import org.apache.brooklyn.core.objs.BasicSpecParameter; import org.apache.brooklyn.core.plan.PlanNotRecognizedException; import org.apache.brooklyn.core.plan.PlanToSpecTransformer; @@ -81,7 +83,9 @@ public > SpecT c // java types were deprecated before we added osgi support so this isn't necessary, // but it doesn't hurt (and if we re-instate a class+bundle approach for RegisteredType // we will want to do this) - type = CatalogUtils.newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemHierarchy()).loadClass(javaType); + final BrooklynClassLoadingContextSequential ctx = new BrooklynClassLoadingContextSequential(mgmt); + ctx.add(CatalogUtils.newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemHierarchy())); + type = ctx.loadClass(javaType); } catch (Exception e) { Exceptions.propagateIfFatal(e); throw new IllegalStateException("Unable to load old-style java catalog item type " + javaType + " for item " + item, e); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java index 177102867f..16bb3de6ee 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java @@ -132,8 +132,10 @@ public BrooklynClassLoadingContext apply(@Nullable Object input) { EntityInternal internal = (EntityInternal)input; final List catalogItemHierarchy = internal.getCatalogItemHierarchy(); if (catalogItemHierarchy.size() > 0) { + final ManagementContext managementContext = internal.getManagementContext(); BrooklynClassLoadingContextSequential seqLoader = - newClassLoadingContextForCatalogItems(internal.getManagementContext(), catalogItemHierarchy); + new BrooklynClassLoadingContextSequential(managementContext); + seqLoader.add(newClassLoadingContextForCatalogItems(managementContext, catalogItemHierarchy)); JavaBrooklynClassLoadingContext entityLoader = JavaBrooklynClassLoadingContext.create(input.getClass().getClassLoader()); seqLoader.add(entityLoader); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java index d9cafdc7c4..a716151310 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java @@ -38,6 +38,8 @@ import javax.xml.xpath.XPathConstants; import com.google.common.collect.ImmutableList; + +import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.api.mgmt.rebind.PersistenceExceptionHandler; import org.apache.brooklyn.api.mgmt.rebind.RebindExceptionHandler; import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMemento; @@ -53,6 +55,7 @@ import org.apache.brooklyn.config.StringConfigMap; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential; import org.apache.brooklyn.core.mgmt.classloading.ClassLoaderFromBrooklynClassLoadingContext; import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore.StoreObjectAccessor; import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore.StoreObjectAccessorWithLock; @@ -183,16 +186,18 @@ protected MementoSerializer getSerializerWithCustomClassLoader(LookupCon } // See RebindIteration.BrooklynObjectInstantiator.load(), for handling where catalog item is missing; // similar logic here. - RegisteredType catalogItem = lookupContext.lookupManagementContext().getTypeRegistry().get(catalogItemId); + final ManagementContext managementContext = lookupContext.lookupManagementContext(); + RegisteredType catalogItem = managementContext.getTypeRegistry().get(catalogItemId); if (catalogItem == null) { // TODO do we need to only log once, rather than risk log.warn too often? I think this only happens on rebind, so ok. LOG.warn("Unable to load catalog item "+catalogItemId +" for custom class loader of " + type + " " + objectId + "; will use default class loader"); return null; } else { - return ClassLoaderFromBrooklynClassLoadingContext.of( - CatalogUtils.newClassLoadingContextForCatalogItems(lookupContext.lookupManagementContext(), - item.getCatalogItemHierarchy())); + final BrooklynClassLoadingContextSequential ctx = new BrooklynClassLoadingContextSequential(managementContext); + ctx.add( + CatalogUtils.newClassLoadingContextForCatalogItems(managementContext, item.getCatalogItemHierarchy())); + return ClassLoaderFromBrooklynClassLoadingContext.of(ctx); } } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index 1f23330dd5..80c5eb28c2 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -19,6 +19,7 @@ package org.apache.brooklyn.core.mgmt.rebind; import static com.google.common.base.Preconditions.checkNotNull; +import static org.apache.brooklyn.core.catalog.internal.CatalogUtils.newClassLoadingContextForCatalogItems; import java.io.IOException; import java.util.Arrays; @@ -74,6 +75,7 @@ import org.apache.brooklyn.core.feed.AbstractFeed; import org.apache.brooklyn.core.location.AbstractLocation; import org.apache.brooklyn.core.location.internal.LocationInternal; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential; import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext; import org.apache.brooklyn.core.mgmt.internal.BrooklynObjectManagementMode; import org.apache.brooklyn.core.mgmt.internal.BrooklynObjectManagerInternal; @@ -957,7 +959,8 @@ protected LoadedClass load(Class bTyp +" for "+contextSuchAsId + " (" + bType.getSimpleName()+"); attempting load nevertheless"); } try { - BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContextForCatalogItems(managementContext, idsFromReboundCatalog); + BrooklynClassLoadingContextSequential loader = new BrooklynClassLoadingContextSequential(managementContext); + loader.add(newClassLoadingContextForCatalogItems(managementContext, idsFromReboundCatalog)); return new LoadedClass(loader.loadClass(jType, bType), idsFromReboundCatalog); } catch (Exception e) { Exceptions.propagateIfFatal(e); diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java index d26296956d..88eb6996b7 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java @@ -16,6 +16,7 @@ package org.apache.brooklyn.util.core; import static com.google.common.base.Preconditions.checkNotNull; +import static org.apache.brooklyn.core.catalog.internal.CatalogUtils.newClassLoadingContextForCatalogItems; import java.net.URL; import java.util.List; @@ -30,6 +31,7 @@ import org.apache.brooklyn.core.BrooklynVersion; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.entity.EntityInternal; +import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential; import org.apache.brooklyn.core.mgmt.ha.OsgiManager; import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.util.core.LoaderDispatcher.ClassLoaderDispatcher; @@ -254,8 +256,8 @@ private Maybe loadClass(String name, LoaderDispatcher dispatcher, Stri if (catalogItemId != null) { CatalogItem item = CatalogUtils.getCatalogItemOptionalVersion(mgmt, catalogItemId); if (item != null) { - BrooklynClassLoadingContext loader = - CatalogUtils.newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemHierarchy()); + BrooklynClassLoadingContextSequential loader = new BrooklynClassLoadingContextSequential(mgmt); + loader.add(newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemHierarchy())); cls = dispatcher.tryLoadFrom(loader, className); if (cls.isPresent()) { return cls; From 81815f9424ba1987dbba5c3ee206deec4400babf Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Fri, 10 Mar 2017 17:10:33 +0000 Subject: [PATCH 29/35] Changes to move to catalogItemId + search path. Restore catalogItemId; change getCatalogItemIdHierarchy to getCatalogItemIdSearchPath. Update "stackCatalogItemId" to work with catalogItemId + search path. Use catalogItemIdAndSearchPath when merging wrapper parent to child. Rebind changes for catalogItemId + search path. Update AbstractBrooklynObject[Spec] for catalogItemId + searchPath Do catalogItemIdAndSearchPath only if non-null Update "catalogItemIdHierarchy" -> "searchPath" in persistence --- .../internal/AbstractBrooklynObjectSpec.java | 90 +++---- .../mementos/BrooklynMementoManifest.java | 10 +- .../api/mgmt/rebind/mementos/Memento.java | 6 +- .../brooklyn/api/objs/BrooklynObject.java | 9 +- .../catalog/CatalogOsgiYamlEntityTest.java | 8 +- .../catalog/CatalogOsgiYamlTemplateTest.java | 2 +- .../catalog/CatalogYamlEntityTest.java | 6 +- .../catalog/CatalogYamlLocationTest.java | 4 +- .../catalog/CatalogYamlRebindTest.java | 6 +- .../catalog/CatalogYamlTemplateTest.java | 4 +- .../core/catalog/internal/CatalogItemDo.java | 12 +- .../internal/CatalogItemDtoAbstract.java | 5 - .../core/catalog/internal/CatalogUtils.java | 14 +- .../JavaCatalogToSpecTransformer.java | 4 +- .../access/PortForwardManagerClient.java | 4 +- .../core/mgmt/EntityManagementUtils.java | 6 +- .../internal/AbstractManagementContext.java | 30 ++- ...BrooklynMementoPersisterToObjectStore.java | 24 +- .../mgmt/persist/XmlMementoSerializer.java | 2 +- .../core/mgmt/rebind/RebindIteration.java | 227 +++++++++++------- .../core/mgmt/rebind/dto/AbstractMemento.java | 48 +--- .../dto/BrooklynMementoManifestImpl.java | 4 +- .../rebind/dto/EntityMementoManifestImpl.java | 20 +- .../mgmt/rebind/dto/MementosGenerators.java | 3 +- .../transformer/CompoundTransformer.java | 23 +- .../core/objs/AbstractBrooklynObject.java | 38 +-- .../core/objs/AbstractEntityAdjunct.java | 3 +- .../core/objs/BrooklynObjectInternal.java | 8 +- .../objs/proxy/InternalEntityFactory.java | 14 +- .../objs/proxy/InternalLocationFactory.java | 16 +- .../objs/proxy/InternalPolicyFactory.java | 30 ++- .../brooklyn/util/core/ClassLoaderUtils.java | 4 +- .../rebind/RebindConfigInheritanceTest.java | 3 +- .../util/core/ClassLoaderUtilsTest.java | 4 +- .../rest/transform/LocationTransformer.java | 4 +- 35 files changed, 374 insertions(+), 321 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java index 16b4175097..10acfe40e1 100644 --- a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java +++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java @@ -68,7 +68,9 @@ public abstract class AbstractBrooklynObjectSpec type; private String displayName; - private Deque catalogItemIdStack; + private String catalogItemId; + private Deque catalogItemIdSearchPath = new ArrayDeque<>(); + private Set tags = MutableSet.of(); private List> parameters = ImmutableList.of(); @@ -108,13 +110,16 @@ public SpecT displayName(String val) { * (or TODO we add a separate field to record other catalog item IDs that could be applied for searching, see below) */ public SpecT catalogItemId(String val) { - getCatalogItemIdStack().clear(); - return stackCatalogItemId(val); + catalogItemId = val; + return self(); } - protected SpecT catalogItemIdStack(Collection catalogItemIdStack) { - this.catalogItemIdStack = null; - getCatalogItemIdStack().addAll(catalogItemIdStack); + public synchronized SpecT catalogItemIdAndSearchPath(String catalogItemId, Collection searchPath) { + if (catalogItemId != null) { + catalogItemId(catalogItemId); + catalogItemIdSearchPath.clear(); + catalogItemIdSearchPath.addAll(searchPath); + } return self(); } @@ -125,30 +130,37 @@ protected SpecT catalogItemIdStack(Collection catalogItemIdStack) { @Beta public SpecT catalogItemIdIfNotNull(String val) { if (val!=null) { - stackCatalogItemId(val); + catalogItemId(val); } return self(); } - private Deque getCatalogItemIdStack() { - if (catalogItemIdStack == null) { - catalogItemIdStack = new ArrayDeque<>(); + protected Object readResolve() { + if (catalogItemIdSearchPath == null) { + catalogItemIdSearchPath = new ArrayDeque<>(); } - return catalogItemIdStack; + return this; } /** * Adds (stacks) the catalog item id of a wrapping specification. * Does nothing if the value is null. + * If the value is not null, and is not the same as the current + * catalogItemId, then the *current* catalogItemId will + * be moved to the start of the search path, and the value supplied + * as the parameter here will be set as the new catalogItemId. *

- * Used when we want to collect nested item ID's so that *all* can be searched. + * Used when we want to collect IDs of items that extend other items, so that *all* can be searched. * e.g. if R3 extends R2 which extends R1 any one of these might supply config keys * referencing resources or types in their local bundles. */ @Beta public SpecT stackCatalogItemId(String val) { - if (null != val && (getCatalogItemIdStack().isEmpty() || !getCatalogItemIdStack().element().equals(val))) { - getCatalogItemIdStack().addFirst(val); + if (null != val) { + if (null != catalogItemId && !catalogItemId.equals(val)) { + catalogItemIdSearchPath.addFirst(catalogItemId); + } + catalogItemId(val); } return self(); } @@ -239,35 +251,26 @@ public final String getDisplayName() { return displayName; } - /** - * @deprecated since 0.11.0, use getOuterCatalogItemId or getInnerCatalogItemIds as appropriate - */ - @Deprecated public final String getCatalogItemId() { - return getOuterCatalogItemId(); + return catalogItemId; } - public final String getOuterCatalogItemId() { - if (getCatalogItemIdStack().size() != 0) { - return getCatalogItemIdStack().getFirst(); - } - return null; - } - - - /** - * An immutable list of ids of this object's catalog item and its defining catalog items. - * Wrapping items are first in the list (i.e. wrapping items precede wrapped items), - * for example, if the catalog item is defined as - *

-         *     items:
-         *     - id: X
-         *       item: Y
-         * 
- * then the list will contain X, Y. - */ - public final List getCatalogItemIdHierarchy() { - return ImmutableList.copyOf(catalogItemIdStack); + /** + * An immutable list of ids of catalog items that define this item. + * Wrapping items are first in the list (i.e. wrapping items precede wrapped items), + * for example, for a spec of an item of type Z, where the catalog is: + *
+     *     items:
+     *     - id: X
+     *     - id: Y
+     *       item: X
+     *     - id: Z
+     *       item: Y
+     * 
+ * then the spec will have getCatalogId() of Z and getCatalogItemIdSearchPath() of Y, X. + */ + public final List getCatalogItemIdSearchPath() { + return ImmutableList.copyOf(catalogItemIdSearchPath); } public final Set getTags() { @@ -317,7 +320,7 @@ protected SpecT copyFrom(SpecT otherSpec) { .configure(otherSpec.getConfig()) .configure(otherSpec.getFlags()) .tags(otherSpec.getTags()) - .catalogItemIdStack(otherSpec.getCatalogItemIdHierarchy()) + .catalogItemIdAndSearchPath(otherSpec.getCatalogItemId(), otherSpec.getCatalogItemIdSearchPath()) .parameters(otherSpec.getParameters()); } @@ -327,7 +330,8 @@ public boolean equals(Object obj) { if (!obj.getClass().equals(getClass())) return false; AbstractBrooklynObjectSpec other = (AbstractBrooklynObjectSpec) obj; if (!Objects.equal(getDisplayName(), other.getDisplayName())) return false; - if (!Objects.equal(getCatalogItemIdHierarchy(), other.getCatalogItemIdHierarchy())) return false; + if (!Objects.equal(getCatalogItemId(), other.getCatalogItemId())) return false; + if (!Objects.equal(getCatalogItemIdSearchPath(), other.getCatalogItemIdSearchPath())) return false; if (!Objects.equal(getType(), other.getType())) return false; if (!Objects.equal(getTags(), other.getTags())) return false; if (!Objects.equal(getConfig(), other.getConfig())) return false; @@ -338,7 +342,7 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return Objects.hashCode(getCatalogItemIdHierarchy(), getDisplayName(), getType(), getTags()); + return Objects.hashCode(getCatalogItemIdSearchPath(), getDisplayName(), getType(), getTags()); } /** diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java index bcf246e2b2..fa56d1d118 100644 --- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java +++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java @@ -36,14 +36,8 @@ public interface EntityMementoManifest extends Identifiable{ String getId(); String getType(); String getParent(); - - /** - * deprecated since 0.11.0, use {@link #getCatalogItemHierarchy()} instead - * @return - */ - @Deprecated String getCatalogItemId(); - - List getCatalogItemHierarchy(); + String getCatalogItemId(); + List getCatalogItemIdSearchPath(); } String getPlaneId(); diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java index 4ca219d783..71fc5871a8 100644 --- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java +++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/Memento.java @@ -48,15 +48,13 @@ public interface Memento extends Serializable { /** * The principal catalog item id. - * @deprecated since 0.11.0 - use {@link #getCatalogItemHierarchy()} instead */ - @Deprecated String getCatalogItemId(); /** - * Catalog Item Ids of all defining catalog items. + * Item Ids of all catalog items used to define this item. */ - List getCatalogItemHierarchy(); + List getCatalogItemIdSearchPath(); String getDisplayName(); diff --git a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java index ff49e1be43..d72fe6a49e 100644 --- a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java +++ b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObject.java @@ -60,16 +60,19 @@ public interface BrooklynObject extends Identifiable, Configurable { String getCatalogItemId(); /** - * An immutable list of ids of this object's catalog item and its defining catalog items. - * e.g. if the catalog item is defined as + * An immutable list of ids of catalog items that define this item. + * e.g. if the catalog item is defined as a Z where *
      *     items:
      *     - id: X
+     *     - id: Y
+     *       item: X
+     *     - id: Z
      *       item: Y
      * 
* then the list will contain X, Y. */ - List getCatalogItemHierarchy(); + List getCatalogItemIdSearchPath(); /** * Tags are arbitrary objects which can be attached to an entity for subsequent reference. diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java index dbf9445967..b0bf747fd4 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java @@ -708,7 +708,7 @@ public void testCreateOsgiSpecFromRegistry() throws Exception { BrooklynTypeRegistry registry = mgmt().getTypeRegistry(); RegisteredType item = registry.get(symbolicName, TEST_VERSION); AbstractBrooklynObjectSpec spec = registry.createSpec(item, null, null); - assertEquals(spec.getOuterCatalogItemId(), ver(symbolicName)); + assertEquals(spec.getCatalogItemId(), ver(symbolicName)); deleteCatalogEntity(symbolicName); } @@ -813,9 +813,9 @@ public void testCatalogItemIdInReferencedItems() throws Exception { Entity entity = app.getChildren().iterator().next(); assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); - assertEquals(entity.getCatalogItemHierarchy().size(), 2); - assertEquals(entity.getCatalogItemHierarchy().get(0), ver(symbolicNameOuter)); - assertEquals(entity.getCatalogItemHierarchy().get(1), ver(symbolicNameInner)); + assertEquals(entity.getCatalogItemIdSearchPath().size(), 1, "should have exactly one item in search path"); + assertEquals(entity.getCatalogItemIdSearchPath().get(0), ver(symbolicNameInner), + "should have " + symbolicNameInner + " in search path"); deleteCatalogEntity(symbolicNameInner); deleteCatalogEntity(symbolicNameOuter); diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlTemplateTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlTemplateTest.java index 4ecfcf282b..8b2a561934 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlTemplateTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlTemplateTest.java @@ -87,7 +87,7 @@ public void testMetadataOnSpecCreatedFromItem() throws Exception { EntitySpec child = Iterables.getOnlyElement( spec.getChildren() ); Assert.assertEquals(child.getType().getName(), SIMPLE_ENTITY_TYPE); - Assert.assertEquals(child.getOuterCatalogItemId(), "t1:"+TEST_VERSION); + Assert.assertEquals(child.getCatalogItemId(), "t1:"+TEST_VERSION); } private RegisteredType makeItem(String symbolicName, String templateType) { diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java index c40f7f8065..b3264f7301 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java @@ -643,9 +643,9 @@ public void testCatalogItemIdInReferencedItems() throws Exception { Entity entity = app.getChildren().iterator().next(); assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); - assertEquals(entity.getCatalogItemHierarchy().size(), 2); - assertEquals(entity.getCatalogItemHierarchy().get(0), ver(symbolicNameOuter)); - assertEquals(entity.getCatalogItemHierarchy().get(1), ver(symbolicNameInner)); + assertEquals(entity.getCatalogItemIdSearchPath().size(), 1, "should have exactly one item in search path"); + assertEquals(entity.getCatalogItemIdSearchPath().get(0), ver(symbolicNameInner), + "should have " + symbolicNameInner + " in search path"); deleteCatalogEntity(symbolicNameInner); deleteCatalogEntity(symbolicNameOuter); diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java index dc017d386b..01fb484d9d 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlLocationTest.java @@ -176,10 +176,10 @@ public void testTypeInheritance() throws Exception { LocationSpec spec1 = mgmt().getLocationRegistry().getLocationSpec(def1).get(); LocationSpec spec2 = mgmt().getLocationRegistry().getLocationSpec(def2).get(); - assertEquals(spec1.getOuterCatalogItemId(), "loc1:0.1.2"); + assertEquals(spec1.getCatalogItemId(), "loc1:0.1.2"); assertEquals(spec1.getDisplayName(), "My Loc 1"); assertContainsAll(spec1.getFlags(), ImmutableMap.of("mykey1", "myval1", "mykey1b", "myval1b")); - assertEquals(spec2.getOuterCatalogItemId(), "loc2:0.1.2"); + assertEquals(spec2.getCatalogItemId(), "loc2:0.1.2"); assertEquals(spec2.getDisplayName(), "My Loc 2"); assertContainsAll(spec2.getFlags(), ImmutableMap.of("mykey1", "myvalOverridden", "mykey1b", "myval1b", "mykey2", "myval2")); } 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 08616fc705..874e3018c6 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 @@ -170,13 +170,13 @@ public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, OsgiMode testRebindWithCatalogAndAppUsingOptions(mode, osgiMode, RebindOptions.create()); } - // Re-run the same tests as testRebindWithCatalogAndApp but with the XML updated to mimic state - // persisted before was replaced with . + // Re-run all the same tests as testRebindWithCatalogAndApp, but with the XML updated to mimic state + // persisted before was introduced. @Test(dataProvider = "dataProvider") public void testRebindWithCatalogAndAppRebindCatalogItemIds(RebindWithCatalogTestMode mode, OsgiMode osgiMode) throws Exception { final RebindOptions rebindOptions = RebindOptions.create(); applyCompoundStateTransformer(rebindOptions, CompoundTransformer.builder() - .xmlReplaceItem("//catalogItemHierarchy", "") + .xmlDeleteItem("//catalogItemIdSearchPath") .build()); testRebindWithCatalogAndAppUsingOptions(mode, osgiMode, rebindOptions); } diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java index f128abc04b..cb585e0e18 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java @@ -208,7 +208,7 @@ public void testMetadataOnSpecCreatedFromItem() throws Exception { EntitySpec child = Iterables.getOnlyElement( spec.getChildren() ); Assert.assertEquals(child.getType().getName(), TestEntity.class.getName()); - Assert.assertEquals(child.getOuterCatalogItemId(), "t1:"+TEST_VERSION); + Assert.assertEquals(child.getCatalogItemId(), "t1:"+TEST_VERSION); } @Test @@ -247,7 +247,7 @@ public void testMetadataOnSpecCreatedFromItemReferencingAnApp() throws Exception Assert.assertEquals(spec.getChildren().size(), 0); Assert.assertEquals(spec.getType(), BasicApplication.class); Assert.assertEquals(ConfigBag.newInstance(spec.getConfig()).getStringKey("foo"), "boo"); - Assert.assertEquals(spec.getOuterCatalogItemId(), "app1r:1"); + Assert.assertEquals(spec.getCatalogItemId(), "app1r:1"); } private RegisteredType addCatalogItem(String symbolicName, String templateType) { diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java index 42cdb42b88..36e1192142 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java @@ -132,18 +132,18 @@ public void setCatalogItemId(String id) { } @Override - public void setCatalogItemIdHierarchy(List ids) { - itemDto.setCatalogItemIdHierarchy(ids); + public void setCatalogItemIdSearchPath(List ids) { + itemDto.setCatalogItemIdSearchPath(ids); } @Override - public List getCatalogItemHierarchy() { - return itemDto.getCatalogItemHierarchy(); + public List getCatalogItemIdSearchPath() { + return itemDto.getCatalogItemIdSearchPath(); } @Override - public void nestCatalogItemId(String id) { - itemDto.nestCatalogItemId(id); + public void stackCatalogItemId(String id) { + itemDto.stackCatalogItemId(id); } @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java index 539b8b187c..0bae32d566 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java @@ -103,11 +103,6 @@ public String getCatalogItemId() { return CatalogUtils.getVersionedId(getSymbolicName(), getVersion()); } - @Override - public List getCatalogItemHierarchy() { - return ImmutableList.of(getCatalogItemId()); - } - @Override public String getJavaType() { if (javaType != null) return javaType; diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index 4bb11fd37a..2f85db977e 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -142,12 +142,12 @@ public static BrooklynClassLoadingContext newClassLoadingContext(@Nullable Manag } public static BrooklynClassLoadingContext newClassLoadingContextForCatalogItems( - ManagementContext managementContext, List catalogItemIds) { + ManagementContext managementContext, String catalogItemId, List searchPath) { - BrooklynClassLoadingContextSequential seqLoader = - new BrooklynClassLoadingContextSequential(managementContext); - for (String catalogItemId : catalogItemIds) { - addCatalogItemContext(managementContext, seqLoader, catalogItemId); + BrooklynClassLoadingContextSequential seqLoader = new BrooklynClassLoadingContextSequential(managementContext); + addCatalogItemContext(managementContext, seqLoader, catalogItemId); + for (String searchId : searchPath) { + addCatalogItemContext(managementContext, seqLoader, searchId); } return seqLoader; } @@ -195,7 +195,9 @@ public static void setCatalogItemIdOnAddition(Entity entity, BrooklynObject item if (log.isDebugEnabled()) BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(entity), "Catalog item addition: "+entity+" from "+entity.getCatalogItemId()+" applying its catalog item ID to "+itemBeingAdded); - ((BrooklynObjectInternal)itemBeingAdded).setCatalogItemIdHierarchy(entity.getCatalogItemHierarchy()); + final BrooklynObjectInternal addInternal = (BrooklynObjectInternal) itemBeingAdded; + addInternal.setCatalogItemId(entity.getCatalogItemId()); + addInternal.setCatalogItemIdSearchPath(entity.getCatalogItemIdSearchPath()); } else { if (!itemBeingAdded.getCatalogItemId().equals(entity.getCatalogItemId())) { // not a problem, but something to watch out for diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java index bf698e869f..f9c413106a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java @@ -26,7 +26,6 @@ import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; import org.apache.brooklyn.api.mgmt.ManagementContext; -import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.api.policy.Policy; import org.apache.brooklyn.api.policy.PolicySpec; import org.apache.brooklyn.api.typereg.RegisteredType; @@ -84,7 +83,8 @@ public > SpecT c // but it doesn't hurt (and if we re-instate a class+bundle approach for RegisteredType // we will want to do this) final BrooklynClassLoadingContextSequential ctx = new BrooklynClassLoadingContextSequential(mgmt); - ctx.add(CatalogUtils.newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemHierarchy())); + ctx.add(CatalogUtils.newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemId(), + item.getCatalogItemIdSearchPath())); type = ctx.loadClass(javaType); } catch (Exception e) { Exceptions.propagateIfFatal(e); diff --git a/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java b/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java index d5781cd3ad..92091fc40b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java +++ b/core/src/main/java/org/apache/brooklyn/core/location/access/PortForwardManagerClient.java @@ -388,8 +388,8 @@ public String getCatalogItemId() { } @Override - public List getCatalogItemHierarchy() { - return getDelegate().getCatalogItemHierarchy(); + public List getCatalogItemIdSearchPath() { + return getDelegate().getCatalogItemIdSearchPath(); } @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java index d222151ce6..8fb6345449 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java @@ -259,12 +259,14 @@ private static void mergeWrapperParentSpecToChildEntity(EntitySpec, Object> configWithoutWrapperMarker = Maps.filterKeys(wrapperParent.getConfig(), Predicates.not(Predicates.>equalTo(EntityManagementUtils.WRAPPER_APP_MARKER))); + Map, Object> configWithoutWrapperMarker = + Maps.filterKeys(wrapperParent.getConfig(), + Predicates.not(Predicates.>equalTo(EntityManagementUtils.WRAPPER_APP_MARKER))); wrappedChild.configure(configWithoutWrapperMarker); wrappedChild.configure(wrapperParent.getFlags()); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java index 16bb3de6ee..6d81626613 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java @@ -51,6 +51,7 @@ import org.apache.brooklyn.api.mgmt.rebind.RebindManager; import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry; +import org.apache.brooklyn.api.typereg.RegisteredType; import org.apache.brooklyn.config.StringConfigMap; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; import org.apache.brooklyn.core.catalog.internal.CatalogInitialization; @@ -130,16 +131,25 @@ private static DataGridFactory loadDataGridFactory(BrooklynProperties properties public BrooklynClassLoadingContext apply(@Nullable Object input) { if (input instanceof EntityInternal) { EntityInternal internal = (EntityInternal)input; - final List catalogItemHierarchy = internal.getCatalogItemHierarchy(); - if (catalogItemHierarchy.size() > 0) { - final ManagementContext managementContext = internal.getManagementContext(); - BrooklynClassLoadingContextSequential seqLoader = - new BrooklynClassLoadingContextSequential(managementContext); - seqLoader.add(newClassLoadingContextForCatalogItems(managementContext, catalogItemHierarchy)); - JavaBrooklynClassLoadingContext entityLoader = - JavaBrooklynClassLoadingContext.create(input.getClass().getClassLoader()); - seqLoader.add(entityLoader); - return seqLoader; + String inputCatalogItemId = internal.getCatalogItemId(); + if(inputCatalogItemId != null) { + RegisteredType item = internal.getManagementContext().getTypeRegistry().get(internal.getCatalogItemId()); + + if (item != null) { + final List searchPath = internal.getCatalogItemIdSearchPath(); + final ManagementContext managementContext = internal.getManagementContext(); + BrooklynClassLoadingContextSequential seqLoader = + new BrooklynClassLoadingContextSequential(managementContext); + seqLoader.add(newClassLoadingContextForCatalogItems(managementContext, inputCatalogItemId, searchPath)); + JavaBrooklynClassLoadingContext entityLoader = + JavaBrooklynClassLoadingContext.create(input.getClass().getClassLoader()); + seqLoader.add(entityLoader); + return seqLoader; + } else { + log.error("Can't find catalog item " + internal.getCatalogItemId() + + " used for instantiating entity " + internal + + ". Falling back to application classpath."); + } } return apply(internal.getManagementSupport()); } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java index a716151310..5aace6d7c1 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java @@ -37,8 +37,6 @@ import javax.annotation.Nullable; import javax.xml.xpath.XPathConstants; -import com.google.common.collect.ImmutableList; - import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.api.mgmt.rebind.PersistenceExceptionHandler; import org.apache.brooklyn.api.mgmt.rebind.RebindExceptionHandler; @@ -195,8 +193,8 @@ protected MementoSerializer getSerializerWithCustomClassLoader(LookupCon return null; } else { final BrooklynClassLoadingContextSequential ctx = new BrooklynClassLoadingContextSequential(managementContext); - ctx.add( - CatalogUtils.newClassLoadingContextForCatalogItems(managementContext, item.getCatalogItemHierarchy())); + ctx.add(CatalogUtils.newClassLoadingContextForCatalogItems(managementContext, + item.getCatalogItemId(), item.getCatalogItemIdSearchPath())); return ClassLoaderFromBrooklynClassLoadingContext.of(ctx); } } @@ -360,20 +358,6 @@ private List getStringList(String innerPath) { } } - // We must be able to cope with XML serialized with either a single "catalogItemId" - // or a list "catalogItemHierarchy" of catalog item ids. Only one should be encountered - // but in any case prefer the list of ids. - private ImmutableList getCatalogItemIds(XPathHelper x) { - final MutableList list = MutableList.of(); - final List catalogItemHierarchy = x.getStringList("catalogItemHierarchy"); - final String catalogItemId = Strings.emptyToNull(x.get("catalogItemId")); - if (!catalogItemHierarchy.isEmpty()) { - list.addAll(catalogItemHierarchy); - } else if (catalogItemId != null) { - list.add(catalogItemId); - } - return ImmutableList.copyOf(list); - } @Override public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mementoData, @@ -391,7 +375,9 @@ public void visit(BrooklynObjectType type, String objectId, final String content XPathHelper x = new XPathHelper(contents, "/"+type.toCamelCase()+"/"); switch (type) { case ENTITY: - builder.entity(x.get("id"), x.get("type"), Strings.emptyToNull(x.get("parent")), getCatalogItemIds(x)); + builder.entity(x.get("id"), x.get("type"), Strings.emptyToNull(x.get("parent")), + Strings.emptyToNull(x.get("catalogItemId")), + x.getStringList("searchPath")); break; case LOCATION: case POLICY: diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java index 12b2c3a902..16beb4ef9c 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java @@ -455,7 +455,7 @@ public boolean canConvert(@SuppressWarnings("rawtypes") Class type) { public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { if (source == null) return; AbstractBrooklynObjectSpec spec = (AbstractBrooklynObjectSpec) source; - String catalogItemId = spec.getOuterCatalogItemId(); + String catalogItemId = spec.getCatalogItemId(); if (Strings.isNonBlank(catalogItemId)) { // write this field first, so we can peek at it when we read writer.startNode("catalogItemId"); diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index 80c5eb28c2..a12bd7eb1a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -19,6 +19,8 @@ package org.apache.brooklyn.core.mgmt.rebind; import static com.google.common.base.Preconditions.checkNotNull; +import static org.apache.brooklyn.core.BrooklynFeatureEnablement.FEATURE_AUTO_FIX_CATALOG_REF_ON_REBIND; +import static org.apache.brooklyn.core.BrooklynFeatureEnablement.FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND; import static org.apache.brooklyn.core.catalog.internal.CatalogUtils.newClassLoadingContextForCatalogItems; import java.io.IOException; @@ -32,7 +34,7 @@ import java.util.concurrent.atomic.AtomicInteger; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; + import org.apache.brooklyn.api.catalog.BrooklynCatalog; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.entity.Application; @@ -771,7 +773,7 @@ protected void finishingUp() { if (!isEmpty) { BrooklynLogging.log(LOG, shouldLogRebinding() ? LoggingLevel.INFO : LoggingLevel.DEBUG, "Rebind complete " + "("+mode+(readOnlyRebindCount.get()>=0 ? ", iteration "+readOnlyRebindCount : "")+")" + - " in {}: {} app{}, {} entit{}, {} location{}, {} polic{}, {} enricher{}, {} feed{}, {} catalog item{}", new Object[]{ + " in {}: {} app{}, {} entit{}, {} location{}, {} polic{}, {} enricher{}, {} feed{}, {} catalog item{}", Time.makeTimeStringRounded(timer), applications.size(), Strings.s(applications), rebindContext.getEntities().size(), Strings.ies(rebindContext.getEntities()), rebindContext.getLocations().size(), Strings.s(rebindContext.getLocations()), @@ -779,7 +781,7 @@ protected void finishingUp() { rebindContext.getEnrichers().size(), Strings.s(rebindContext.getEnrichers()), rebindContext.getFeeds().size(), Strings.s(rebindContext.getFeeds()), rebindContext.getCatalogItems().size(), Strings.s(rebindContext.getCatalogItems()) - }); + ); } // Return the top-level applications @@ -797,30 +799,51 @@ protected void noteErrors(final RebindExceptionHandler exceptionHandler, Excepti rebindMetrics.noteError(messages); } } - - protected List findCatalogItemIds(ClassLoader cl, Map entityIdToManifest, EntityMementoManifest entityManifest) { - if (!entityManifest.getCatalogItemHierarchy().isEmpty()) { - return entityManifest.getCatalogItemHierarchy(); + + protected class CatalogItemIdAndSearchPath { + private String catalogItemId; + private List searchPath; + + public CatalogItemIdAndSearchPath(String catalogItemId, List searchPath) { + this.catalogItemId = catalogItemId; + this.searchPath = searchPath; + } + public String getCatalogItemId() { return catalogItemId; } + public List getSearchPath() { return searchPath; } + } + + protected CatalogItemIdAndSearchPath findCatalogItemIds(ClassLoader cl, Map entityIdToManifest, EntityMementoManifest entityManifest) { + + if (entityManifest.getCatalogItemId() != null) { + return new CatalogItemIdAndSearchPath(entityManifest.getCatalogItemId(), + entityManifest.getCatalogItemIdSearchPath()); } - if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND)) { + if (BrooklynFeatureEnablement.isEnabled(FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND)) { + String typeId = null; + List searchPath = MutableList.of(); //First check if any of the parent entities has a catalogItemId set. EntityMementoManifest ptr = entityManifest; while (ptr != null) { - if (ptr.getCatalogItemHierarchy() != null) { - List ids = MutableList.of(); - for (String id : ptr.getCatalogItemHierarchy()) { - RegisteredType type = managementContext.getTypeRegistry().get(id); + final String pId = ptr.getCatalogItemId(); + if (pId != null) { + RegisteredType type = managementContext.getTypeRegistry().get(pId); + if (type != null) { + typeId = type.getId(); + } + for (String id : ptr.getCatalogItemIdSearchPath()) { + type = managementContext.getTypeRegistry().get(id); if (type != null) { - ids.add(type.getId()); + searchPath.add(type.getId()); } else { - //Couldn't find a catalog item with this id, but return it anyway and + //Couldn't find a catalog item with this id, but add it anyway and //let the caller deal with the error. //TODO under what circumstances is this permitted? - ids.add(id); + searchPath.add(id); } } - return ids; + return new CatalogItemIdAndSearchPath(typeId, searchPath); } if (ptr.getParent() != null) { ptr = entityIdToManifest.get(ptr.getParent()); @@ -839,7 +862,7 @@ protected List findCatalogItemIds(ClassLoader cl, Mapof()); } if (ptr.getParent() != null) { ptr = entityIdToManifest.get(ptr.getParent()); @@ -851,7 +874,7 @@ protected List findCatalogItemIds(ClassLoader cl, Mapof()); } // TODO get to the point when we can deprecate this behaviour!: @@ -859,21 +882,24 @@ protected List findCatalogItemIds(ClassLoader cl, Mapof()); } } } - return ImmutableList.of(); + return new CatalogItemIdAndSearchPath(null, ImmutableList.of()); } protected static class LoadedClass { protected final Class clazz; - protected final List catalogItemIds; - - protected LoadedClass(Class clazz, List catalogItemIds) { + protected final String catalogItemId; + protected final List searchPath; + + protected LoadedClass(Class clazz, String catalogItemId, List searchPath) { this.clazz = clazz; - this.catalogItemIds = catalogItemIds; + this.catalogItemId = catalogItemId; + this.searchPath = searchPath; } } @@ -891,10 +917,12 @@ protected BrooklynObjectInstantiator(ClassLoader classLoader, RebindContextImpl protected Entity newEntity(EntityMementoManifest entityManifest) { String entityId = entityManifest.getId(); - List catalogItemIds = findCatalogItemIds(classLoader, mementoManifest.getEntityIdToManifest(), entityManifest); + CatalogItemIdAndSearchPath idPath = + findCatalogItemIds(classLoader, mementoManifest.getEntityIdToManifest(), entityManifest); String entityType = entityManifest.getType(); - LoadedClass loaded = load(Entity.class, entityType, catalogItemIds, entityId); + LoadedClass loaded = + load(Entity.class, entityType, idPath.getCatalogItemId(), idPath.getSearchPath(), entityId); Class entityClazz = loaded.clazz; Entity entity; @@ -906,7 +934,8 @@ protected Entity newEntity(EntityMementoManifest entityManifest) { entity = entityFactory.constructEntity(entityClazz, Reflections.getAllInterfaces(entityClazz), entityId); } else { - LOG.warn("Deprecated rebind of entity without no-arg constructor; this may not be supported in future versions: id="+entityId+"; type="+entityType); + LOG.warn("Deprecated rebind of entity without no-arg constructor; " + + "this may not be supported in future versions: id=" + entityId+"; type=" + entityType); // There are several possibilities for the constructor; find one that works. // Prefer passing in the flags because required for Application to set the management context @@ -916,9 +945,11 @@ protected Entity newEntity(EntityMementoManifest entityManifest) { flags.put("id", entityId); if (AbstractApplication.class.isAssignableFrom(entityClazz)) flags.put("mgmt", managementContext); - // TODO document the multiple sources of flags, and the reason for setting the mgmt context *and* supplying it as the flag + // TODO document the multiple sources of flags, and the reason for setting the mgmt context *and* + // supplying it as the flag // (NB: merge reported conflict as the two things were added separately) - entity = invokeConstructor(null, entityClazz, new Object[] {flags}, new Object[] {flags, null}, new Object[] {null}, new Object[0]); + entity = invokeConstructor(null, entityClazz, + new Object[] {flags}, new Object[] {flags, null}, new Object[] {null}, new Object[0]); // In case the constructor didn't take the Map arg, then also set it here. // e.g. for top-level app instances such as WebClusterDatabaseExampleApp will (often?) not have @@ -933,90 +964,110 @@ protected Entity newEntity(EntityMementoManifest entityManifest) { managementContext.prePreManage(entity); } - setCatalogItemIds(entity, loaded.catalogItemIds); + setCatalogItemIds(entity, loaded.catalogItemId, loaded.searchPath); return entity; } - protected void setCatalogItemIds(BrooklynObject object, List idHierarchy) { - ((BrooklynObjectInternal)object).setCatalogItemIdHierarchy(idHierarchy); + protected void setCatalogItemIds(BrooklynObject object, String catalogItemId, List searchPath) { + final BrooklynObjectInternal internal = (BrooklynObjectInternal) object; + internal.setCatalogItemId(catalogItemId); + internal.setCatalogItemIdSearchPath(searchPath); } protected LoadedClass load(Class bType, Memento memento) { - return load(bType, memento.getType(), memento.getCatalogItemHierarchy(), memento.getId()); + return load(bType, memento.getType(), memento.getCatalogItemId(), memento.getCatalogItemIdSearchPath(), + memento.getId()); } @SuppressWarnings("unchecked") - protected LoadedClass load(Class bType, String jType, List catalogItemIds, String contextSuchAsId) { + protected LoadedClass load(Class bType, String jType, + String catalogItemId, List searchPath, String contextSuchAsId) { checkNotNull(jType, "Type of %s (%s) must not be null", contextSuchAsId, bType.getSimpleName()); - List idsFromReboundCatalog = MutableList.of(); - if (catalogItemIds != null && !catalogItemIds.isEmpty()) { - findCatalogIdsInReboundCatalog(bType, catalogItemIds, contextSuchAsId, idsFromReboundCatalog); - if (idsFromReboundCatalog.size() != catalogItemIds.size()) { - LOG.warn("Unable to load all catalog items "+ Iterables.toString(catalogItemIds) - +" for "+contextSuchAsId + " (" + bType.getSimpleName()+"); attempting load nevertheless"); + List reboundSearchPath = MutableList.of(); + if (searchPath != null && !searchPath.isEmpty()) { + for (String searchItemId : searchPath) { + CatalogItem searchItem = findCatalogItemInReboundCatalog(bType, searchItemId, contextSuchAsId); + if (searchItem != null) { + reboundSearchPath.add(searchItem.getCatalogItemId()); + } else { + LOG.warn("Unable to load catalog item "+ searchItemId + +" for "+contextSuchAsId + " (" + bType.getSimpleName()+"); attempting load nevertheless"); + } } - try { - BrooklynClassLoadingContextSequential loader = new BrooklynClassLoadingContextSequential(managementContext); - loader.add(newClassLoadingContextForCatalogItems(managementContext, idsFromReboundCatalog)); - return new LoadedClass(loader.loadClass(jType, bType), idsFromReboundCatalog); - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - LOG.warn("Unable to load "+jType+" using loader; will try reflections"); + } + + if (catalogItemId != null) { + CatalogItem catalogItem = findCatalogItemInReboundCatalog(bType, catalogItemId, contextSuchAsId); + if (catalogItem != null) { + String transformedCatalogItemId = catalogItem.getCatalogItemId(); + try { + BrooklynClassLoadingContextSequential loader = + new BrooklynClassLoadingContextSequential(managementContext); + loader.add(newClassLoadingContextForCatalogItems(managementContext, transformedCatalogItemId, + reboundSearchPath)); + return new LoadedClass(loader.loadClass(jType, bType), transformedCatalogItemId, reboundSearchPath); + } catch (Exception e) { + Exceptions.propagateIfFatal(e); + LOG.warn("Unable to load "+jType+" using loader; will try reflections"); + } + } else { + LOG.warn("Unable to load catalog item "+catalogItemId+" for " + contextSuchAsId + + " ("+bType.getSimpleName()+"); will try reflection"); } } - + try { - return new LoadedClass((Class)loadClass(jType), catalogItemIds); + return new LoadedClass((Class)loadClass(jType), catalogItemId, reboundSearchPath); } catch (Exception e) { Exceptions.propagateIfFatal(e); LOG.warn("Unable to load "+jType+" using reflections; will try standard context"); } - if (catalogItemIds != null && !catalogItemIds.isEmpty()) { - throw new IllegalStateException("Unable to load catalog items " + Iterables.toString(catalogItemIds) - + " for "+contextSuchAsId+", or load class from classpath"); - } else if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND)) { + if (catalogItemId != null) { + throw new IllegalStateException("Unable to load catalog item " + catalogItemId + " for " + + contextSuchAsId + ", or load class from classpath"); + } else if (BrooklynFeatureEnablement.isEnabled(FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND)) { //Try loading from whichever catalog bundle succeeds. BrooklynCatalog catalog = managementContext.getCatalog(); for (CatalogItem item : catalog.getCatalogItems()) { BrooklynClassLoadingContext catalogLoader = CatalogUtils.newClassLoadingContext(managementContext, item); Maybe> catalogClass = catalogLoader.tryLoadClass(jType); if (catalogClass.isPresent()) { - return new LoadedClass((Class) catalogClass.get(), catalogItemIds); + return new LoadedClass((Class) catalogClass.get(), catalogItemId, reboundSearchPath); } } - throw new IllegalStateException("No catalogItemId specified for "+contextSuchAsId+" and can't load class (" + jType + ") from either classpath or catalog items"); + throw new IllegalStateException("No catalogItemId specified for " + contextSuchAsId + + " and can't load class (" + jType + ") from either classpath or catalog items"); } else { - throw new IllegalStateException("No catalogItemId specified for "+contextSuchAsId+" and can't load class (" + jType + ") from classpath"); + throw new IllegalStateException("No catalogItemId specified for " + contextSuchAsId + + " and can't load class (" + jType + ") from classpath"); } } - private void findCatalogIdsInReboundCatalog(Class bType, List catalogItemIds, String contextSuchAsId, List idsToUse) { - for (String catalogItemId : catalogItemIds) { - CatalogItem catalogItem = rebindContext.lookup().lookupCatalogItem(catalogItemId); - if (catalogItem == null) { - if (BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_AUTO_FIX_CATALOG_REF_ON_REBIND)) { - // See https://issues.apache.org/jira/browse/BROOKLYN-149 - // This is a dangling reference to the catalog item (which will have been logged by lookupCatalogItem). - // Try loading as any version. - if (CatalogUtils.looksLikeVersionedId(catalogItemId)) { - String symbolicName = CatalogUtils.getSymbolicNameFromVersionedId(catalogItemId); - catalogItem = rebindContext.lookup().lookupCatalogItem(symbolicName); - - if (catalogItem != null) { - LOG.warn("Unable to load catalog item "+ catalogItemIds +" for "+contextSuchAsId - +" ("+bType.getSimpleName()+"); will auto-upgrade to "+catalogItem.getCatalogItemId()); - idsToUse.add(catalogItem.getCatalogItemId()); - } + private CatalogItem findCatalogItemInReboundCatalog(Class bType, + String catalogItemId, String contextSuchAsId) { + CatalogItem catalogItem = rebindContext.lookup().lookupCatalogItem(catalogItemId); + if (catalogItem == null) { + if (BrooklynFeatureEnablement.isEnabled(FEATURE_AUTO_FIX_CATALOG_REF_ON_REBIND)) { + // See https://issues.apache.org/jira/browse/BROOKLYN-149 + // This is a dangling reference to the catalog item (which will have been logged by lookupCatalogItem). + // Try loading as any version. + if (CatalogUtils.looksLikeVersionedId(catalogItemId)) { + String symbolicName = CatalogUtils.getSymbolicNameFromVersionedId(catalogItemId); + catalogItem = rebindContext.lookup().lookupCatalogItem(symbolicName); + + if (catalogItem != null) { + LOG.warn("Unable to load catalog item " + catalogItemId + " for " + contextSuchAsId + + " (" + bType.getSimpleName() + "); will auto-upgrade to " + + catalogItem.getCatalogItemId() + ":" + catalogItem.getVersion()); } } - } else { - idsToUse.add(catalogItemId); } } + return catalogItem; } protected Class loadClass(String jType) throws ClassNotFoundException { @@ -1056,7 +1107,8 @@ protected Location newLocation(String locationId, String locationType) { return location; } else { - LOG.warn("Deprecated rebind of location without no-arg constructor; this may not be supported in future versions: id="+locationId+"; type="+locationType); + LOG.warn("Deprecated rebind of location without no-arg constructor; " + + "this may not be supported in future versions: id=" + locationId + "; type="+locationType); // There are several possibilities for the constructor; find one that works. // Prefer passing in the flags because required for Application to set the management context @@ -1073,7 +1125,8 @@ protected Location newLocation(String locationId, String locationType) { */ protected Policy newPolicy(PolicyMemento memento) { String id = memento.getId(); - LoadedClass loaded = load(Policy.class, memento.getType(), memento.getCatalogItemHierarchy(), id); + LoadedClass loaded = load(Policy.class, memento.getType(), memento.getCatalogItemId(), + memento.getCatalogItemIdSearchPath(), id); Class policyClazz = loaded.clazz; Policy policy; @@ -1084,7 +1137,8 @@ protected Policy newPolicy(PolicyMemento memento) { ((AbstractPolicy)policy).setManagementContext(managementContext); } else { - LOG.warn("Deprecated rebind of policy without no-arg constructor; this may not be supported in future versions: id="+id+"; type="+policyClazz); + LOG.warn("Deprecated rebind of policy without no-arg constructor; " + + "this may not be supported in future versions: id=" + id + "; type="+policyClazz); // There are several possibilities for the constructor; find one that works. // Prefer passing in the flags because required for Application to set the management context @@ -1098,7 +1152,7 @@ protected Policy newPolicy(PolicyMemento memento) { policy = invokeConstructor(null, policyClazz, new Object[] {flags}); } - setCatalogItemIds(policy, memento.getCatalogItemHierarchy()); + setCatalogItemIds(policy, memento.getCatalogItemId(), memento.getCatalogItemIdSearchPath()); return policy; } @@ -1118,7 +1172,8 @@ protected Enricher newEnricher(EnricherMemento memento) { ((AbstractEnricher)enricher).setManagementContext(managementContext); } else { - LOG.warn("Deprecated rebind of enricher without no-arg constructor; this may not be supported in future versions: id="+id+"; type="+enricherClazz); + LOG.warn("Deprecated rebind of enricher without no-arg constructor; " + + "this may not be supported in future versions: id=" + id + "; type="+enricherClazz); // There are several possibilities for the constructor; find one that works. // Prefer passing in the flags because required for Application to set the management context @@ -1132,7 +1187,7 @@ protected Enricher newEnricher(EnricherMemento memento) { enricher = invokeConstructor(reflections, enricherClazz, new Object[] {flags}); } - setCatalogItemIds(enricher, memento.getCatalogItemHierarchy()); + setCatalogItemIds(enricher, memento.getCatalogItemId(), memento.getCatalogItemIdSearchPath()); return enricher; } @@ -1152,10 +1207,11 @@ protected Feed newFeed(FeedMemento memento) { ((AbstractFeed)feed).setManagementContext(managementContext); } else { - throw new IllegalStateException("rebind of feed without no-arg constructor unsupported: id="+id+"; type="+feedClazz); + throw new IllegalStateException("rebind of feed without no-arg constructor unsupported: id=" + id + + "; type="+feedClazz); } - setCatalogItemIds(feed, memento.getCatalogItemHierarchy()); + setCatalogItemIds(feed, memento.getCatalogItemId(), memento.getCatalogItemIdSearchPath()); return feed; } @@ -1189,7 +1245,8 @@ protected T invokeConstructor(Reflections reflections, Class clazz, Objec args.append(Arrays.asList(possibleArgs[i])); } } - throw new IllegalStateException("Cannot instantiate instance of type "+clazz+"; expected constructor signature not found ("+args+")"); + throw new IllegalStateException("Cannot instantiate instance of type " + clazz + + "; expected constructor signature not found ("+args+")"); } } 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 876ab24e5e..6e2a0f2f7d 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 @@ -24,7 +24,6 @@ import java.util.Map; import java.util.Set; -import com.google.common.collect.Iterables; import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento; import org.apache.brooklyn.core.BrooklynVersion; import org.apache.brooklyn.core.config.Sanitizer; @@ -47,9 +46,8 @@ protected static abstract class Builder> { protected String type; protected Class typeClass; protected String displayName; - // catalogItemId is retained to support rebind of previously persisted state (prior to catalogItemHierarchy) protected String catalogItemId; - protected List catalogItemHierarchy; + protected List searchPath; protected Map customFields = Maps.newLinkedHashMap(); protected List tags = Lists.newArrayList(); protected Map> relations = Maps.newLinkedHashMap(); @@ -68,7 +66,9 @@ public B from(Memento other) { type = other.getType(); typeClass = other.getTypeClass(); displayName = other.getDisplayName(); - setCatalogItemIdHierarchy(other.getCatalogItemHierarchy(), other.getCatalogItemId()); + catalogItemId = other.getCatalogItemId(); + searchPath = isEmpty(other.getCatalogItemIdSearchPath()) ? + MutableList.of() : MutableList.copyOf(other.getCatalogItemIdSearchPath()); customFields.putAll(other.getCustomFields()); tags.addAll(other.getTags()); relations.putAll(other.getRelations()); @@ -76,16 +76,6 @@ public B from(Memento other) { return self(); } - private void setCatalogItemIdHierarchy(List otherItemIdHierarchy, String otherItemId) { - if (isEmpty(otherItemIdHierarchy) && otherItemId == null) { - catalogItemHierarchy = MutableList.of(); - } else if (isEmpty(otherItemIdHierarchy) && otherItemId != null) { - catalogItemHierarchy = MutableList.of(otherItemId); - } else { - catalogItemHierarchy = MutableList.copyOf(otherItemIdHierarchy); - } - } - private boolean isEmpty(List ids) { return ids == null || ids.isEmpty(); } @@ -103,14 +93,8 @@ public B customFields(Map vals) { private String type; private String id; private String displayName; - - @Deprecated - /** - @deprecated since 0.11.0; retained to support rebind of previously persisted state (prior to catalogItemHierarchy) - */ protected String catalogItemId; - - private List catalogItemHierarchy; + private List searchPath; private List tags; private Map> relations; @@ -130,7 +114,8 @@ protected AbstractMemento(Builder builder) { type = builder.type; typeClass = builder.typeClass; displayName = builder.displayName; - catalogItemHierarchy = builder.catalogItemHierarchy; + catalogItemId = builder.catalogItemId; + searchPath = builder.searchPath; setCustomFields(builder.customFields); tags = toPersistedList(builder.tags); relations = toPersistedMap(builder.relations); @@ -141,17 +126,6 @@ protected AbstractMemento(Builder builder) { // but the method declared here simplifies how it is connected in via builder etc protected abstract void setCustomFields(Map fields); - // deals with value created by deserialization of state persisted with - private void normalizeCatalogItemIds() { - if (catalogItemHierarchy == null) { - catalogItemHierarchy = MutableList.of(); - } - if (catalogItemHierarchy.isEmpty() && catalogItemId != null) { - catalogItemHierarchy = MutableList.of(catalogItemId); - catalogItemId = null; - } - } - @Override public void injectTypeClass(Class clazz) { this.typeClass = clazz; @@ -184,14 +158,12 @@ public String getDisplayName() { @Override public String getCatalogItemId() { - normalizeCatalogItemIds(); - return Iterables.getFirst(getCatalogItemHierarchy(), null); + return catalogItemId; } @Override - public List getCatalogItemHierarchy() { - normalizeCatalogItemIds(); - return catalogItemHierarchy; + public List getCatalogItemIdSearchPath() { + return searchPath; } @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java index a4a7ecc963..9e7d5da811 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java @@ -56,8 +56,8 @@ public Builder planeId(String planeId) { public Builder brooklynVersion(String val) { brooklynVersion = val; return this; } - public Builder entity(String id, String type, String parent, List catalogItemIds) { - entityIdToManifest.put(id, new EntityMementoManifestImpl(id, type, parent, catalogItemIds)); + public Builder entity(String id, String type, String parent, String catalogItemId, List searchPath) { + entityIdToManifest.put(id, new EntityMementoManifestImpl(id, type, parent, catalogItemId, searchPath)); return this; } public Builder location(String id, String type) { diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java index 28c2a7e13f..439db61dc7 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/EntityMementoManifestImpl.java @@ -19,7 +19,7 @@ package org.apache.brooklyn.core.mgmt.rebind.dto; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; + import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoManifest.EntityMementoManifest; import java.util.List; @@ -28,13 +28,15 @@ public class EntityMementoManifestImpl implements EntityMementoManifest { private String id; private String type; private String parentId; - private List catalogItemIds; + private String catalogItemId; + private List searchPath; - public EntityMementoManifestImpl(String id, String type, String parentId, List catalogItemIds) { + public EntityMementoManifestImpl(String id, String type, String parentId, String catalogItemId, List searchPath) { this.id = id; this.type = type; this.parentId = parentId; - this.catalogItemIds = ImmutableList.copyOf(catalogItemIds); + this.catalogItemId = catalogItemId; + this.searchPath = ImmutableList.copyOf(searchPath); } @Override @@ -52,18 +54,14 @@ public String getParent() { return parentId; } - /** - * @deprecated since 0.11.0, use {@link #getCatalogItemHierarchy()} instead - */ - @Deprecated @Override public String getCatalogItemId() { - return Iterables.getFirst(catalogItemIds, null); + return catalogItemId; } @Override - public List getCatalogItemHierarchy() { - return catalogItemIds; + public List getCatalogItemIdSearchPath() { + return searchPath; } } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java index 06f567c9ec..c998de7136 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java @@ -451,7 +451,8 @@ private static void populateBrooklynObjectMementoBuilder(BrooklynObject instance builder.id = instance.getId(); builder.displayName = instance.getDisplayName(); - builder.catalogItemHierarchy = instance.getCatalogItemHierarchy(); + builder.catalogItemId = instance.getCatalogItemId(); + builder.searchPath = instance.getCatalogItemIdSearchPath(); builder.type = (typePrefix.isPresent() ? typePrefix.get() : "") + instance.getClass().getName(); builder.typeClass = instance.getClass(); if (instance instanceof EntityAdjunct) { 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 ece0cdfd32..a79318374e 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 @@ -102,7 +102,8 @@ protected Builder xsltTransformerRecursiveCopyWithExtraRules(String ...rules) { return xsltTransformer(xslt); } - /** Discards and replaces the item at the given XPath. + /** + * Discards and replaces the item at the given XPath. *

* For example to replace all occurrences * of text "foo" inside a tag "Tag1", you can use TagName/text()[.='foo']; @@ -119,7 +120,15 @@ public Builder xmlReplaceItem(String xpathToMatch, String newValue) { + newValue + ""); } - + + /** + * Discards the item at the given XPath. + */ + public Builder xmlDeleteItem(String xpathToMatch) { + return xsltTransformerRecursiveCopyWithExtraRules( + ""); + } + /** * Replaces a tag, but while continuing to recurse. */ @@ -182,12 +191,12 @@ public Builder renameField(String clazz, String oldVal, String newVal) { * old text matches oldSymbolicName and optionally oldVersion * to have newSymbolicName and newVersion. *

- * Also changes contents of elements within a list of 'catalogItemHierarchy' e.g. + * Also changes contents of elements within a list of 'catalogItemIdSearchPath' e.g. *

-         *     <catalogItemHierarchy>
+         *     <catalogItemIdSearchPath>
          *        <string>one</string>
          *        <string>two</string>
-         *     </catalogItemHierarchy>
+         *     </catalogItemIdSearchPath>
          * 
*

* This provides a programmatic way to change the catalogItemID. */ @@ -196,13 +205,13 @@ public Builder changeCatalogItemId(String oldSymbolicName, String oldVersion, if (oldVersion==null) return changeCatalogItemId(oldSymbolicName, newSymbolicName, newVersion); // warnings use underscore notation because that's what CompoundTransformerLoader uses - return xmlReplaceItem("*[self::catalogItemId|parent::catalogItemHierarchy]/text()[.='"+ + return xmlReplaceItem("*[self::catalogItemId|parent::catalogItemIdSearchPath]/text()[.='"+ Preconditions.checkNotNull(oldSymbolicName, "old_symbolic_name")+":"+Preconditions.checkNotNull(oldVersion, "old_version")+"']", Preconditions.checkNotNull(newSymbolicName, "new_symbolic_name")+":"+Preconditions.checkNotNull(newVersion, "new_version")); } /** As {@link #changeCatalogItemId(String, String, String, String)} matching any old version. */ public Builder changeCatalogItemId(String oldSymbolicName, String newSymbolicName, String newVersion) { - return xmlReplaceItem("*[self::catalogItemId|parent::catalogItemHierarchy]/text()[starts-with(.,'"+Preconditions.checkNotNull(oldSymbolicName, "old_symbolic_name")+":')]", + return xmlReplaceItem("*[self::catalogItemId|parent::catalogItemIdSearchPath]/text()[starts-with(.,'"+Preconditions.checkNotNull(oldSymbolicName, "old_symbolic_name")+":')]", Preconditions.checkNotNull(newSymbolicName, "new_symbolic_name")+":"+Preconditions.checkNotNull(newVersion, "new_version")); } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java index 9ba131c5cb..cadeab84ff 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java @@ -26,6 +26,7 @@ import java.util.Set; import com.google.common.collect.ImmutableList; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,7 +63,8 @@ public abstract class AbstractBrooklynObject implements BrooklynObjectInternal { @SetFromFlag("id") private String id = Identifiers.makeRandomLowercaseId(10); - private Deque catalogItemIdStack = new ArrayDeque<>(); + private String catalogItemId; + private Deque searchPath = new ArrayDeque<>(); /** callers (only in TagSupport) should synchronize on this for all access */ @SetFromFlag("tags") @@ -100,6 +102,13 @@ public AbstractBrooklynObject(Map properties) { // rely on sub-class to call configure(properties), because otherwise its fields will not have been initialised } + protected Object readResolve() { + if (searchPath == null) { + searchPath = new ArrayDeque<>(); + } + return this; + } + /** * See {@link #configure(Map)} * @@ -202,33 +211,32 @@ public String getId() { @Override public void setCatalogItemId(String id) { - catalogItemIdStack.clear(); - nestCatalogItemId(id); + catalogItemId = id; } @Override - public void setCatalogItemIdHierarchy(List ids) { - catalogItemIdStack.clear(); - catalogItemIdStack.addAll(ids); + public void setCatalogItemIdSearchPath(List ids) { + searchPath.clear(); + searchPath.addAll(ids); } - @Override - public void nestCatalogItemId(String id) { + @Override + public void stackCatalogItemId(String id) { if (null != id) { - catalogItemIdStack.addFirst(id); + if (null != catalogItemId && !catalogItemId.equals(id)) { + searchPath.addFirst(catalogItemId); + } + setCatalogItemId(id); } } - public List getCatalogItemHierarchy() { - return ImmutableList.copyOf(catalogItemIdStack); + public List getCatalogItemIdSearchPath() { + return ImmutableList.copyOf(searchPath); } @Override public String getCatalogItemId() { - if (catalogItemIdStack.size() != 0) { - return catalogItemIdStack.getFirst(); - } - return null; + return catalogItemId; } protected void onTagsChanged() { diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java index 260c210219..ea0287767b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java @@ -379,7 +379,8 @@ public void setEntity(EntityLocal entity) { this.entity = entity; this.execution = ((EntityInternal) entity).getExecutionContext(); if (entity!=null && getCatalogItemId() == null) { - setCatalogItemIdHierarchy(entity.getCatalogItemHierarchy()); + setCatalogItemId(entity.getCatalogItemId()); + setCatalogItemIdSearchPath(entity.getCatalogItemIdSearchPath()); } } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java index 4c05ed6116..6cec5ab673 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java @@ -38,9 +38,13 @@ public interface BrooklynObjectInternal extends BrooklynObject, Rebindable { void setCatalogItemId(String id); - void setCatalogItemIdHierarchy(List id); + void setCatalogItemIdSearchPath(List id); - void nestCatalogItemId(String id); + /** + * Moves the current catalog item id onto the start of the search path, + * then sets the catalog item id to the supplied value. + */ + void stackCatalogItemId(String id); // subclasses typically apply stronger typing @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java index a80d12a9fe..6d32aa8ff5 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java @@ -243,17 +243,19 @@ protected T createEntityAndDescendantsUninitialized(EntitySpe @SuppressWarnings({ "unchecked", "rawtypes" }) protected T loadUnitializedEntity(final T entity, final EntitySpec spec) { try { + final AbstractEntity theEntity = (AbstractEntity) entity; if (spec.getDisplayName()!=null) - ((AbstractEntity)entity).setDisplayName(spec.getDisplayName()); + theEntity.setDisplayName(spec.getDisplayName()); - if (spec.getOuterCatalogItemId()!=null) { - ((AbstractEntity)entity).setCatalogItemIdHierarchy(spec.getCatalogItemIdHierarchy()); + if (spec.getCatalogItemId()!=null) { + theEntity.setCatalogItemId(spec.getCatalogItemId()); + theEntity.setCatalogItemIdSearchPath(spec.getCatalogItemIdSearchPath()); } entity.tags().addTags(spec.getTags()); - addSpecParameters(spec, ((AbstractEntity)entity).getMutableEntityType()); + addSpecParameters(spec, theEntity.getMutableEntityType()); - ((AbstractEntity)entity).configure(MutableMap.copyOf(spec.getFlags())); + theEntity.configure(MutableMap.copyOf(spec.getFlags())); for (Map.Entry, Object> entry : spec.getConfig().entrySet()) { entity.config().set((ConfigKey)entry.getKey(), entry.getValue()); } @@ -280,7 +282,7 @@ private void addSpecParameters(EntitySpec spec, EntityDynamicType edType) { // except what is being added programmatically. // (this logic could get confused if catalog item ID referred to some runtime-inherited context, // but those semantics should no longer be used -- https://issues.apache.org/jira/browse/BROOKLYN-445) - if (Strings.isNonBlank(spec.getOuterCatalogItemId())) { + if (Strings.isNonBlank(spec.getCatalogItemId())) { edType.clearConfigKeys(); } for (SpecParameter param : spec.getParameters()) { diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java index de6a0bd678..ad0d0dba4f 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java @@ -114,27 +114,29 @@ public T createLocation(LocationSpec spec) { managementContext.prePreManage(loc); + final AbstractLocation location = (AbstractLocation) loc; if (spec.getDisplayName()!=null) - ((AbstractLocation)loc).setDisplayName(spec.getDisplayName()); + location.setDisplayName(spec.getDisplayName()); - if (spec.getOuterCatalogItemId()!=null) { - ((AbstractLocation)loc).setCatalogItemIdHierarchy(spec.getCatalogItemIdHierarchy()); + if (spec.getCatalogItemId()!=null) { + location.setCatalogItemId(spec.getCatalogItemId()); + location.setCatalogItemIdSearchPath(spec.getCatalogItemIdSearchPath()); } loc.tags().addTags(spec.getTags()); if (isNewStyle(clazz)) { - ((AbstractLocation)loc).setManagementContext(managementContext); - ((AbstractLocation)loc).configure(ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig()); + location.setManagementContext(managementContext); + location.configure(ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig()); } for (Map.Entry, Object> entry : spec.getConfig().entrySet()) { - ((AbstractLocation)loc).config().set((ConfigKey)entry.getKey(), entry.getValue()); + location.config().set((ConfigKey)entry.getKey(), entry.getValue()); } for (Entry, Object> entry : spec.getExtensions().entrySet()) { ((LocationInternal)loc).addExtension((Class)entry.getKey(), entry.getValue()); } - ((AbstractLocation)loc).init(); + location.init(); Location parent = spec.getParent(); if (parent != null) { diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java index 776cfef2d8..4de113c408 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java @@ -103,19 +103,21 @@ public T createPolicy(PolicySpec spec) { T pol = construct(clazz, spec, null); + final AbstractPolicy policy = (AbstractPolicy) pol; if (spec.getDisplayName()!=null) { - ((AbstractPolicy)pol).setDisplayName(spec.getDisplayName()); + policy.setDisplayName(spec.getDisplayName()); } - if (spec.getOuterCatalogItemId()!=null) { - ((AbstractPolicy)pol).setCatalogItemIdHierarchy(spec.getCatalogItemIdHierarchy()); + if (spec.getCatalogItemId()!=null) { + policy.setCatalogItemId(spec.getCatalogItemId()); + policy.setCatalogItemIdSearchPath(spec.getCatalogItemIdSearchPath()); } pol.tags().addTags(spec.getTags()); if (isNewStyle(clazz)) { - ((AbstractPolicy)pol).setManagementContext(managementContext); + policy.setManagementContext(managementContext); Map config = ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig(); - ((AbstractPolicy)pol).configure(MutableMap.copyOf(config)); // TODO AbstractPolicy.configure modifies the map + policy.configure(MutableMap.copyOf(config)); // TODO AbstractPolicy.configure modifies the map } // TODO Can we avoid this for "new-style policies"? Should we just trust the configure() method, @@ -124,7 +126,7 @@ public T createPolicy(PolicySpec spec) { for (Map.Entry, Object> entry : spec.getConfig().entrySet()) { pol.config().set((ConfigKey)entry.getKey(), entry.getValue()); } - ((AbstractPolicy)pol).init(); + policy.init(); return pol; @@ -143,20 +145,22 @@ public T createEnricher(EnricherSpec spec) { Class clazz = spec.getType(); T enricher = construct(clazz, spec, null); - + + final AbstractEnricher theEnricher = (AbstractEnricher) enricher; if (spec.getDisplayName()!=null) - ((AbstractEnricher)enricher).setDisplayName(spec.getDisplayName()); + theEnricher.setDisplayName(spec.getDisplayName()); - if (spec.getOuterCatalogItemId()!=null) { - ((AbstractEnricher)enricher).setCatalogItemIdHierarchy(spec.getCatalogItemIdHierarchy()); + if (spec.getCatalogItemId()!=null) { + theEnricher.setCatalogItemId(spec.getCatalogItemId()); + theEnricher.setCatalogItemIdSearchPath(spec.getCatalogItemIdSearchPath()); } enricher.tags().addTags(spec.getTags()); if (isNewStyle(clazz)) { - ((AbstractEnricher)enricher).setManagementContext(managementContext); + theEnricher.setManagementContext(managementContext); Map config = ConfigBag.newInstance().putAll(spec.getFlags()).putAll(spec.getConfig()).getAllConfig(); - ((AbstractEnricher)enricher).configure(MutableMap.copyOf(config)); // TODO AbstractEnricher.configure modifies the map + theEnricher.configure(MutableMap.copyOf(config)); // TODO AbstractEnricher.configure modifies the map } // TODO Can we avoid this for "new-style policies"? Should we just trust the configure() method, @@ -165,7 +169,7 @@ public T createEnricher(EnricherSpec spec) { for (Map.Entry, Object> entry : spec.getConfig().entrySet()) { enricher.config().set((ConfigKey)entry.getKey(), entry.getValue()); } - ((AbstractEnricher)enricher).init(); + theEnricher.init(); return enricher; diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java index 88eb6996b7..b802dfbdf3 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java @@ -27,7 +27,6 @@ import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.mgmt.ManagementContext; -import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.core.BrooklynVersion; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.entity.EntityInternal; @@ -257,7 +256,8 @@ private Maybe loadClass(String name, LoaderDispatcher dispatcher, Stri CatalogItem item = CatalogUtils.getCatalogItemOptionalVersion(mgmt, catalogItemId); if (item != null) { BrooklynClassLoadingContextSequential loader = new BrooklynClassLoadingContextSequential(mgmt); - loader.add(newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemHierarchy())); + loader.add(newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemId(), + item.getCatalogItemIdSearchPath())); cls = dispatcher.tryLoadFrom(loader, className); if (cls.isPresent()) { return cls; 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 index b340d2ae7e..97faeec5ef 100644 --- 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 @@ -117,9 +117,8 @@ public void testReadConfigInheritance_2016_11() throws Exception { checkNewAppNonInheritingKey1(rebindedApp); String origMementoTidied = origMemento.substring(origMemento.indexOf("")); - origMementoTidied = origMementoTidied.replaceFirst("", "\n "); origMementoTidied = Strings.replaceAllNonRegex(origMementoTidied, "VERSION", BrooklynVersion.get()); - Asserts.assertEquals(origMementoTidied, newMemento); + Asserts.assertEquals(origMementoTidied, newMemento.replaceAll("\n.*searchPath.*\n", "\n")); } @Test diff --git a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java index a9686d5f72..ce0470da94 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java @@ -325,7 +325,9 @@ protected Entity createSimpleEntity(String bundleUrl, Class clazz) { .plan("{\"services\":[{\"type\": \"" + clazz.getName() + "\"}]}") .build(); mgmt.getCatalog().addItem(item); - ((EntityInternal)entity).setCatalogItemIdHierarchy(item.getCatalogItemHierarchy()); + final EntityInternal entityInternal = (EntityInternal) entity; + entityInternal.setCatalogItemId(item.getCatalogItemId()); + entityInternal.setCatalogItemIdSearchPath(item.getCatalogItemIdSearchPath()); return entity; } diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java index 2ad36080ec..c612c6f409 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java @@ -83,7 +83,7 @@ private static LocationSummary newInstance(ManagementContext mgmt, } } - String id = Strings.isNonBlank(optionalExplicitId) ? optionalExplicitId : spec!=null && Strings.isNonBlank(spec.getOuterCatalogItemId()) ? spec.getOuterCatalogItemId() : null; + String id = Strings.isNonBlank(optionalExplicitId) ? optionalExplicitId : spec!=null && Strings.isNonBlank(spec.getCatalogItemId()) ? spec.getCatalogItemId() : null; URI selfUri = serviceUriBuilder(ub, LocationApi.class, "get").build(id); CatalogLocationSummary catalogSummary = null; @@ -100,7 +100,7 @@ private static LocationSummary newInstance(ManagementContext mgmt, return new LocationSummary( id, Strings.isNonBlank(name) ? name : spec!=null ? spec.getDisplayName() : null, - Strings.isNonBlank(specString) ? specString : spec!=null ? spec.getOuterCatalogItemId() : null, + Strings.isNonBlank(specString) ? specString : spec!=null ? spec.getCatalogItemId() : null, null, copyConfig(config, level), catalogSummary, From 51b0b754e0640a6403b11359ecb4467d052c505a Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Sat, 18 Mar 2017 20:04:43 +0000 Subject: [PATCH 30/35] Correct testRebindWithCatalogAndAppRebindCatalogItemIds --- .../camp/brooklyn/catalog/CatalogYamlRebindTest.java | 3 ++- .../core/mgmt/rebind/dto/AbstractMemento.java | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) 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 874e3018c6..8daf21c35a 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 @@ -176,7 +176,8 @@ public void testRebindWithCatalogAndApp(RebindWithCatalogTestMode mode, OsgiMode public void testRebindWithCatalogAndAppRebindCatalogItemIds(RebindWithCatalogTestMode mode, OsgiMode osgiMode) throws Exception { final RebindOptions rebindOptions = RebindOptions.create(); applyCompoundStateTransformer(rebindOptions, CompoundTransformer.builder() - .xmlDeleteItem("//catalogItemIdSearchPath") + .xmlDeleteItem("//searchPath") // delete searchPath element + .xmlDeleteItem("//@*[contains(., 'searchPath')]") // delete any attributes that reference searchPath .build()); testRebindWithCatalogAndAppUsingOptions(mode, osgiMode, rebindOptions); } 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 6e2a0f2f7d..c5e9c9c15b 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 @@ -94,7 +94,7 @@ public B customFields(Map vals) { private String id; private String displayName; protected String catalogItemId; - private List searchPath; + private List searchPath = Lists.newArrayList(); private List tags; private Map> relations; @@ -107,7 +107,14 @@ public B customFields(Map vals) { protected AbstractMemento() { } - // Trusts the builder to not mess around with mutability after calling build() + protected AbstractMemento readResolve() { + if (searchPath == null) { + searchPath = Lists.newArrayList(); + } + return this; + } + + // Trusts the builder to not mess around with mutability after calling build() protected AbstractMemento(Builder builder) { brooklynVersion = builder.brooklynVersion; id = builder.id; From b4e56a59c2c9811b8358ea8c4de4dc0a98567c1e Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Sat, 18 Mar 2017 20:46:34 +0000 Subject: [PATCH 31/35] XPathHelper.getStringList fix and formatting, hashcode/equals fixes. --- .../internal/AbstractBrooklynObjectSpec.java | 14 +- .../catalog/CatalogOsgiYamlEntityTest.java | 145 +++++++++--------- .../catalog/CatalogYamlEntityTest.java | 6 +- .../catalog/CatalogYamlRebindTest.java | 17 -- .../internal/CatalogItemDtoAbstract.java | 4 +- ...BrooklynMementoPersisterToObjectStore.java | 2 +- 6 files changed, 85 insertions(+), 103 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java index 10acfe40e1..12a8e73fab 100644 --- a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java +++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java @@ -90,9 +90,9 @@ protected SpecT self() { @Override public String toString() { return MoreObjects.toStringHelper(this).omitNullValues() - .add("type", type) - .add("displayName", displayName) - .toString(); + .add("type", type) + .add("displayName", displayName) + .toString(); } protected abstract void checkValidType(Class type); @@ -223,9 +223,9 @@ public SpecT parametersAdd(Iterable> parameters) { current.removeAll(params); return parametersReplace(ImmutableList.>builder() - .addAll(params) - .addAll(current) - .build()); + .addAll(params) + .addAll(current) + .build()); } /** @@ -328,7 +328,7 @@ protected SpecT copyFrom(SpecT otherSpec) { public boolean equals(Object obj) { if (obj == null) return false; if (!obj.getClass().equals(getClass())) return false; - AbstractBrooklynObjectSpec other = (AbstractBrooklynObjectSpec) obj; + AbstractBrooklynObjectSpec other = (AbstractBrooklynObjectSpec) obj; if (!Objects.equal(getDisplayName(), other.getDisplayName())) return false; if (!Objects.equal(getCatalogItemId(), other.getCatalogItemId())) return false; if (!Objects.equal(getCatalogItemIdSearchPath(), other.getCatalogItemIdSearchPath())) return false; diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java index b0bf747fd4..7b726bc6e7 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java @@ -46,6 +46,7 @@ import org.testng.annotations.Test; import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; public class CatalogOsgiYamlEntityTest extends AbstractYamlTest { @@ -745,81 +746,77 @@ public void testIndirectCatalogItemCanLoadResources() throws Exception { deleteCatalogEntity(symbolicNameOuter); } + @Test + public void testCatalogItemIdInReferencedItems() throws Exception { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); + + String symbolicNameInner = "my.catalog.app.id.inner"; + String symbolicNameOuter = "my.catalog.app.id.outer"; + addCatalogItems( + "brooklyn.catalog:", + " version: " + TEST_VERSION, + " items:", + " - id: " + symbolicNameInner, + " name: My Catalog App", + " description: My description", + " icon_url: classpath://path/to/myicon.jpg", + " brooklyn.libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, + " item: " + SIMPLE_ENTITY_TYPE, + " - id: " + symbolicNameOuter, + " item: " + symbolicNameInner); + + String yaml = "name: " + symbolicNameOuter + "\n" + + "services: \n" + + " - serviceType: " + ver(symbolicNameOuter); + + Entity app = createAndStartApplication(yaml); + Entity entity = app.getChildren().iterator().next(); + assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); + assertEquals(entity.getCatalogItemIdSearchPath(), ImmutableList.of(ver(symbolicNameInner)), + "should have just " + symbolicNameInner + " in search path"); + + deleteCatalogEntity(symbolicNameInner); + deleteCatalogEntity(symbolicNameOuter); + } + @Test + public void testDeepCatalogItemCanLoadResources() throws Exception { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH); + + String symbolicNameInner = "my.catalog.app.id.inner"; + String symbolicNameFiller = "my.catalog.app.id.filler"; + String symbolicNameOuter = "my.catalog.app.id.outer"; + addCatalogItems( + "brooklyn.catalog:", + " version: " + TEST_VERSION, + " items:", + " - id: " + symbolicNameInner, + " name: My Catalog App", + " brooklyn.libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, + " item: " + SIMPLE_ENTITY_TYPE, + " - id: " + symbolicNameFiller, + " name: Filler App", + " brooklyn.libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_URL, + " item: " + symbolicNameInner, + " - id: " + symbolicNameOuter, + " item: " + symbolicNameFiller); + + String yaml = "name: " + symbolicNameOuter + "\n" + + "services: \n" + + " - serviceType: "+ver(symbolicNameOuter); + Entity app = createAndStartApplication(yaml); + Entity entity = app.getChildren().iterator().next(); + + final String catalogBom = ResourceUtils.create(entity).getResourceAsString("classpath://" + MORE_ENTITIES_POM_PROPERTIES_PATH); + assertTrue(catalogBom.contains("artifactId=brooklyn-test-osgi-more-entities")); - @Test - public void testDeepCatalogItemCanLoadResources() throws Exception { - TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); - TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_PATH); - - String symbolicNameInner = "my.catalog.app.id.inner"; - String symbolicNameFiller = "my.catalog.app.id.filler"; - String symbolicNameOuter = "my.catalog.app.id.outer"; - addCatalogItems( - "brooklyn.catalog:", - " version: " + TEST_VERSION, - " items:", - " - id: " + symbolicNameInner, - " name: My Catalog App", - " brooklyn.libraries:", - " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, - " item: " + SIMPLE_ENTITY_TYPE, - " - id: " + symbolicNameFiller, - " name: Filler App", - " brooklyn.libraries:", - " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_MORE_ENTITIES_0_1_0_URL, - " item: " + symbolicNameInner, - " - id: " + symbolicNameOuter, - " item: " + symbolicNameFiller); - - String yaml = "name: " + symbolicNameOuter + "\n" + - "services: \n" + - " - serviceType: "+ver(symbolicNameOuter); - Entity app = createAndStartApplication(yaml); - Entity entity = app.getChildren().iterator().next(); - - final String catalogBom = ResourceUtils.create(entity).getResourceAsString("classpath://" + MORE_ENTITIES_POM_PROPERTIES_PATH); - assertTrue(catalogBom.contains("artifactId=brooklyn-test-osgi-more-entities")); - - deleteCatalogEntity(symbolicNameOuter); - deleteCatalogEntity(symbolicNameFiller); - deleteCatalogEntity(symbolicNameInner); - } - - @Test - public void testCatalogItemIdInReferencedItems() throws Exception { - TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); - - String symbolicNameInner = "my.catalog.app.id.inner"; - String symbolicNameOuter = "my.catalog.app.id.outer"; - addCatalogItems( - "brooklyn.catalog:", - " version: " + TEST_VERSION, - " items:", - " - id: " + symbolicNameInner, - " name: My Catalog App", - " description: My description", - " icon_url: classpath://path/to/myicon.jpg", - " brooklyn.libraries:", - " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, - " item: " + SIMPLE_ENTITY_TYPE, - " - id: " + symbolicNameOuter, - " item: " + symbolicNameInner); - - String yaml = "name: " + symbolicNameOuter + "\n" + - "services: \n" + - " - serviceType: "+ver(symbolicNameOuter); - - Entity app = createAndStartApplication(yaml); - - Entity entity = app.getChildren().iterator().next(); - assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); - assertEquals(entity.getCatalogItemIdSearchPath().size(), 1, "should have exactly one item in search path"); - assertEquals(entity.getCatalogItemIdSearchPath().get(0), ver(symbolicNameInner), - "should have " + symbolicNameInner + " in search path"); - - deleteCatalogEntity(symbolicNameInner); - deleteCatalogEntity(symbolicNameOuter); - } + deleteCatalogEntity(symbolicNameOuter); + deleteCatalogEntity(symbolicNameFiller); + deleteCatalogEntity(symbolicNameInner); + } private void registerAndLaunchAndAssertSimpleEntity(String symbolicName, String serviceType) throws Exception { addCatalogOSGiEntity(symbolicName, serviceType); diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java index b3264f7301..847e4619ed 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java @@ -45,6 +45,7 @@ import org.testng.annotations.Test; import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; @@ -643,9 +644,8 @@ public void testCatalogItemIdInReferencedItems() throws Exception { Entity entity = app.getChildren().iterator().next(); assertEquals(entity.getCatalogItemId(), ver(symbolicNameOuter)); - assertEquals(entity.getCatalogItemIdSearchPath().size(), 1, "should have exactly one item in search path"); - assertEquals(entity.getCatalogItemIdSearchPath().get(0), ver(symbolicNameInner), - "should have " + symbolicNameInner + " in search path"); + assertEquals(entity.getCatalogItemIdSearchPath(), ImmutableList.of(ver(symbolicNameInner)), + "should have just " + symbolicNameInner + " in search path"); deleteCatalogEntity(symbolicNameInner); deleteCatalogEntity(symbolicNameOuter); 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 8daf21c35a..c4af503476 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 @@ -25,24 +25,13 @@ import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; -import java.io.StringReader; -import java.io.StringWriter; import java.util.List; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -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; import org.apache.brooklyn.camp.brooklyn.AbstractYamlRebindTest; import org.apache.brooklyn.core.BrooklynFeatureEnablement; @@ -68,16 +57,10 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; public class CatalogYamlRebindTest extends AbstractYamlRebindTest { diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java index 0bae32d566..5aec768626 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java @@ -191,7 +191,8 @@ public String getPlanYaml() { @Override public int hashCode() { - return Objects.hashCode(symbolicName, planYaml, javaType, nullIfEmpty(libraries), version, getCatalogItemId()); + return Objects.hashCode(symbolicName, planYaml, javaType, nullIfEmpty(libraries), version, getCatalogItemId(), + getCatalogItemIdSearchPath()); } @Override @@ -205,6 +206,7 @@ public boolean equals(Object obj) { if (!Objects.equal(javaType, other.javaType)) return false; if (!Objects.equal(nullIfEmpty(libraries), nullIfEmpty(other.libraries))) return false; if (!Objects.equal(getCatalogItemId(), other.getCatalogItemId())) return false; + if (!Objects.equal(getCatalogItemIdSearchPath(), other.getCatalogItemIdSearchPath())) return false; if (!Objects.equal(version, other.version)) return false; if (!Objects.equal(deprecated, other.deprecated)) return false; if (!Objects.equal(description, other.description)) return false; diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java index 5aace6d7c1..2e0b8bf1da 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java @@ -350,7 +350,7 @@ private String get(String innerPath) { private List getStringList(String innerPath) { List result = MutableList.of(); final NodeList nodeList = - (NodeList) XmlUtil.xpathHandlingIllegalChars(contents, prefix + innerPath + "/string", XPathConstants.NODESET); + (NodeList) XmlUtil.xpathHandlingIllegalChars(contents, prefix + innerPath + "//string", XPathConstants.NODESET); for(int c = 0 ; c < nodeList.getLength() ; c++) { result.add(nodeList.item(c).getFirstChild().getNodeValue()); } From 63beadae3ae7cfd42afca7352d4700b324c54a50 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 21 Mar 2017 12:04:59 +0000 Subject: [PATCH 32/35] Add searchPath to Entities.dumpInfo. --- .../java/org/apache/brooklyn/core/entity/Entities.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java index 3f1857ffb2..acad9d268a 100644 --- a/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java +++ b/core/src/main/java/org/apache/brooklyn/core/entity/Entities.java @@ -329,6 +329,15 @@ public static void dumpInfo(Entity e, Writer out, String currentIndentation, Str if (Strings.isNonBlank(e.getCatalogItemId())) { out.append(currentIndentation+tab+tab+"catalogItemId = "+e.getCatalogItemId()+"\n"); } + final List searchPath = e.getCatalogItemIdSearchPath(); + if (!searchPath.isEmpty()) { + out.append(currentIndentation + tab + tab + "searchPath = ["); + for (int i = 0 ; i < searchPath.size() ; i++) { + out.append(i > 0 ? ",\n" : "\n"); + out.append(currentIndentation + tab + tab + searchPath.get(i)); + } + out.append("\n" + currentIndentation + tab + tab + "]"); + } out.append(currentIndentation+tab+tab+"locations = "+e.getLocations()+"\n"); From 9b176a3c6e7bc21d7299cd191d5c3701f9d3d910 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 21 Mar 2017 12:05:52 +0000 Subject: [PATCH 33/35] Set searchPath in JavaCatalogToSpecTransformer. --- .../core/catalog/internal/JavaCatalogToSpecTransformer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java index f9c413106a..e8bb23b4b8 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java @@ -103,7 +103,7 @@ public > SpecT c } else { throw new IllegalStateException("Catalog item " + item + " java type " + javaType + " is not a Brooklyn supported object."); } - spec.catalogItemId(item.getCatalogItemId()); + spec.catalogItemIdAndSearchPath(item.getCatalogItemId(), item.getCatalogItemIdSearchPath()); @SuppressWarnings("unchecked") SpecT untypedSpc = (SpecT) spec; return untypedSpc; From db2e23ff74b08d4ebd4f54a30003f0c0a99248db Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 21 Mar 2017 12:06:51 +0000 Subject: [PATCH 34/35] Update comments on catalogItemId(). --- .../brooklyn/api/internal/AbstractBrooklynObjectSpec.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java index 12a8e73fab..d88078ae68 100644 --- a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java +++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java @@ -103,17 +103,19 @@ public SpecT displayName(String val) { } /** - * Set the catalog item ID that defined this object, also used for searching for type and resources referenced + * Set the catalog item ID that defined this object; * since https://issues.apache.org/jira/browse/BROOKLYN-445 this must no longer be used to indicate * a caller-context catalog item that should be used for search purposes; - * if that behaviour is desired, the child should be refactored to be its own item in the catalog BOM - * (or TODO we add a separate field to record other catalog item IDs that could be applied for searching, see below) + * instead use {@link #catalogItemIdAndSearchPath}. */ public SpecT catalogItemId(String val) { catalogItemId = val; return self(); } + /** + * Set the immediate catalog item ID of this object, and the search path of other catalog items used to define it. + */ public synchronized SpecT catalogItemIdAndSearchPath(String catalogItemId, Collection searchPath) { if (catalogItemId != null) { catalogItemId(catalogItemId); From fde6aa5f5aa85e50496db3a3662ad2068dfd74a5 Mon Sep 17 00:00:00 2001 From: Geoff Macartney Date: Tue, 21 Mar 2017 12:18:56 +0000 Subject: [PATCH 35/35] Do setCatalogItemIdAndSearchPath instead of just set search path. --- .../brooklyn/core/catalog/internal/CatalogItemDo.java | 4 ++-- .../brooklyn/core/catalog/internal/CatalogUtils.java | 3 +-- .../brooklyn/core/mgmt/rebind/RebindIteration.java | 3 +-- .../brooklyn/core/objs/AbstractBrooklynObject.java | 10 ++-------- .../brooklyn/core/objs/AbstractEntityAdjunct.java | 3 +-- .../brooklyn/core/objs/BrooklynObjectInternal.java | 2 +- .../core/objs/proxy/InternalEntityFactory.java | 3 +-- .../core/objs/proxy/InternalLocationFactory.java | 3 +-- .../core/objs/proxy/InternalPolicyFactory.java | 6 ++---- .../brooklyn/util/core/ClassLoaderUtilsTest.java | 3 +-- 10 files changed, 13 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java index 36e1192142..0738d7618e 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDo.java @@ -132,8 +132,8 @@ public void setCatalogItemId(String id) { } @Override - public void setCatalogItemIdSearchPath(List ids) { - itemDto.setCatalogItemIdSearchPath(ids); + public void setCatalogItemIdAndSearchPath(String catalogItemId, List ids) { + itemDto.setCatalogItemIdAndSearchPath(catalogItemId, ids); } @Override diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java index 2f85db977e..776894f5fa 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java @@ -196,8 +196,7 @@ public static void setCatalogItemIdOnAddition(Entity entity, BrooklynObject item BrooklynLogging.log(log, BrooklynLogging.levelDebugOrTraceIfReadOnly(entity), "Catalog item addition: "+entity+" from "+entity.getCatalogItemId()+" applying its catalog item ID to "+itemBeingAdded); final BrooklynObjectInternal addInternal = (BrooklynObjectInternal) itemBeingAdded; - addInternal.setCatalogItemId(entity.getCatalogItemId()); - addInternal.setCatalogItemIdSearchPath(entity.getCatalogItemIdSearchPath()); + addInternal.setCatalogItemIdAndSearchPath(entity.getCatalogItemId(), entity.getCatalogItemIdSearchPath()); } else { if (!itemBeingAdded.getCatalogItemId().equals(entity.getCatalogItemId())) { // not a problem, but something to watch out for diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java index a12bd7eb1a..e4fbaa6c30 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java @@ -971,8 +971,7 @@ protected Entity newEntity(EntityMementoManifest entityManifest) { protected void setCatalogItemIds(BrooklynObject object, String catalogItemId, List searchPath) { final BrooklynObjectInternal internal = (BrooklynObjectInternal) object; - internal.setCatalogItemId(catalogItemId); - internal.setCatalogItemIdSearchPath(searchPath); + internal.setCatalogItemIdAndSearchPath(catalogItemId, searchPath); } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java index cadeab84ff..9a409ca656 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractBrooklynObject.java @@ -45,13 +45,6 @@ import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.core.flags.SetFromFlag; import org.apache.brooklyn.util.text.Identifiers; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; public abstract class AbstractBrooklynObject implements BrooklynObjectInternal { @@ -215,7 +208,8 @@ public void setCatalogItemId(String id) { } @Override - public void setCatalogItemIdSearchPath(List ids) { + public void setCatalogItemIdAndSearchPath(String catalogItemId, List ids) { + setCatalogItemId(catalogItemId); searchPath.clear(); searchPath.addAll(ids); } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java index ea0287767b..69e51e6e13 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java @@ -379,8 +379,7 @@ public void setEntity(EntityLocal entity) { this.entity = entity; this.execution = ((EntityInternal) entity).getExecutionContext(); if (entity!=null && getCatalogItemId() == null) { - setCatalogItemId(entity.getCatalogItemId()); - setCatalogItemIdSearchPath(entity.getCatalogItemIdSearchPath()); + setCatalogItemIdAndSearchPath(entity.getCatalogItemId(), entity.getCatalogItemIdSearchPath()); } } diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java index 6cec5ab673..d7fe17be7d 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynObjectInternal.java @@ -38,7 +38,7 @@ public interface BrooklynObjectInternal extends BrooklynObject, Rebindable { void setCatalogItemId(String id); - void setCatalogItemIdSearchPath(List id); + void setCatalogItemIdAndSearchPath(String catalogItemId, List searchPath); /** * Moves the current catalog item id onto the start of the search path, diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java index 6d32aa8ff5..0cf933ce62 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalEntityFactory.java @@ -248,8 +248,7 @@ protected T loadUnitializedEntity(final T entity, final Entit theEntity.setDisplayName(spec.getDisplayName()); if (spec.getCatalogItemId()!=null) { - theEntity.setCatalogItemId(spec.getCatalogItemId()); - theEntity.setCatalogItemIdSearchPath(spec.getCatalogItemIdSearchPath()); + theEntity.setCatalogItemIdAndSearchPath(spec.getCatalogItemId(), spec.getCatalogItemIdSearchPath()); } entity.tags().addTags(spec.getTags()); diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java index ad0d0dba4f..b15863d08d 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalLocationFactory.java @@ -119,8 +119,7 @@ public T createLocation(LocationSpec spec) { location.setDisplayName(spec.getDisplayName()); if (spec.getCatalogItemId()!=null) { - location.setCatalogItemId(spec.getCatalogItemId()); - location.setCatalogItemIdSearchPath(spec.getCatalogItemIdSearchPath()); + location.setCatalogItemIdAndSearchPath(spec.getCatalogItemId(), spec.getCatalogItemIdSearchPath()); } loc.tags().addTags(spec.getTags()); diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java index 4de113c408..8ba7f81544 100644 --- a/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java +++ b/core/src/main/java/org/apache/brooklyn/core/objs/proxy/InternalPolicyFactory.java @@ -108,8 +108,7 @@ public T createPolicy(PolicySpec spec) { policy.setDisplayName(spec.getDisplayName()); } if (spec.getCatalogItemId()!=null) { - policy.setCatalogItemId(spec.getCatalogItemId()); - policy.setCatalogItemIdSearchPath(spec.getCatalogItemIdSearchPath()); + policy.setCatalogItemIdAndSearchPath(spec.getCatalogItemId(), spec.getCatalogItemIdSearchPath()); } pol.tags().addTags(spec.getTags()); @@ -151,8 +150,7 @@ public T createEnricher(EnricherSpec spec) { theEnricher.setDisplayName(spec.getDisplayName()); if (spec.getCatalogItemId()!=null) { - theEnricher.setCatalogItemId(spec.getCatalogItemId()); - theEnricher.setCatalogItemIdSearchPath(spec.getCatalogItemIdSearchPath()); + theEnricher.setCatalogItemIdAndSearchPath(spec.getCatalogItemId(), spec.getCatalogItemIdSearchPath()); } enricher.tags().addTags(spec.getTags()); diff --git a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java index ce0470da94..6310e3b91e 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java @@ -326,8 +326,7 @@ protected Entity createSimpleEntity(String bundleUrl, Class clazz) { .build(); mgmt.getCatalog().addItem(item); final EntityInternal entityInternal = (EntityInternal) entity; - entityInternal.setCatalogItemId(item.getCatalogItemId()); - entityInternal.setCatalogItemIdSearchPath(item.getCatalogItemIdSearchPath()); + entityInternal.setCatalogItemIdAndSearchPath(item.getCatalogItemId(), item.getCatalogItemIdSearchPath()); return entity; }