/**
   * Convert map of step execution results keyed by step number, to a collection of step execution
   * results keyed by node name
   */
  protected Map<String, Collection<StepExecutionResult>> convertFailures(
      final Map<Integer, StepExecutionResult> failedMap) {

    final Map<String, Collection<StepExecutionResult>> failures =
        new HashMap<String, Collection<StepExecutionResult>>();
    for (final Map.Entry<Integer, StepExecutionResult> entry : failedMap.entrySet()) {
      final StepExecutionResult o = entry.getValue();

      if (NodeDispatchStepExecutor.isWrappedDispatcherResult(o)) {
        // indicates dispatcher returned node results
        final DispatcherResult dispatcherResult =
            NodeDispatchStepExecutor.extractDispatcherResult(o);

        for (final String s : dispatcherResult.getResults().keySet()) {
          final NodeStepResult interpreterResult = dispatcherResult.getResults().get(s);
          if (!failures.containsKey(s)) {
            failures.put(s, new ArrayList<StepExecutionResult>());
          }
          failures.get(s).add(interpreterResult);
        }
      } else if (NodeDispatchStepExecutor.isWrappedDispatcherException(o)) {
        DispatcherException e = NodeDispatchStepExecutor.extractDispatcherException(o);
        final INodeEntry node = e.getNode();
        if (null != node) {
          // dispatch failed for a specific node
          final String key = node.getNodename();
          if (!failures.containsKey(key)) {
            failures.put(key, new ArrayList<StepExecutionResult>());
          }
          failures.get(key).add(e.getResultMap().get(node.getNodename()));
        } else {
          // dispatch failed for a set of nodes
          for (final String s : e.getResultMap().keySet()) {
            final NodeStepResult interpreterResult = e.getResultMap().get(s);
            if (!failures.containsKey(s)) {
              failures.put(s, new ArrayList<StepExecutionResult>());
            }
            failures.get(s).add(interpreterResult);
          }
        }
      }
    }
    return failures;
  }
 /** Add any node-specific step failure information to the node-specific data contexts */
 private StepExecutionContext addNodeStepFailureContextData(
     StepExecutionResult dispatcherStepResult, StepExecutionContext handlerExecContext) {
   final Map<String, ? extends NodeStepResult> resultMap;
   if (NodeDispatchStepExecutor.isWrappedDispatcherResult(dispatcherStepResult)) {
     DispatcherResult dispatcherResult =
         NodeDispatchStepExecutor.extractDispatcherResult(dispatcherStepResult);
     resultMap = dispatcherResult.getResults();
   } else if (NodeDispatchStepExecutor.isWrappedDispatcherException(dispatcherStepResult)) {
     DispatcherException exception =
         NodeDispatchStepExecutor.extractDispatcherException(dispatcherStepResult);
     resultMap = exception.getResultMap();
   } else {
     return handlerExecContext;
   }
   ExecutionContextImpl.Builder builder = ExecutionContextImpl.builder(handlerExecContext);
   for (final Map.Entry<String, ? extends NodeStepResult> dentry : resultMap.entrySet()) {
     String nodename = dentry.getKey();
     NodeStepResult stepResult = dentry.getValue();
     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
     HashMap<String, Map<String, String>> ndata = new HashMap<String, Map<String, String>>();
     ndata.put("result", resultData);
     builder.nodeDataContext(nodename, ndata);
   }
   return builder.build();
 }