private String determineFutureNodeName(
     RouteNode node, MovePoint movePoint, int currentStep, Set nodesProcessed)
     throws InvalidActionTakenException {
   if (nodesProcessed.contains(node.getRouteNodeId())) {
     throw new InvalidActionTakenException(
         "Detected a cycle at node "
             + node.getRouteNodeName()
             + " when attempting to move document.");
   }
   nodesProcessed.add(node.getRouteNodeId());
   if (currentStep == movePoint.getStepsToMove()) {
     return node.getRouteNodeName();
   }
   List nextNodes = node.getNextNodes();
   if (nextNodes.size() == 0) {
     throw new InvalidActionTakenException(
         "Could not proceed forward, there are no more nodes in the route.  Halted on step "
             + currentStep);
   }
   if (nextNodes.size() != 1) {
     throw new InvalidActionTakenException(
         "Cannot move forward in a multi-branch path.  Located "
             + nextNodes.size()
             + " branches.  Halted on step "
             + currentStep);
   }
   return determineFutureNodeName(
       (RouteNode) nextNodes.get(0), movePoint, currentStep + 1, nodesProcessed);
 }
 private String determineReturnNodeName(RouteNode node, MovePoint movePoint, int currentStep)
     throws InvalidActionTakenException {
   if (currentStep == movePoint.getStepsToMove()) {
     return node.getRouteNodeName();
   }
   List previousNodes = node.getPreviousNodes();
   if (previousNodes.size() == 0) {
     throw new InvalidActionTakenException(
         "Could not locate the named target node in the document's past route.  Halted on step "
             + currentStep);
   }
   if (previousNodes.size() != 1) {
     throw new InvalidActionTakenException(
         "Located a multi-branch path, could not proceed backward past this point.  Halted on step "
             + currentStep);
   }
   return determineReturnNodeName((RouteNode) previousNodes.get(0), movePoint, currentStep - 1);
 }
 private String displayMovePoint(MovePoint movePoint) {
   return "fromNode="
       + movePoint.getStartNodeName()
       + ", stepsToMove="
       + movePoint.getStepsToMove();
 }
  public void recordAction() throws InvalidActionTakenException {
    MDC.put("docId", getRouteHeader().getDocumentId());
    updateSearchableAttributesIfPossible();
    LOG.debug(
        "Moving document "
            + getRouteHeader().getDocumentId()
            + " to point: "
            + displayMovePoint(movePoint)
            + ", annotation: "
            + annotation);

    List actionRequests =
        getActionRequestService()
            .findAllValidRequests(
                getPrincipal().getPrincipalId(),
                getDocumentId(),
                KewApiConstants.ACTION_REQUEST_COMPLETE_REQ);
    Collection activeNodes =
        KEWServiceLocator.getRouteNodeService()
            .getActiveNodeInstances(getRouteHeader().getDocumentId());
    String errorMessage = validateActionRules(actionRequests, activeNodes);
    if (!org.apache.commons.lang.StringUtils.isEmpty(errorMessage)) {
      throw new InvalidActionTakenException(errorMessage);
    }

    RouteNodeInstance startNodeInstance = determineStartNode(activeNodes, movePoint);

    LOG.debug("Record the move action");
    Recipient delegator = findDelegatorForActionRequests(actionRequests);
    ActionTakenValue actionTaken = saveActionTaken(delegator);
    getActionRequestService().deactivateRequests(actionTaken, actionRequests);
    notifyActionTaken(actionTaken);

    // TODO this whole bit is a bit hacky at the moment
    if (movePoint.getStepsToMove() > 0) {
      Set<String> targetNodeNames = new HashSet<String>();
      targetNodeNames.add(determineFutureNodeName(startNodeInstance, movePoint));

      final boolean shouldIndex =
          getRouteHeader().getDocumentType().hasSearchableAttributes()
              && RouteContext.getCurrentRouteContext().isSearchIndexingRequestedForContext();
      String applicationId = routeHeader.getDocumentType().getApplicationId();
      DocumentOrchestrationQueue orchestrationQueue =
          KewApiServiceLocator.getDocumentOrchestrationQueue(
              routeHeader.getDocumentId(), applicationId);
      org.kuali.rice.kew.api.document.OrchestrationConfig orchestrationConfig =
          org.kuali.rice.kew.api.document.OrchestrationConfig.create(
              actionTaken.getActionTakenId(), targetNodeNames);
      DocumentProcessingOptions options =
          DocumentProcessingOptions.create(true, shouldIndex, false);
      orchestrationQueue.orchestrateDocument(
          routeHeader.getDocumentId(),
          getPrincipal().getPrincipalId(),
          orchestrationConfig,
          options);
    } else {
      String targetNodeName = determineReturnNodeName(startNodeInstance, movePoint);
      ReturnToPreviousNodeAction returnAction =
          new ReturnToPreviousNodeAction(
              KewApiConstants.ACTION_TAKEN_MOVE_CD,
              getRouteHeader(),
              getPrincipal(),
              annotation,
              targetNodeName,
              false);

      returnAction.recordAction();
    }
  }