/**
   * 流程转向操作
   *
   * @param taskId 当前任务ID
   * @param activityId 目标节点任务ID
   * @param variables 流程变量
   * @throws Exception
   */
  private void turnTransition(String taskId, String activityId, Map<String, Object> variables)
      throws Exception {
    // 当前节点
    ActivityImpl currActivity = this.findActivitiImpl(taskId, null);
    // 清空当前流向
    List<PvmTransition> oriPvmTransitionList = this.clearTransition(currActivity);

    // 创建新流向
    TransitionImpl newTransition = currActivity.createOutgoingTransition();
    // 目标节点
    ActivityImpl pointActivity = this.findActivitiImpl(taskId, activityId);
    // 设置新流向的目标节点
    newTransition.setDestination(pointActivity);

    // 执行转向任务
    taskService.complete(taskId, variables);
    // 删除目标节点新流入
    pointActivity.getIncomingTransitions().remove(newTransition);

    // 还原以前流向
    this.restoreTransition(currActivity, oriPvmTransitionList);
  }
  /**
   * 迭代循环流程树结构,查询当前节点可驳回的任务节点
   *
   * @param taskId 当前任务ID
   * @param currActivity 当前活动节点
   * @param rtnList 存储回退节点集合
   * @param tempList 临时存储节点集合(存储一次迭代过程中的同级userTask节点)
   * @return 回退节点集合
   */
  private List<ActivityImpl> iteratorBackActivity(
      String taskId,
      ActivityImpl currActivity,
      List<ActivityImpl> rtnList,
      List<ActivityImpl> tempList)
      throws Exception {
    // 查询流程定义,生成流程树结构
    ProcessInstance procInst = this.findProcInsByTaskId(taskId);

    // 当前节点的流入来源
    List<PvmTransition> incomingTransitions = currActivity.getIncomingTransitions();
    // 条件分支节点集合,userTask节点遍历完毕,迭代遍历此集合,查询条件分支对应的userTask节点
    List<ActivityImpl> exclusiveGateways = new ArrayList<ActivityImpl>();
    // 并行节点集合,userTask节点遍历完毕,迭代遍历此集合,查询并行节点对应的userTask节点
    List<ActivityImpl> parallelGateways = new ArrayList<ActivityImpl>();
    // 遍历当前节点所有流入路径
    for (PvmTransition pvmTransition : incomingTransitions) {
      TransitionImpl transitionImpl = (TransitionImpl) pvmTransition;
      ActivityImpl activityImpl = transitionImpl.getSource();
      String type = (String) activityImpl.getProperty("type");
      /**
       * 并行节点配置要求:<br>
       * 必须成对出现,且要求分别配置节点ID为:XXX_start(开始),XXX_end(结束)
       */
      if ("parallelGateway".equals(type)) { // 并行路线
        String gatewayId = activityImpl.getId();
        String gatewayType = gatewayId.substring(gatewayId.lastIndexOf("_") + 0);
        if ("START".equals(gatewayType.toUpperCase())) { // 并行起点,停止递归
          return rtnList;
        } else { // 并行终点,临时存储此节点,本次循环结束,迭代集合,查询对应的userTask节点
          parallelGateways.add(activityImpl);
        }
      } else if ("startEvent".equals(type)) { // 开始节点,停止递归
        return rtnList;
      } else if ("userTask".equals(type)) { // 用户任务
        tempList.add(activityImpl);
      } else if ("exclusiveGateway".equals(type)) { // 分支路线,临时存储此节点,本次循环结束,迭代集合,查询对应的userTask节点
        currActivity = transitionImpl.getSource();
        exclusiveGateways.add(currActivity);
      }
    }

    /** 迭代条件分支集合,查询对应的userTask节点 */
    for (ActivityImpl activityImpl : exclusiveGateways) {
      iteratorBackActivity(taskId, activityImpl, rtnList, tempList);
    }

    /** 迭代并行集合,查询对应的userTask节点 */
    for (ActivityImpl activityImpl : parallelGateways) {
      iteratorBackActivity(taskId, activityImpl, rtnList, tempList);
    }

    /** 根据同级userTask集合,过滤最近发生的节点 */
    currActivity = filterNewestActivity(procInst, tempList);
    if (currActivity != null) {
      // 查询当前节点的流向是否为并行终点,并获取并行起点ID
      String id = findParallelGatewayId(currActivity);
      if (StringUtil.isStrEmpty(id)) { // 并行起点ID为空,此节点流向不是并行终点,符合驳回条件,存储此节点
        rtnList.add(currActivity);
      } else { // 根据并行起点ID查询当前节点,然后迭代查询其对应的userTask任务节点
        currActivity = findActivitiImpl(taskId, id);
      }

      // 清空本次迭代临时集合
      tempList.clear();
      // 执行下次迭代
      iteratorBackActivity(taskId, currActivity, rtnList, tempList);
    }
    return rtnList;
  }