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 918acb96e765d8a217146213431b33de0acdf876
Author: Alex Heneveld <[email protected]>
AuthorDate: Fri Sep 15 13:41:56 2023 +0100

    allow workflow to have no steps if it has output
---
 .../core/workflow/WorkflowExecutionContext.java     |  2 +-
 .../core/workflow/WorkflowStepResolution.java       | 11 +++++++++--
 .../core/workflow/steps/CustomWorkflowStep.java     | 21 +++++++++++++++------
 .../brooklyn/core/workflow/WorkflowBasicTest.java   | 16 ++++++++++++++--
 4 files changed, 39 insertions(+), 11 deletions(-)

diff --git 
a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java
 
b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java
index 0abb57c806..deef3d0353 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowExecutionContext.java
@@ -917,7 +917,7 @@ public class WorkflowExecutionContext {
     @JsonIgnore
     List<WorkflowStepDefinition> getStepsResolved() {
         if (stepsResolved ==null) {
-            stepsResolved = 
MutableList.copyOf(WorkflowStepResolution.resolveSteps(getManagementContext(), 
WorkflowExecutionContext.this.stepsDefinition));
+            stepsResolved = 
MutableList.copyOf(WorkflowStepResolution.resolveSteps(getManagementContext(), 
WorkflowExecutionContext.this.stepsDefinition, outputDefinition));
         }
         return stepsResolved;
     }
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 515153a33c..102843d950 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
@@ -45,8 +45,15 @@ import java.util.Map;
 public class WorkflowStepResolution {
 
     public static List<WorkflowStepDefinition> resolveSteps(ManagementContext 
mgmt, List<Object> steps) {
+        return resolveSteps(mgmt, steps, null);
+    }
+    public static List<WorkflowStepDefinition> resolveSteps(ManagementContext 
mgmt, List<Object> steps, Object outputDefinition) {
         List<WorkflowStepDefinition> result = MutableList.of();
-        if (steps==null || steps.isEmpty()) throw new 
IllegalStateException("No steps defined in workflow");
+        if (steps==null || steps.isEmpty()) {
+            if (outputDefinition==null) throw new IllegalStateException("No 
steps defined in workflow and no output set");
+            // if there is output, an empty workflow makes sense
+            return result;
+        }
         for (int i=0; i<steps.size(); i++) {
             try {
                 result.add(resolveStep(mgmt, steps.get(i)));
@@ -172,7 +179,7 @@ public class WorkflowStepResolution {
         if (!hasCondition && entityOrAdjunctWhereRunningIfKnown!=null) {
             // ideally try to resolve the steps at entity init time; except if 
a condition is required we skip that so you can have steps that only resolve 
late,
             // and if entity isn't available then we don't need that either
-            WorkflowStepResolution.resolveSteps( 
((BrooklynObjectInternal)entityOrAdjunctWhereRunningIfKnown).getManagementContext(),
 steps);
+            WorkflowStepResolution.resolveSteps( 
((BrooklynObjectInternal)entityOrAdjunctWhereRunningIfKnown).getManagementContext(),
 steps, params.containsKey(WorkflowCommonConfig.OUTPUT.getName()) ? 
"has_output" : null);
         }
     }
 
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java
 
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java
index d1925d2327..e56d38e00a 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/workflow/steps/CustomWorkflowStep.java
@@ -58,6 +58,7 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
@@ -163,8 +164,10 @@ public class CustomWorkflowStep extends 
WorkflowStepDefinition implements Workfl
     public void validateStep(@Nullable ManagementContext mgmt, @Nullable 
WorkflowExecutionContext workflow) {
         super.validateStep(mgmt, workflow);
 
-        if (steps instanceof List) WorkflowStepResolution.resolveSteps(mgmt, 
(List<Object>) steps);
-        else if (steps!=null) throw new IllegalArgumentException("Workflow 
`steps` must be a list");
+        if (steps instanceof List) {
+            if (((List)steps).isEmpty()) throw new 
IllegalArgumentException("Workflow `steps` must be supplied for a custom or 
nested workflow");
+            WorkflowStepResolution.resolveSteps(mgmt, (List<Object>) steps, 
null);
+        } else if (steps!=null) throw new IllegalArgumentException("Workflow 
`steps` must be a list");
         else if (target!=null) throw new IllegalArgumentException("Workflow 
cannot take a `target` without `steps`");
     }
 
@@ -561,7 +564,10 @@ public class CustomWorkflowStep extends 
WorkflowStepDefinition implements Workfl
         return newWorkflowExecution(entity, name, extraConfig, null);
     }
     public WorkflowExecutionContext newWorkflowExecution(Entity entity, String 
name, ConfigBag extraConfig, Map extraTaskFlags) {
-        if (steps==null) throw new IllegalArgumentException("Cannot make new 
workflow with no steps");
+        if (steps==null) {
+            if (target!=null) throw new IllegalArgumentException("Steps are 
required for a workflow with a target");
+            else steps = MutableList.of();
+        }
 
         if (target==null) {
             // copy everything as we are going to run it "flat"
@@ -580,12 +586,15 @@ public class CustomWorkflowStep extends 
WorkflowStepDefinition implements Workfl
         }
     }
 
-    private ConfigBag getConfigForSubWorkflow(boolean includeInput) {
+    private ConfigBag getConfigForSubWorkflow(boolean isFlattened) {
+        if (isFlattened && (output!=null && workflowOutput!=null)) {
+            if (!Objects.equals(output, workflowOutput)) throw new 
IllegalArgumentException("Setting both 'output' and 'workflowOutput' is not 
supported for custom steps without target");
+        }
         ConfigBag result = ConfigBag.newInstance()
                 .configure(WorkflowCommonConfig.PARAMETER_DEFS, parameters)
                 .configure(WorkflowCommonConfig.STEPS, steps)
-                .configure(WorkflowCommonConfig.INPUT, includeInput ? input : 
null)  // input is resolved in outer workflow so it can reference outer 
workflow vars
-                .configure(WorkflowCommonConfig.OUTPUT, workflowOutput)
+                .configure(WorkflowCommonConfig.INPUT, isFlattened ? input : 
null)  // input is resolved in outer workflow so it can reference outer 
workflow vars
+                .configure(WorkflowCommonConfig.OUTPUT, isFlattened && 
workflowOutput==null ? output : workflowOutput)
                 .configure(WorkflowCommonConfig.RETENTION, retention)
                 .configure(WorkflowCommonConfig.REPLAYABLE, replayable)
                 .configure(WorkflowCommonConfig.IDEMPOTENT, idempotent)
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java 
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java
index 8d0ce20a87..9287cfb8b2 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java
@@ -216,7 +216,7 @@ public class WorkflowBasicTest extends 
BrooklynMgmtUnitTestSupport {
                         "log test message"
                 );
 
-        List<WorkflowStepDefinition> steps = 
WorkflowStepResolution.resolveSteps(mgmt, stepsDefinition);
+        List<WorkflowStepDefinition> steps = 
WorkflowStepResolution.resolveSteps(mgmt, stepsDefinition, null);
         Asserts.assertSize(steps, 4);
     }
 
@@ -229,7 +229,7 @@ public class WorkflowBasicTest extends 
BrooklynMgmtUnitTestSupport {
             Asserts.assertInstanceOf(wf, CustomWorkflowStep.class);
             Asserts.assertSize(((CustomWorkflowStep) wf).peekSteps(), 1);
             Asserts.assertInstanceOf(
-                    WorkflowStepResolution.resolveSteps( mgmt, 
((CustomWorkflowStep) wf).peekSteps() ).get(0), LogWorkflowStep.class);
+                    WorkflowStepResolution.resolveSteps( mgmt, 
((CustomWorkflowStep) wf).peekSteps(), null ).get(0), LogWorkflowStep.class);
         };
 
         test.accept( BeanWithTypeUtils.convert(mgmt,
@@ -480,5 +480,17 @@ public class WorkflowBasicTest extends 
BrooklynMgmtUnitTestSupport {
                 w1.getTask(false).get().getUnchecked(),
                 MutableList.of("a=b", "b=c"));
     }
+
+    @Test
+    public void testOutputOnlyWorkflow() {
+        loadTypes();
+        BasicApplication app = 
mgmt.getEntityManager().createEntity(EntitySpec.create(BasicApplication.class));
+        WorkflowExecutionContext w1 = WorkflowBasicTest.runWorkflow(app, 
Strings.lines(
+                "output: 42"
+        ), null);
+        Asserts.assertEquals(
+                w1.getTask(false).get().getUnchecked(),
+                42);
+    }
     
 }

Reply via email to