/**
   * 封装输出信息,包括:当前节点的X、Y坐标、变量信息、任务类型、任务描述
   *
   * @param activity
   * @param processInstance
   * @param currentActiviti
   * @return
   */
  private Map<String, Object> packageSingleActivitiInfo(
      ActivityImpl activity, ProcessInstance processInstance, boolean currentActiviti)
      throws Exception {
    Map<String, Object> vars = new HashMap<String, Object>();
    Map<String, Object> activityInfo = new HashMap<String, Object>();
    activityInfo.put("currentActiviti", currentActiviti);
    setPosition(activity, activityInfo);
    setWidthAndHeight(activity, activityInfo);

    Map<String, Object> properties = activity.getProperties();
    vars.put("任务类型", WorkflowUtils.parseToZhType(properties.get("type").toString()));

    ActivityBehavior activityBehavior = activity.getActivityBehavior();
    logger.debug("activityBehavior={}", activityBehavior);
    if (activityBehavior instanceof UserTaskActivityBehavior) {

      Task currentTask = null;

      /*
       * 当前节点的task
       */
      if (currentActiviti) {
        currentTask = getCurrentTaskInfo(processInstance);
      }

      /*
       * 当前任务的分配角色
       */
      UserTaskActivityBehavior userTaskActivityBehavior =
          (UserTaskActivityBehavior) activityBehavior;
      TaskDefinition taskDefinition = userTaskActivityBehavior.getTaskDefinition();
      Set<Expression> candidateGroupIdExpressions = taskDefinition.getCandidateGroupIdExpressions();
      if (!candidateGroupIdExpressions.isEmpty()) {

        // 任务的处理角色
        setTaskGroup(vars, candidateGroupIdExpressions);

        // 当前处理人
        if (currentTask != null) {
          setCurrentTaskAssignee(vars, currentTask);
        }
      }
    }

    vars.put("节点说明", properties.get("documentation"));

    String description = activity.getProcessDefinition().getDescription();
    vars.put("描述", description);

    logger.debug("trace variables: {}", vars);
    activityInfo.put("vars", vars);
    return activityInfo;
  }
 /** @return */
 @Override
 public String getProcessDefinitionId() {
   return activityImpl.getProcessDefinition().getId();
 }
  @SuppressWarnings("unchecked")
  @Override
  protected void eventNotificationsCompleted(InterpretableExecution execution) {
    ActivityImpl activity = (ActivityImpl) execution.getActivity();
    ActivityImpl parentActivity = activity.getParentActivity();

    // if the execution is a single path of execution inside the process definition scope
    if ((parentActivity != null) && (!parentActivity.isScope())) {
      execution.setActivity(parentActivity);
      execution.performOperation(ACTIVITY_END);

    } else if (execution.isProcessInstance()) {
      execution.performOperation(PROCESS_END);

    } else if (execution.isScope()) {

      ActivityBehavior parentActivityBehavior =
          (parentActivity != null ? parentActivity.getActivityBehavior() : null);
      if (parentActivityBehavior instanceof CompositeActivityBehavior) {
        CompositeActivityBehavior compositeActivityBehavior =
            (CompositeActivityBehavior) parentActivity.getActivityBehavior();

        if (activity.isScope() && activity.getOutgoingTransitions().isEmpty()) {
          // there is no transition destroying the scope
          InterpretableExecution parentScopeExecution =
              (InterpretableExecution) execution.getParent();
          execution.destroy();
          execution.remove();
          parentScopeExecution.setActivity(parentActivity);
          compositeActivityBehavior.lastExecutionEnded(parentScopeExecution);
        } else {
          execution.setActivity(parentActivity);
          compositeActivityBehavior.lastExecutionEnded(execution);
        }
      } else {
        // default destroy scope behavior
        InterpretableExecution parentScopeExecution =
            (InterpretableExecution) execution.getParent();
        execution.destroy();
        execution.remove();
        // if we are a scope under the process instance
        // and have no outgoing transitions: end the process instance here
        if (activity.getParent() == activity.getProcessDefinition()
            && activity.getOutgoingTransitions().isEmpty()) {
          parentScopeExecution.setActivity(activity);
          // we call end() because it sets isEnded on the execution
          parentScopeExecution.end();
        } else {
          parentScopeExecution.setActivity(parentActivity);
          parentScopeExecution.performOperation(ACTIVITY_END);
        }
      }

    } else { // execution.isConcurrent() && !execution.isScope()

      execution.remove();

      // prune if necessary
      InterpretableExecution concurrentRoot = (InterpretableExecution) execution.getParent();
      if (concurrentRoot.getExecutions().size() == 1) {
        InterpretableExecution lastConcurrent =
            (InterpretableExecution) concurrentRoot.getExecutions().get(0);
        if (!lastConcurrent.isScope()) {
          concurrentRoot.setActivity((ActivityImpl) lastConcurrent.getActivity());
          lastConcurrent.setReplacedBy(concurrentRoot);

          // Move children of lastConcurrent one level up
          if (lastConcurrent.getExecutions().size() > 0) {
            concurrentRoot.getExecutions().clear();
            for (ActivityExecution childExecution : lastConcurrent.getExecutions()) {
              InterpretableExecution childInterpretableExecution =
                  (InterpretableExecution) childExecution;
              ((List) concurrentRoot.getExecutions())
                  .add(childExecution); // casting ... damn generics
              childInterpretableExecution.setParent(concurrentRoot);
            }
            lastConcurrent.getExecutions().clear();
          }

          // Copy execution-local variables of lastConcurrent
          concurrentRoot.setVariablesLocal(lastConcurrent.getVariablesLocal());

          lastConcurrent.remove();
        } else {
          lastConcurrent.setConcurrent(false);
        }
      }
    }
  }