This is an automated email from the ASF dual-hosted git repository. heneveld pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
commit 987694403aae28046a94f11d730a55c9c08532f8 Author: Alex Heneveld <[email protected]> AuthorDate: Fri Aug 6 12:45:48 2021 +0100 ensure scopeRoot resovles to the root node of the blueprint _where the DSL is used_ even for nested (extended) types - do this by replacing the DSL expression _at parse time_ --- .../camp/brooklyn/spi/creation/CampResolver.java | 34 ++++++++++++++++++++-- .../brooklyn/spi/dsl/methods/DslComponent.java | 18 +++++++++++- .../brooklyn/camp/brooklyn/EntitiesYamlTest.java | 12 ++------ 3 files changed, 52 insertions(+), 12 deletions(-) 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 8ac1ecb..9d809d9 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 @@ -22,6 +22,8 @@ import com.google.common.annotations.Beta; import java.util.Set; import java.util.Stack; +import java.util.function.Consumer; +import java.util.function.Function; import org.apache.brooklyn.api.entity.Application; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.entity.EntitySpec; @@ -36,8 +38,11 @@ import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext; import org.apache.brooklyn.camp.BasicCampPlatform; import org.apache.brooklyn.camp.CampPlatform; import org.apache.brooklyn.camp.brooklyn.api.AssemblyTemplateSpecInstantiator; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent; +import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope; import org.apache.brooklyn.camp.spi.AssemblyTemplate; import org.apache.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator; +import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; import org.apache.brooklyn.core.catalog.internal.CatalogUtils; import org.apache.brooklyn.core.entity.AbstractEntity; @@ -176,11 +181,14 @@ class CampResolver { // above will unwrap but only if it's an Application (and it's permitted); // but it doesn't know whether we need an App or if an Entity is okay - if (!isApplication) return EntityManagementUtils.unwrapEntity(appSpec); + EntitySpec<?> result = !isApplication ? EntityManagementUtils.unwrapEntity(appSpec) : appSpec; // if we need an App then definitely *don't* unwrap here because // the instantiator will have done that, and it knows if the plan // specified a wrapped app explicitly (whereas we don't easily know that here!) - return appSpec; + + fixScopeRootAtRoot(result); + + return result; } else { if (at.getPlatformComponentTemplates()==null || at.getPlatformComponentTemplates().isEmpty()) { @@ -191,4 +199,26 @@ class CampResolver { } + private static void fixScopeRootAtRoot(EntitySpec<?> node) { + node.getConfig().entrySet().forEach(entry -> { + fixScopeRoot(entry.getValue(), newValue -> node.configure( (ConfigKey) entry.getKey(), newValue)); + }); + node.getFlags().entrySet().forEach(entry -> { + fixScopeRoot(entry.getValue(), newValue -> node.configure( entry.getKey(), newValue)); + }); + } + + private static void fixScopeRoot(Object value, Consumer<Object> updater) { + Function<String,String> fixString = v -> "$brooklyn:self()" + Strings.removeFromStart((String)v, "$brooklyn:scopeRoot()"); + if (value instanceof String && ((String)value).startsWith("$brooklyn:scopeRoot()")) { + value = fixString.apply((String)value); + updater.accept(value); + } else if (value instanceof DslComponent) { + if ( ((DslComponent)value).getScope() == Scope.SCOPE_ROOT ) { + value = DslComponent.newInstanceChangingScope(Scope.THIS, (DslComponent) value, fixString); + updater.accept(value); + } + } + } + } \ No newline at end of file diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java index cf6fa2d..01c68e1 100644 --- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java +++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java @@ -21,6 +21,7 @@ package org.apache.brooklyn.camp.brooklyn.spi.dsl.methods; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import java.util.Set; +import java.util.function.Function; import static org.apache.brooklyn.camp.brooklyn.spi.dsl.DslUtils.resolved; import java.util.Collection; @@ -113,6 +114,20 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> implements } } + public static DslComponent newInstanceChangingScope(Scope scope, DslComponent old, Function<String,String> dslUpdateFn) { + DslComponent result; + if (old.componentIdSupplier!=null) result = new DslComponent(scope, old.componentIdSupplier); + else if (old.componentId!=null) result = new DslComponent(scope, old.componentId); + else result = new DslComponent(scope); + + if (dslUpdateFn!=null && old.dsl instanceof String) { + result.dsl = dslUpdateFn.apply((String) old.dsl); + } else { + result.dsl = old.dsl; + } + return result; + } + /** * Resolve componentId in the {@link Scope#GLOBAL} scope. * @@ -1028,7 +1043,8 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> implements DESCENDANT, ANCESTOR, ROOT, - /** highest ancestor where all items come from the same catalog item ID */ + /** root node of blueprint where the the DSL is used; usually the depth in ancestor, + * though specially treated in CampResolver to handle usage within blueprints */ SCOPE_ROOT, THIS; diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java index 4ee8a4c..e86ab1a 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EntitiesYamlTest.java @@ -586,7 +586,8 @@ public class EntitiesYamlTest extends AbstractYamlTest { Entity e2 = nextChild(e1); assertScopes(e2, "APP-grandchild", app, app); Entity e3 = nextChild(e2); - assertScopes(e3, "APP-greatgrandchild=RP", app, e2, app); + // see logic in CampResolver which ensures scopeRoot in a nested blueprint refer to the root of that nested blueprint + assertScopes(e3, "APP-greatgrandchild=RP", app, e3, app); Entity e4 = nextChild(e3); assertScopes(e4, "RP-child", app, e3); Entity e5 = nextChild(e4); @@ -622,14 +623,7 @@ public class EntitiesYamlTest extends AbstractYamlTest { private static void assertScopes(Entity entity, String name, Entity root, Entity scopeRoot, Entity scopeRoot2) { if (name!=null) assertEquals(entity.getDisplayName(), name); assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_ROOT), root); - - Entity actualScopeRoot = entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_SCOPE_ROOT); - if (!actualScopeRoot.equals(scopeRoot) && !actualScopeRoot.equals(scopeRoot2)) { - Assert.fail("Wrong scope root; should be either "+scopeRoot+" or "+scopeRoot2+"; but is actually "+actualScopeRoot); - } - // TODO would be nice if we can capture which blueprint scopeRoot is used in - but this requires introspecting the DSL - // currently it will always equal scopeRoot2; if we could convert it to "self()" when the definition is loaded, that would solve it - + assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_SCOPE_ROOT), scopeRoot); assertEquals(entity.config().get(ReferencingYamlTestEntity.TEST_REFERENCE_SCOPE_ROOT2), scopeRoot2); }
