Repository: incubator-brooklyn Updated Branches: refs/heads/master 015b5cdf5 -> 2aa01c0f9
Add catalog recursion prevention to special flags handling Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/805aae27 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/805aae27 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/805aae27 Branch: refs/heads/master Commit: 805aae27682a02977476ae57249056341ca30917 Parents: 703354d Author: Svetoslav Neykov <[email protected]> Authored: Mon Nov 9 15:09:49 2015 +0200 Committer: Svetoslav Neykov <[email protected]> Committed: Mon Nov 9 16:52:26 2015 +0200 ---------------------------------------------------------------------- .../BrooklynComponentTemplateResolver.java | 21 +++++------ .../brooklyn/catalog/CatalogYamlAppTest.java | 38 +++++++++++++++++++- 2 files changed, 48 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/805aae27/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java index a273c50..db6a78e 100644 --- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java +++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java @@ -65,7 +65,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Function; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; @@ -226,19 +225,19 @@ public class BrooklynComponentTemplateResolver { if (childLocations != null) spec.locations(childLocations); - decorateSpec(spec); + decorateSpec(spec, encounteredRegisteredTypeIds); } - private <T extends Entity> void decorateSpec(EntitySpec<T> spec) { + private <T extends Entity> void decorateSpec(EntitySpec<T> spec, Set<String> encounteredRegisteredTypeIds) { new BrooklynEntityDecorationResolver.PolicySpecResolver(yamlLoader).decorate(spec, attrs); new BrooklynEntityDecorationResolver.EnricherSpecResolver(yamlLoader).decorate(spec, attrs); new BrooklynEntityDecorationResolver.InitializerResolver(yamlLoader).decorate(spec, attrs); - configureEntityConfig(spec); + configureEntityConfig(spec, encounteredRegisteredTypeIds); } @SuppressWarnings({ "unchecked", "rawtypes" }) - private void configureEntityConfig(EntitySpec<?> spec) { + private void configureEntityConfig(EntitySpec<?> spec, Set<String> encounteredRegisteredTypeIds) { // first take *recognised* flags and config keys from the top-level, and put them in the bag (of brooklyn.config) // attrs will contain only brooklyn.xxx properties when coming from BrooklynEntityMatcher. // Any top-level flags will go into "brooklyn.flags". When resolving a spec from $brooklyn:entitySpec @@ -263,12 +262,12 @@ public class BrooklynComponentTemplateResolver { Set<String> keyNamesUsed = new LinkedHashSet<String>(); for (FlagConfigKeyAndValueRecord r: records) { if (r.getFlagMaybeValue().isPresent()) { - Object transformed = new SpecialFlagsTransformer(loader).apply(r.getFlagMaybeValue().get()); + Object transformed = new SpecialFlagsTransformer(loader, encounteredRegisteredTypeIds).apply(r.getFlagMaybeValue().get()); spec.configure(r.getFlagName(), transformed); keyNamesUsed.add(r.getFlagName()); } if (r.getConfigKeyMaybeValue().isPresent()) { - Object transformed = new SpecialFlagsTransformer(loader).apply(r.getConfigKeyMaybeValue().get()); + Object transformed = new SpecialFlagsTransformer(loader, encounteredRegisteredTypeIds).apply(r.getConfigKeyMaybeValue().get()); spec.configure((ConfigKey<Object>)r.getConfigKey(), transformed); keyNamesUsed.add(r.getConfigKey().getName()); } @@ -281,7 +280,7 @@ public class BrooklynComponentTemplateResolver { // we don't let a flag with the same name as a config key override the config key // (that's why we check whether it is used) if (!keyNamesUsed.contains(key)) { - Object transformed = new SpecialFlagsTransformer(loader).apply(bag.getStringKey(key)); + Object transformed = new SpecialFlagsTransformer(loader, encounteredRegisteredTypeIds).apply(bag.getStringKey(key)); spec.configure(ConfigKeys.newConfigKey(Object.class, key.toString()), transformed); } } @@ -313,10 +312,12 @@ public class BrooklynComponentTemplateResolver { * which can be used to find it from mgmt, rather than pass the loader. */ private BrooklynClassLoadingContext loader = null; + private Set<String> encounteredRegisteredTypeIds; - public SpecialFlagsTransformer(BrooklynClassLoadingContext loader) { + public SpecialFlagsTransformer(BrooklynClassLoadingContext loader, Set<String> encounteredRegisteredTypeIds) { this.loader = loader; mgmt = loader.getManagementContext(); + this.encounteredRegisteredTypeIds = encounteredRegisteredTypeIds; } @Override public Object apply(Object input) { @@ -362,7 +363,7 @@ public class BrooklynComponentTemplateResolver { @SuppressWarnings("unchecked") Map<String, Object> resolvedConfig = (Map<String, Object>)transformSpecialFlags(specConfig.getSpecConfiguration()); specConfig.setSpecConfiguration(resolvedConfig); - return Factory.newInstance(getLoader(), specConfig.getSpecConfiguration()).resolveSpec(ImmutableSet.<String>of()); + return Factory.newInstance(getLoader(), specConfig.getSpecConfiguration()).resolveSpec(encounteredRegisteredTypeIds); } if (flag instanceof ManagementContextInjectable) { log.debug("Injecting Brooklyn management context info object: {}", flag); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/805aae27/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlAppTest.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlAppTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlAppTest.java index 30c383d..f4e58be 100644 --- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlAppTest.java +++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlAppTest.java @@ -21,10 +21,18 @@ package org.apache.brooklyn.camp.brooklyn.catalog; import org.testng.annotations.Test; import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest; +import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; +import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; public class CatalogYamlAppTest extends AbstractYamlTest { - + + @Override + protected LocalManagementContext newTestManagementContext() { + // Don't need osgi + return LocalManagementContextForTests.newInstance(); + } + /** * "Contrived" example was encountered by a customer in a real use-case! * I couldn't yet simplify it further while still reproducing the failure. @@ -70,4 +78,32 @@ public class CatalogYamlAppTest extends AbstractYamlTest { deleteCatalogEntity("org.apache.brooklyn.entity.stock.BasicEntity"); } } + + @Test // same as above, but the minimal possible setup + public void testAddCatalogItemWithMemberSpecCircularReference() throws Exception { + // Add a catalog item with a circular reference to its own id through a $brooklyn:entitySpec + addCatalogItems( + "brooklyn.catalog:", + " id: org.apache.brooklyn.entity.stock.BasicApplication", + " version: "+TEST_VERSION, + "services:", + "- type: org.apache.brooklyn.entity.stock.BasicApplication", + " brooklyn.config:", + " memberSpec:", + " $brooklyn:entitySpec:", + " - type: org.apache.brooklyn.entity.stock.BasicApplication"); + + try { + // Use the blueprint from the catalog that has the circular reference. + addCatalogItems( + "brooklyn.catalog:", + " id: another.app.in.the.catalog", + " version: "+TEST_VERSION, + "services:", + "- type: org.apache.brooklyn.entity.stock.BasicApplication"); + deleteCatalogEntity("another.app.in.the.catalog"); + } finally { + deleteCatalogEntity("org.apache.brooklyn.entity.stock.BasicApplication"); + } + } }
