@Test
  public void testAdhocApproversJoinScenario() throws Exception {
    WorkflowDocument document =
        WorkflowDocumentFactory.createDocument(
            getPrincipalIdForName("ewestfal"), "AdHocApproversDocType");
    document.route("");

    // should send an approve to bmcgough
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("bmcgough"), document.getDocumentId());
    assertTrue("Bmcgough should have approve request.", document.isApprovalRequested());
    document.approve("");

    // at this point the document should pass the split, and end up at the WorkflowDocument2 node
    // and the AdHocApproversJoin node
    // after bypassing the AdHocJoinPoint
    Set<String> nodeNames = document.getNodeNames();
    assertEquals("There should be two node names.", 2, nodeNames.size());
    assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("WorkflowDocument2"));
    assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("AdHocApproversJoin"));

    // pmckown has the request at the adhoc approvers node, if we approve as him then the document
    // should _not_ transition out
    // of it's current nodes
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("pmckown"), document.getDocumentId());
    assertTrue("Pmckown should have approve request.", document.isApprovalRequested());
    document.approve("");

    // the document should still be at the same nodes
    nodeNames = document.getNodeNames();
    assertEquals("There should be two node names.", 2, nodeNames.size());
    assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("WorkflowDocument2"));
    assertTrue("Should be at WorkflowDocument2 node.", nodeNames.contains("AdHocApproversJoin"));

    // at WorkflowDocument2, rkirkend is the approver, if we approve as him we should end up at the
    // WorkflowDocumentFinal node
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("rkirkend"), document.getDocumentId());
    assertTrue("Rkirkend should have approve request.", document.isApprovalRequested());
    document.approve("");

    // the document should now be at WorkflowDocumentFinal with a request to xqi
    nodeNames = document.getNodeNames();
    assertEquals("There should be one node name.", 1, nodeNames.size());
    assertTrue(
        "Should be at WorkflowDocumentFinal node.", nodeNames.contains("WorkflowDocumentFinal"));

    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("xqi"), document.getDocumentId());
    assertTrue("Document should still be enroute.", document.isEnroute());
    document.approve("");
    assertTrue("Document should now be final.", document.isFinal());
  }
  /**
   * Tests that an exception is thrown if you try to execute a "route" command on an already routed
   * document.
   */
  @Test
  public void testRouteAlreadyRoutedDocument() throws Exception {
    WorkflowDocument document =
        WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), DOCUMENT_TYPE_NAME);
    document.route("");

    assertTrue("Document should be ENROUTE.", document.isEnroute());
    assertFalse("There should not be a request to ewestfal.", document.isApprovalRequested());

    // verify that only 1 action taken has been performed
    Collection<ActionTakenValue> actionTakens =
        KEWServiceLocator.getActionTakenService().findByDocumentId(document.getDocumentId());
    assertEquals("There should be only 1 action taken.", 1, actionTakens.size());

    // now try and route the document again, an exception should be thrown
    try {
      document.route("");
      fail("A WorkflowException should have been thrown.");
    } catch (InvalidActionTakenException e) {
      e.printStackTrace();
    }

    // verify that there is still only 1 action taken (the transaction above should have rolled
    // back)
    actionTakens =
        KEWServiceLocator.getActionTakenService().findByDocumentId(document.getDocumentId());
    assertEquals("There should still be only 1 action taken.", 1, actionTakens.size());
  }
  @Override
  public boolean canEditDocumentOverview(Document document) {
    WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
    Set<String> nodeNames = workflowDocument.getCurrentNodeNames();

    return workflowDocument.isEnroute()
        && CollectionUtils.isNotEmpty(nodeNames)
        && nodeNames.contains(KFSConstants.RouteLevelNames.ACCOUNT_REVIEW_FULL_EDIT)
        && workflowDocument.isApprovalRequested()
        && !workflowDocument.isAcknowledgeRequested();
  }
  /**
   * Tests that the document route past the join properly when there are parallel branches that
   * don't generate requests. This was coded in response to a bug found while testing with ERA in
   * order to track it down and fix it.
   */
  @Test
  public void testEmptyParallelBranches() throws Exception {

    WorkflowDocument document =
        WorkflowDocumentFactory.createDocument(
            getPrincipalIdForName("ewestfal"), PARALLEL_EMPTY_DOCUMENT_TYPE_NAME);
    document.saveDocumentData();
    assertTrue("Document should be initiated", document.isInitiated());
    assertEquals("Should be no action requests.", 0, document.getRootActionRequests().size());
    Collection<? extends Object> nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
    document.route("");

    // should have generated a request to "bmcgough"
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("bmcgough"), document.getDocumentId());
    assertTrue("Document should be enroute", document.isEnroute());
    List<ActionRequestValue> actionRequests =
        KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
    assertEquals("Incorrect pending action requests.", 1, actionRequests.size());
    ActionRequestValue bRequest = actionRequests.get(0);
    assertNotNull("Should have been routed through node instance.", bRequest.getNodeInstance());
    assertTrue(document.isApprovalRequested());

    document.approve("");

    // now the document should have split, passed through nodes in each branch which didn't generate
    // requests,
    // and then passed the join node and generated requests at WorkflowDocumentFinal
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("xqi"), document.getDocumentId());
    assertTrue("Document should be enroute", document.isEnroute());
    assertTrue(document.isApprovalRequested());
  }
  @Test
  public void testParallelRoute() throws Exception {
    WorkflowDocument document =
        WorkflowDocumentFactory.createDocument(
            getPrincipalIdForName("ewestfal"), DOCUMENT_TYPE_NAME);
    document.saveDocumentData();
    assertTrue("Document should be initiated", document.isInitiated());
    assertEquals("Should be no action requests.", 0, document.getRootActionRequests().size());
    Collection<RouteNodeInstance> nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
    document.route("Routing for parallel");

    // should have generated a request to "bmcgough"
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("bmcgough"), document.getDocumentId());
    assertTrue("Document should be enroute", document.isEnroute());
    List<ActionRequestValue> actionRequests =
        KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
    assertEquals("Incorrect pending action requests.", 1, actionRequests.size());
    ActionRequestValue bRequest = actionRequests.get(0);
    assertNotNull("Should have been routed through node instance.", bRequest.getNodeInstance());
    assertTrue(document.isApprovalRequested());

    document.approve("Approving test");

    // document should split at this point and generate an ack to temay and approves to rkirkend and
    // pmckown
    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("rkirkend"), document.getDocumentId());
    assertTrue("Document should be enroute", document.isEnroute());
    actionRequests =
        KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId());
    assertEquals("Incorrect pending action requests.", 3, actionRequests.size());
    boolean isToTemay = false;
    boolean isToPmckown = false;
    boolean isToRkirkend = false;
    for (Iterator iterator = actionRequests.iterator(); iterator.hasNext(); ) {
      ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
      if (actionRequest.getPrincipalId().equals(getPrincipalIdForName("temay"))) {
        isToTemay = true;
        assertEquals(
            "Request should be activated.",
            ActionRequestStatus.ACTIVATED.getCode(),
            actionRequest.getStatus());
        assertEquals(
            "Wrong action requested.",
            KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ,
            actionRequest.getActionRequested());
        assertNotNull(
            "Should have been routed through node instance.", actionRequest.getNodeInstance());
        assertEquals(
            "Invalid node.",
            ACKNOWLEDGE_1_NODE,
            actionRequest.getNodeInstance().getRouteNode().getRouteNodeName());
      }
      if (actionRequest.getPrincipalId().equals(getPrincipalIdForName("rkirkend"))) {
        isToRkirkend = true;
        assertEquals(
            "Request should be activated.",
            ActionRequestStatus.ACTIVATED.getCode(),
            actionRequest.getStatus());
        assertEquals(
            "Wrong action requested.",
            KewApiConstants.ACTION_REQUEST_APPROVE_REQ,
            actionRequest.getActionRequested());
        assertNotNull(
            "Should have been routed through node instance.", actionRequest.getNodeInstance());
        assertEquals(
            "Invalid node.",
            WORKFLOW_DOCUMENT_2_NODE,
            actionRequest.getNodeInstance().getRouteNode().getRouteNodeName());
      }
      if (actionRequest.getPrincipalId().equals(getPrincipalIdForName("pmckown"))) {
        isToPmckown = true;
        assertEquals(
            "Request should be activated.",
            ActionRequestStatus.ACTIVATED.getCode(),
            actionRequest.getStatus());
        assertEquals(
            "Wrong action requested.",
            KewApiConstants.ACTION_REQUEST_APPROVE_REQ,
            actionRequest.getActionRequested());
        assertNotNull(
            "Should have been routed through node instance.", actionRequest.getNodeInstance());
        assertEquals(
            "Invalid node.",
            WORKFLOW_DOCUMENT_3_NODE,
            actionRequest.getNodeInstance().getRouteNode().getRouteNodeName());
      }
    }
    assertTrue("No request to temay.", isToTemay);
    assertTrue("No request to pmckown.", isToPmckown);
    assertTrue("No request to rkirkend.", isToRkirkend);

    // check that we are at both nodes, one in each branch
    Set<String> nodeNames = document.getNodeNames();
    assertEquals("Wrong number of node names.", 2, nodeNames.size());
    boolean isNode2 = false;
    boolean isNode3 = false;
    for (String name : nodeNames) {
      if (name.equals(WORKFLOW_DOCUMENT_2_NODE)) {
        isNode2 = true;
      }
      if (name.equals(WORKFLOW_DOCUMENT_3_NODE)) {
        isNode3 = true;
      }
    }
    assertTrue("Not at node2.", isNode2);
    assertTrue("Not at node3.", isNode3);
    nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals("Wrong number of active nodes.", 2, nodeInstances.size());
    Iterator<RouteNodeInstance> iterator = nodeInstances.iterator();
    RouteNodeInstance instance1 = (RouteNodeInstance) iterator.next();
    RouteNodeInstance instance2 = (RouteNodeInstance) iterator.next();
    assertNotNull("Node should be in branch.", instance1.getBranch());
    assertNotNull("Node should be in branch.", instance2.getBranch());
    assertTrue(
        "Branches should be different.",
        !instance1.getBranch().getBranchId().equals(instance2.getBranch().getBranchId()));

    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("rkirkend"), document.getDocumentId());
    assertTrue("Should have request.", document.isApprovalRequested());
    document.approve("Git-r-dun");

    nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals("Wrong number of active nodes.", 2, nodeInstances.size());
    boolean isAtJoin = false;
    boolean isAtWD3 = false;
    for (RouteNodeInstance nodeInstance : nodeInstances) {
      if (nodeInstance.getRouteNode().getRouteNodeName().equals(JOIN_NODE)) {
        assertEquals(
            "Join branch should be split branch.",
            instance1.getBranch().getParentBranch().getBranchId(),
            nodeInstance.getBranch().getBranchId());
        isAtJoin = true;
      }
      if (nodeInstance.getRouteNode().getRouteNodeName().equals(WORKFLOW_DOCUMENT_3_NODE)) {
        isAtWD3 = true;
      }
    }
    assertTrue("Not at join", isAtJoin);
    assertTrue("Not at WD3", isAtWD3);

    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("pmckown"), document.getDocumentId());
    assertTrue("Should have request.", document.isApprovalRequested());
    document.approve("Do it.");

    nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals("Wrong number of active nodes.", 1, nodeInstances.size());
    boolean isAtWDF = false;
    for (RouteNodeInstance nodeInstance : nodeInstances) {
      if (nodeInstance.getRouteNode().getRouteNodeName().equals(WORKFLOW_DOCUMENT_FINAL_NODE)) {
        isAtWDF = true;
      }
    }
    assertTrue("Not at WDF", isAtWDF);

    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("xqi"), document.getDocumentId());
    assertTrue("Should still be enroute.", document.isEnroute());
    assertTrue("Should have request.", document.isApprovalRequested());
    document.approve("I'm the last approver");

    assertTrue("Document should be processed.", document.isProcessed());
    nodeInstances =
        KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId());
    assertEquals(
        "The doc is processed so no node instances should be active", 0, nodeInstances.size());

    document =
        WorkflowDocumentFactory.loadDocument(
            getPrincipalIdForName("temay"), document.getDocumentId());
    assertTrue("Should have request.", document.isAcknowledgeRequested());
    document.acknowledge("");
    assertTrue(document.isFinal());
  }