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 8975991af7bb57331e9894c23de186e58a64e2ea Author: Alex Heneveld <a...@cloudsoft.io> AuthorDate: Mon Feb 26 14:04:32 2024 +0000 allow if workflow step to take condition objects --- .../core/workflow/steps/flow/IfWorkflowStep.java | 58 +++++++++++++++++----- .../WorkflowSubIfAndCustomExtensionEdgeTest.java | 18 ++++++- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/flow/IfWorkflowStep.java b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/flow/IfWorkflowStep.java index 0fcdfdda8c..c269616080 100644 --- a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/flow/IfWorkflowStep.java +++ b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/flow/IfWorkflowStep.java @@ -22,14 +22,18 @@ import java.util.Map; import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.common.reflect.TypeToken; +import org.apache.brooklyn.core.resolve.jackson.WrappedValue; import org.apache.brooklyn.core.workflow.WorkflowExpressionResolution.WorkflowExpressionStage; import org.apache.brooklyn.core.workflow.WorkflowExpressionResolution.WrappedResolvedExpression; import org.apache.brooklyn.core.workflow.WorkflowExpressionResolution.WrappingMode; import org.apache.brooklyn.core.workflow.WorkflowStepInstanceExecutionContext; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.predicates.DslPredicates.DslEntityPredicateDefault; import org.apache.brooklyn.util.core.predicates.DslPredicates.DslPredicate; +import org.apache.brooklyn.util.core.predicates.DslPredicates.DslPredicateDefault; import org.apache.brooklyn.util.core.predicates.DslPredicates.WhenPresencePredicate; +import org.apache.brooklyn.util.core.task.DeferredSupplier; public class IfWorkflowStep extends SubWorkflowStep { @@ -77,21 +81,51 @@ public class IfWorkflowStep extends SubWorkflowStep { Map<String, Object> raw = MutableMap.of("target", getConditionRaw()); Object conditionConstructed = this.condition; if (conditionConstructed==null) { - Object k = context.getWorkflowExectionContext().resolveWrapped( - WorkflowExpressionStage.STEP_RUNNING, condition_target, TypeToken.of(Object.class), + boolean isCondition = false; + boolean seemsStatic = false; + Object k = condition_target; + if (condition_equals==null) { + if (condition_target instanceof Map) isCondition = true; + else if (condition_target instanceof String) { + if (((String) condition_target).trim().startsWith("$")) isCondition = false; + if (((String) condition_target).trim().startsWith("{")) { + isCondition = true; + k = context.getWorkflowExectionContext().resolveWrapped( + WorkflowExpressionStage.STEP_RUNNING, condition_target, TypeToken.of(Map.class), + WrappingMode.WRAPPED_RESULT_DEFER_THROWING_ERROR_BUT_NO_RETRY); + } else seemsStatic = true; + } else seemsStatic = true; + } + k = context.getWorkflowExectionContext().resolveWrapped( + WorkflowExpressionStage.STEP_RUNNING, k, TypeToken.of(isCondition ? DslEntityPredicateDefault.class : Object.class), WrappingMode.WRAPPED_RESULT_DEFER_THROWING_ERROR_BUT_NO_RETRY); - Map c = MutableMap.of("target", WrappedResolvedExpression.ifNonDeferred(condition_target, k)); - - if (condition_equals !=null) { - Object v = context.getWorkflowExectionContext().resolveWrapped( - WorkflowExpressionStage.STEP_RUNNING, condition_equals, TypeToken.of(Object.class), - WrappingMode.WRAPPED_RESULT_DEFER_THROWING_ERROR_BUT_NO_RETRY); - c.put("check", WrappedResolvedExpression.ifNonDeferred(condition_equals, v)); - c.put("assert", MutableMap.of("when", WhenPresencePredicate.PRESENT)); // when doing equals we need LHS and RHS to be present + + if (seemsStatic && !(k instanceof DslPredicate || k instanceof Boolean || k instanceof DeferredSupplier)) { + throw new IllegalArgumentException("Argument supplied as condition target will always evaluate as true."); + } + + if (isCondition) { + if (WrappedValue.getMaybe( ((DslPredicateDefault<?>)k).implicitEquals ).map( + impEq -> condition_target.equals(impEq)).or(false)) { + // will probably have thrown error when coercing from map, so probably not needed, but for good measure + throw new IllegalArgumentException("Argument supplied as condition target could not be evaluated as condition."); + } + conditionConstructed = k; + } else { - c.put("when", WhenPresencePredicate.TRUTHY); + Map c = MutableMap.of("target", WrappedResolvedExpression.ifNonDeferred(condition_target, k)); + + if (condition_equals != null) { + Object v = context.getWorkflowExectionContext().resolveWrapped( + WorkflowExpressionStage.STEP_RUNNING, condition_equals, TypeToken.of(Object.class), + WrappingMode.WRAPPED_RESULT_DEFER_THROWING_ERROR_BUT_NO_RETRY); + c.put("check", WrappedResolvedExpression.ifNonDeferred(condition_equals, v)); + c.put("assert", MutableMap.of("when", WhenPresencePredicate.PRESENT)); // when doing equals we need LHS and RHS to be present + } else { + c.put("when", WhenPresencePredicate.TRUTHY); + } + conditionConstructed = c; } - conditionConstructed = c; } DslPredicate result = getConditionResolved(context, conditionConstructed); diff --git a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowSubIfAndCustomExtensionEdgeTest.java b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowSubIfAndCustomExtensionEdgeTest.java index 4505bd8f15..e411031ac0 100644 --- a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowSubIfAndCustomExtensionEdgeTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowSubIfAndCustomExtensionEdgeTest.java @@ -199,6 +199,11 @@ public class WorkflowSubIfAndCustomExtensionEdgeTest extends RebindTestFixture<T Asserts.assertEquals(run.apply(null, "${x} == ${x}"), "yes"); Asserts.assertEquals(run.apply("let boolean x = true", "${x} == true"), "yes"); + Asserts.assertEquals(run.apply("set-sensor xy = yes", "{ sensor: xy, equals: yes }"), "yes"); + Asserts.assertEquals(run.apply(null, "{ sensor: xn, equals: yes }"), "no"); + Asserts.assertFailsWith(() -> run.apply(null, "{ unknown_field: xn }"), + Asserts.expectedFailureContainsIgnoreCase("unknown_field", "predicate")); + // unresolvable things -- allowed iff no == block Asserts.assertEquals(run.apply(null, "${unresolvable_without_equals}"), "no"); Asserts.assertFailsWith(() -> run.apply(null, "${x} == ${unresolvable_on_rhs}"), @@ -210,11 +215,22 @@ public class WorkflowSubIfAndCustomExtensionEdgeTest extends RebindTestFixture<T Asserts.assertEquals(runWorkflow(MutableList.of("let boolean x = true", "if ${x} then return yes", "return no")), "yes"); - Asserts.assertEquals(runWorkflow(MutableList.of("let integer x = 1", MutableMap.of("id", "loop", "step", "let x = ${x} + 1"), "if ${x} == 2 then goto loop", "return ${x}")), 3); } + @Test + public void testIfWorkflowWithSteps() throws Exception { + BiFunction<String, String, Object> run = (preface, cond) -> + runWorkflow(MutableList.<Object>of(preface==null ? "let x = hi" : preface, + MutableMap.of("step", "if "+(cond==null ? "${x}" : cond), + "steps", MutableList.of("let y = yes", "return ${y}")), + "return no")); + + Asserts.assertEquals(run.apply(null, null), "yes"); + Asserts.assertEquals(run.apply("let boolean x = false", null), "no"); + } + }