/** Add step result failure information to the data context */
  private StepExecutionContext addStepFailureContextData(
      StepExecutionResult stepResult, StepExecutionContext handlerExecContext) {
    HashMap<String, String> resultData = new HashMap<String, String>();
    if (null != stepResult.getFailureData()) {
      // convert values to string
      for (final Map.Entry<String, Object> entry : stepResult.getFailureData().entrySet()) {
        resultData.put(entry.getKey(), entry.getValue().toString());
      }
    }
    FailureReason reason = stepResult.getFailureReason();
    if (null == reason) {
      reason = StepFailureReason.Unknown;
    }
    resultData.put("reason", reason.toString());
    String message = stepResult.getFailureMessage();
    if (null == message) {
      message = "No message";
    }
    resultData.put("message", message);
    // add to data context

    handlerExecContext =
        ExecutionContextImpl.builder(handlerExecContext).setContext("result", resultData).build();
    return handlerExecContext;
  }
  /**
   * Execute a workflow item, returns true if the item succeeds. This method will throw an exception
   * if the workflow item fails and the Workflow is has keepgoing==false.
   *
   * @param failedMap List to add any messages if the item fails
   * @param c index of the WF item
   * @param cmd WF item descriptor
   * @return true if the execution succeeds, false otherwise
   */
  protected StepExecutionResult executeWFItem(
      final StepExecutionContext executionContext,
      final Map<Integer, StepExecutionResult> failedMap,
      final int c,
      final StepExecutionItem cmd) {

    if (null != executionContext.getExecutionListener()) {
      executionContext
          .getExecutionListener()
          .log(Constants.DEBUG_LEVEL, c + ": Workflow step executing: " + cmd);
    }
    StepExecutionResult result;
    try {
      result =
          framework
              .getExecutionService()
              .executeStep(
                  ExecutionContextImpl.builder(executionContext).stepNumber(c).build(), cmd);
      if (!result.isSuccess()) {
        failedMap.put(c, result);
      }
    } catch (StepException e) {
      result = StepExecutionResultImpl.wrapStepException(e);
      failedMap.put(c, result);
    }
    if (null != executionContext.getExecutionListener()) {
      executionContext
          .getExecutionListener()
          .log(Constants.DEBUG_LEVEL, c + ": Workflow step finished, result: " + result);
    }
    return result;
  }
 private Map<String, Object> resultMetadata(StepExecutionResult result) {
   if (null != result && result.isSuccess()) {
     return null;
   }
   HashMap<String, Object> map = new HashMap<String, Object>();
   if (null != result && null != result.getFailureData()) {
     map.putAll(result.getFailureData());
   }
   map.put("failureReason", null != result ? result.getFailureReason().toString() : "Unknown");
   return map;
 }
  /**
   * Execute the sequence of ExecutionItems within the context, and with the given keepgoing value,
   * return true if successful
   */
  protected boolean executeWorkflowItemsForNodeSet(
      final StepExecutionContext executionContext,
      final Map<Integer, StepExecutionResult> failedMap,
      final List<StepExecutionResult> resultList,
      final List<StepExecutionItem> iWorkflowCmdItems,
      final boolean keepgoing,
      final int beginStepIndex) {

    boolean workflowsuccess = true;
    final WorkflowExecutionListener wlistener = getWorkflowListener(executionContext);
    int c = beginStepIndex;
    for (final StepExecutionItem cmd : iWorkflowCmdItems) {
      boolean stepSuccess = false;
      if (null != wlistener) {
        wlistener.beginWorkflowItem(c, cmd);
      }

      // wrap node failed listener (if any) and capture status results
      NodeRecorder stepCaptureFailedNodesListener = new NodeRecorder();
      StepExecutionContext stepContext =
          replaceFailedNodesListenerInContext(executionContext, stepCaptureFailedNodesListener);
      Map<String, NodeStepResult> nodeFailures;

      // execute the step item, and store the results
      StepExecutionResult stepResult = null;
      Map<Integer, StepExecutionResult> stepFailedMap = new HashMap<Integer, StepExecutionResult>();
      stepResult = executeWFItem(stepContext, stepFailedMap, c, cmd);
      stepSuccess = stepResult.isSuccess();
      nodeFailures = stepCaptureFailedNodesListener.getFailedNodes();

      if (null != executionContext.getExecutionListener()
          && null != executionContext.getExecutionListener().getFailedNodesListener()) {
        executionContext
            .getExecutionListener()
            .getFailedNodesListener()
            .matchedNodes(stepCaptureFailedNodesListener.getMatchedNodes());
      }

      try {
        if (!stepSuccess && cmd instanceof HasFailureHandler) {
          final HasFailureHandler handles = (HasFailureHandler) cmd;
          final StepExecutionItem handler = handles.getFailureHandler();
          if (null != handler) {
            // if there is a failure, and a failureHandler item, execute the failure handler
            // set keepgoing=false, and store the results
            // will throw an exception on failure because keepgoing=false

            NodeRecorder handlerCaptureFailedNodesListener = new NodeRecorder();
            StepExecutionContext handlerExecContext =
                replaceFailedNodesListenerInContext(
                    executionContext, handlerCaptureFailedNodesListener);

            // if multi-node, determine set of nodes to run handler on: (failed node list only)
            if (stepCaptureFailedNodesListener.getMatchedNodes().size() > 1) {
              HashSet<String> failedNodeList =
                  new HashSet<String>(stepCaptureFailedNodesListener.getFailedNodes().keySet());

              handlerExecContext =
                  new ExecutionContextImpl.Builder(handlerExecContext)
                      .nodeSelector(SelectorUtils.nodeList(failedNodeList))
                      .build();
            }

            if (null != stepResult) {
              // add step failure data to data context
              handlerExecContext = addStepFailureContextData(stepResult, handlerExecContext);

              // extract node-specific failure and set as node-context data
              handlerExecContext = addNodeStepFailureContextData(stepResult, handlerExecContext);
            }

            Map<Integer, StepExecutionResult> handlerFailedMap =
                new HashMap<Integer, StepExecutionResult>();
            StepExecutionResult handlerResult =
                executeWFItem(handlerExecContext, handlerFailedMap, c, handler);
            boolean handlerSuccess = handlerResult.isSuccess();

            // handle success conditions:
            // 1. if keepgoing=true, then status from handler overrides original step
            // 2. keepgoing=false, then status is the same as the original step, unless
            //   the keepgoingOnSuccess is set to true and the handler succeeded
            boolean useHandlerResults = keepgoing;
            if (!keepgoing && handlerSuccess && handler instanceof HandlerExecutionItem) {
              useHandlerResults = ((HandlerExecutionItem) handler).isKeepgoingOnSuccess();
            }
            if (useHandlerResults) {
              stepSuccess = handlerSuccess;
              stepResult = handlerResult;
              stepFailedMap = handlerFailedMap;
              nodeFailures = handlerCaptureFailedNodesListener.getFailedNodes();
            }
          }
        }
      } finally {
        if (null != wlistener) {
          wlistener.finishWorkflowItem(c, cmd);
        }
      }
      resultList.add(stepResult);
      failedMap.putAll(stepFailedMap);
      if (!stepSuccess) {
        workflowsuccess = false;
      }

      // report node failures based on results of step and handler run.
      if (null != executionContext.getExecutionListener()
          && null != executionContext.getExecutionListener().getFailedNodesListener()) {
        if (nodeFailures.size() > 0) {
          executionContext
              .getExecutionListener()
              .getFailedNodesListener()
              .nodesFailed(nodeFailures);
        } else if (workflowsuccess) {
          executionContext.getExecutionListener().getFailedNodesListener().nodesSucceeded();
        }
      }

      if (!stepSuccess && !keepgoing) {
        break;
      }
      c++;
    }
    return workflowsuccess;
  }
 private ExecutionState resultState(StepExecutionResult result) {
   return (null != result && result.isSuccess())
       ? ExecutionState.SUCCEEDED
       : ExecutionState.FAILED;
 }
 private String resultMessage(StepExecutionResult result) {
   return null != result ? result.getFailureMessage() : null;
 }