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 ead691b30b8b8771e89c3db4b5d9c5086e55ef49 Author: Alex Heneveld <a...@cloudsoft.io> AuthorDate: Tue Feb 13 17:02:37 2024 +0000 allow 'entity' to be used as a type, and lookup based on plan id or internal id reusing existing coercion from string --- .../mgmt/internal/AbstractManagementContext.java | 36 ++++++++++++++++++++++ .../core/workflow/WorkflowStepResolution.java | 24 ++------------- .../core/flags/BrooklynTypeNameResolution.java | 4 +++ .../workflow/WorkflowConfigSensorEffectorTest.java | 22 +++++++++++++ 4 files changed, 65 insertions(+), 21 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 b212589556..722f6040c5 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 @@ -19,6 +19,8 @@ package org.apache.brooklyn.core.mgmt.internal; import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Predicates; import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl; import static org.apache.brooklyn.core.catalog.internal.CatalogUtils.newClassLoadingContextForCatalogItems; @@ -60,7 +62,9 @@ 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.entity.AbstractEntity; +import org.apache.brooklyn.core.entity.BrooklynConfigKeys; import org.apache.brooklyn.core.entity.EntityInternal; +import org.apache.brooklyn.core.entity.EntityPredicates; import org.apache.brooklyn.core.entity.drivers.BasicEntityDriverManager; import org.apache.brooklyn.core.entity.drivers.downloads.BasicDownloadsManager; import org.apache.brooklyn.core.internal.BrooklynProperties; @@ -82,6 +86,7 @@ import org.apache.brooklyn.util.core.task.BasicExecutionContext; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.guava.Maybe; +import org.apache.brooklyn.util.javalang.Boxing; import org.apache.brooklyn.util.javalang.Reflections; import org.apache.brooklyn.util.text.Strings; import org.slf4j.Logger; @@ -540,14 +545,45 @@ public abstract class AbstractManagementContext implements ManagementContextInte public <T extends BrooklynObject> T lookup(String id, Class<T> type) { if (id==null) return null; Object result; + result = getEntityManager().getEntity(id); if (result!=null && type.isInstance(result)) return (T)result; result = getLocationManager().getLocation(id); if (result!=null && type.isInstance(result)) return (T)result; + Entity contextEntity = BrooklynTaskTags.getContextEntity(Tasks.current()); + if (type.isAssignableFrom(Entity.class) && contextEntity!=null) { + result = findEntity(contextEntity, id).orNull(); + if (result!=null && type.isInstance(result)) return (T)result; + } + return lookup((o) -> { return type.isInstance(o) && Objects.equal(id, o.getId()); }); } + + public static Maybe<Entity> findEntity(Entity contextEntity, Object entityO) { + Entity entity=null; + String entityId; + if (entityO instanceof Entity) { + entity = (Entity) entityO; + } else if (entityO instanceof String || Boxing.isPrimitiveOrBoxedObject(entityO)) { + entityId = entityO.toString(); + + List<Entity> firstGroupOfMatches = AppGroupTraverser.findFirstGroupOfMatches(contextEntity, true, + Predicates.and(EntityPredicates.configEqualTo(BrooklynConfigKeys.PLAN_ID, entityId), x->true)::apply); + if (firstGroupOfMatches.isEmpty()) { + firstGroupOfMatches = AppGroupTraverser.findFirstGroupOfMatches(contextEntity, true, + Predicates.and(EntityPredicates.idEqualTo(entityId), x->true)::apply); + } + if (!firstGroupOfMatches.isEmpty()) { + entity = firstGroupOfMatches.get(0); + } + + if (entity==null) return Maybe.absent("Cannot find entity with id '"+entityId+"'"); + + } else return Maybe.absent("Invalid expression for entity; must be a string or entity, not '"+entityO+"'"); + return Maybe.of(entity); + } @Override public <T extends BrooklynObject> T lookup(Predicate<? super T> filter) { diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepResolution.java b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepResolution.java index e127e782fa..a41eb524b2 100644 --- a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepResolution.java +++ b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepResolution.java @@ -27,6 +27,7 @@ import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.core.entity.BrooklynConfigKeys; import org.apache.brooklyn.core.entity.EntityPredicates; +import org.apache.brooklyn.core.mgmt.internal.AbstractManagementContext; import org.apache.brooklyn.core.mgmt.internal.AppGroupTraverser; import org.apache.brooklyn.core.objs.BrooklynObjectInternal; import org.apache.brooklyn.core.resolve.jackson.BeanWithTypeUtils; @@ -187,26 +188,7 @@ public class WorkflowStepResolution { } public static Maybe<Entity> findEntity(WorkflowStepInstanceExecutionContext context, Object entityO) { - Entity entity=null; - String entityId; - if (entityO instanceof Entity) { - entity = (Entity) entityO; - } else if (entityO instanceof String || Boxing.isPrimitiveOrBoxedObject(entityO)) { - entityId = entityO.toString(); - - List<Entity> firstGroupOfMatches = AppGroupTraverser.findFirstGroupOfMatches(context.getEntity(), true, - Predicates.and(EntityPredicates.configEqualTo(BrooklynConfigKeys.PLAN_ID, entityId), x->true)::apply); - if (firstGroupOfMatches.isEmpty()) { - firstGroupOfMatches = AppGroupTraverser.findFirstGroupOfMatches(context.getEntity(), true, - Predicates.and(EntityPredicates.idEqualTo(entityId), x->true)::apply); - } - if (!firstGroupOfMatches.isEmpty()) { - entity = firstGroupOfMatches.get(0); - } - - if (entity==null) return Maybe.absent("Cannot find entity with id '"+entityId+"'"); - - } else return Maybe.absent("Invalid expression for entity; must be a string or entity, not '"+entityO+"'"); - return Maybe.of(entity); + return AbstractManagementContext.findEntity(context.getEntity(), entityO); } + } diff --git a/core/src/main/java/org/apache/brooklyn/util/core/flags/BrooklynTypeNameResolution.java b/core/src/main/java/org/apache/brooklyn/util/core/flags/BrooklynTypeNameResolution.java index b09db8e1be..2a91915e59 100644 --- a/core/src/main/java/org/apache/brooklyn/util/core/flags/BrooklynTypeNameResolution.java +++ b/core/src/main/java/org/apache/brooklyn/util/core/flags/BrooklynTypeNameResolution.java @@ -22,6 +22,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.reflect.TypeToken; +import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.location.PortRange; import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext; @@ -81,6 +82,9 @@ public class BrooklynTypeNameResolution { .put("timestamp", Timestamp.class) .put("instant", Instant.class) .put("port", PortRange.class) + + .put("entity", Entity.class) + .build(); private static final Map<String,Class<?>> BUILT_IN_TYPE_CLASSES; diff --git a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowConfigSensorEffectorTest.java b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowConfigSensorEffectorTest.java index 0386fd5dd9..ea02bc12b0 100644 --- a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowConfigSensorEffectorTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowConfigSensorEffectorTest.java @@ -187,4 +187,26 @@ public class WorkflowConfigSensorEffectorTest extends RebindTestFixture<TestAppl return ""+entry.getKey()+"="+entry.getValue()+"x"+n; } } + + @Test + public void testLetEntityType() throws Exception { + runWorkflow(MutableList.of("let entity x = chilld", "return ${x}")); + Entity chilld = Iterables.getOnlyElement(app.getChildren()); + Asserts.assertEquals(lastInvocation.getUnchecked(), chilld); + + runWorkflow(MutableList.of("let entity x = chilldx", + "let y = ${x} ?? missing", + "return ${y}")); + Asserts.assertEquals(lastInvocation.getUnchecked(), "missing"); + Asserts.assertFailsWith(() -> runWorkflow(MutableList.of("let entity x = chilldx", + "return ${x}")), + // would be nice not to cast it to null if not found, and maybe for return null to be allowed (?); + // might want a different way to look up an entity (functional?) +// Asserts.expectedFailureContainsIgnoreCase("entity", "not known", "chilldx") +// .and(Asserts.expectedFailureDoesNotContainIgnoreCase("${x}", "null")) + // but for now it is useful to be able to do lookups, and null lets us tell it wasn't found + Asserts.expectedFailureContainsIgnoreCase("${x}", "null") + ); + } + }