@Override public List<String> buildListForFYI(AwardDocument awardDocument) throws WorkflowException { WorkflowDocument document = awardDocument.getDocumentHeader().getWorkflowDocument(); RoutingReportCriteria reportCriteria = RoutingReportCriteria.Builder.createByDocumentId(document.getDocumentId()).build(); // gather the IDs for action requests that predate the simulation DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId()); Set<String> preexistingActionRequestIds = getActionRequestIds(routeHeader); // run the simulation via WorkflowUtility DocumentDetail documentDetail = workflowUtility.executeSimulation(reportCriteria); // fabricate our ActionRequestValueS from the results List<ActionRequestValue> actionRequests = reconstituteActionRequestValues(documentDetail, preexistingActionRequestIds); List<String> actionIds = new ArrayList<String>(); for (ActionRequestValue request : actionRequests) { if (request.isGroupRequest()) { actionIds.addAll( KimApiServiceLocator.getGroupService().getMemberPrincipalIds(request.getGroupId())); } if (request.isUserRequest()) { actionIds.add(request.getPrincipalId()); } } return actionIds; }
/** * Tests that an exception is not thrown if you try to execute a "route" command on a document you * did not initiate. */ @Test public void testRouteDocumentAsNonInitiatorUser() throws Exception { WorkflowDocument firstDocument = WorkflowDocumentFactory.createDocument( getPrincipalIdForName("user1"), DOCUMENT_TYPE_POLICY_TEST_NAME); WorkflowDocument document = WorkflowDocumentFactory.loadDocument( getPrincipalIdForName("user2"), firstDocument.getDocumentId()); try { document.route(""); } catch (Exception e) { e.printStackTrace(); fail( "Exception thrown but should not have have been... Exception was of type " + e.getClass().getName() + " and message was " + e.getMessage()); } document = WorkflowDocumentFactory.loadDocument( getPrincipalIdForName("user1"), firstDocument.getDocumentId()); assertEquals( "Document should be in Enroute status.", DocumentStatus.ENROUTE, document.getStatus()); // verify that there is 1 action taken Collection<ActionTakenValue> actionTakens = KEWServiceLocator.getActionTakenService().findByDocumentId(document.getDocumentId()); assertEquals("There should be 1 action taken.", 1, actionTakens.size()); }
/** * 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()); }
@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()); }
/** * @see * org.kuali.rice.ken.service.NotificationWorkflowDocumentService#terminateWorkflowDocument(org.kuali.rice.kew.api.WorkflowDocument) */ public void terminateWorkflowDocument(WorkflowDocument document) { document.superUserCancel( "terminating document: documentId=" + document.getDocumentId() + ", appDocId=" + document.getApplicationDocumentId()); }
/** * Test the approval of a protocol. The protocol status and its corresponding action should be set * to approved. */ @Test public void runApprovedTest() throws Exception { ProtocolDocument protocolDocument = ProtocolFactory.createProtocolDocument(); protocolSubmitActionService.submitToIrbForReview( protocolDocument.getProtocol(), getMockSubmitAction()); documentService.routeDocument(protocolDocument, null, null); documentService.blanketApproveDocument(protocolDocument, null, null); WorkflowDocument workflowDoc = getWorkflowDocument(protocolDocument); WorkflowDocumentActionsService info = GlobalResourceLoader.getService("rice.kew.workflowDocumentActionsService"); RoutingReportCriteria.Builder reportCriteriaBuilder = RoutingReportCriteria.Builder.createByDocumentId(workflowDoc.getDocumentId()); DocumentDetail results1 = info.executeSimulation(reportCriteriaBuilder.build()); assertTrue(workflowDoc.isFinal()); // the status update is not happening within doRouteStatusChange anymore // assertEquals(protocolDocument.getProtocol().getProtocolStatusCode(), // ProtocolStatus.ACTIVE_OPEN_TO_ENROLLMENT); assertTrue(protocolDocument.getProtocol().isActive()); // verifyProtocolAction(protocolDocument.getProtocol().getProtocolId(), // ProtocolActionType.APPROVED); }
public ProtocolOnlineReviewDocumentBase createProtocolOnlineReviewDocument( ProtocolSubmissionBase protocolSubmission, ProtocolReviewer protocolReviewer, String documentDescription, String documentExplanation, String documentOrganizationDocumentNumber, Date dateRequested, Date dateDue, String principalId) throws WorkflowException { IacucProtocolOnlineReviewDocument protocolReviewDocument; Person person = personService.getPerson(principalId); WorkflowDocument workflowDocument = workflowDocumentService.createWorkflowDocument( IACUC_PROTOCOL_ONLINE_REVIEW_DOCUMENT_TYPE, person); DocumentHeader docHeader = new DocumentHeader(); docHeader.setWorkflowDocument(workflowDocument); docHeader.setDocumentNumber(workflowDocument.getDocumentId().toString()); protocolReviewDocument = new IacucProtocolOnlineReviewDocument(); protocolReviewDocument.setDocumentNumber(docHeader.getDocumentNumber()); protocolReviewDocument.setDocumentHeader(docHeader); protocolReviewDocument.getProtocolOnlineReview().setProtocol(protocolSubmission.getProtocol()); protocolReviewDocument .getProtocolOnlineReview() .setProtocolId(protocolSubmission.getProtocolId()); protocolReviewDocument.getProtocolOnlineReview().setProtocolSubmission(protocolSubmission); protocolReviewDocument .getProtocolOnlineReview() .setSubmissionIdFk(protocolSubmission.getSubmissionId()); protocolReviewDocument .getProtocolOnlineReview() .setProtocolOnlineReviewStatusCode(IacucProtocolOnlineReviewStatus.SAVED_STATUS_CD); protocolReviewDocument .getProtocolOnlineReview() .setDateRequested( dateRequested == null ? new Date((new java.util.Date()).getTime()) : dateRequested); protocolReviewDocument.getProtocolOnlineReview().setDateDue(dateDue); protocolReviewDocument .getProtocolOnlineReview() .setProtocolReviewerId(protocolReviewer.getProtocolReviewerId()); protocolReviewDocument.getProtocolOnlineReview().setProtocolReviewer(protocolReviewer); docHeader.setDocumentDescription(documentDescription); docHeader.setOrganizationDocumentNumber(documentOrganizationDocumentNumber); docHeader.setExplanation(documentExplanation); documentService.saveDocument(protocolReviewDocument); return protocolReviewDocument; }
/** * Creates a new ProtocolReviewDocument. * * <p>Handles creating the workflow document, and the underlying ProtocolReview BO linking the * protocol, submission, and reviewer. * * @param protocolSubmission The protocol submission * @param protocolReviewerBean The bean that holds * @param documentDescription the description for the created document * @param documentExplanation the explanation for the created document * @param documentOrganizationNumber the organizationNumber for the created document * @param principalId The principalId to use when creating the workflow document. Usually this * should be the principal of the user creating the review. * @return * @throws WorkflowException */ protected ProtocolOnlineReviewDocumentBase createProtocolOnlineReviewDocument( ProtocolSubmissionBase protocolSubmission, ProtocolReviewer protocolReviewer, String documentDescription, String documentExplanation, String documentOrganizationDocumentNumber, Date dateRequested, Date dateDue, String principalId) throws WorkflowException { ProtocolOnlineReviewDocumentBase protocolReviewDocument; Person person = personService.getPerson(principalId); WorkflowDocument workflowDocument = workflowDocumentService.createWorkflowDocument(getProtocolOLRDocumentTypeHook(), person); DocumentHeader docHeader = new DocumentHeader(); docHeader.setWorkflowDocument(workflowDocument); docHeader.setDocumentNumber(workflowDocument.getDocumentId().toString()); protocolReviewDocument = getNewProtocolOnlineReviewDocumentInstanceHook(); protocolReviewDocument.setDocumentNumber(docHeader.getDocumentNumber()); protocolReviewDocument.setDocumentHeader(docHeader); protocolReviewDocument.getProtocolOnlineReview().setProtocol(protocolSubmission.getProtocol()); protocolReviewDocument .getProtocolOnlineReview() .setProtocolId(protocolSubmission.getProtocolId()); protocolReviewDocument.getProtocolOnlineReview().setProtocolSubmission(protocolSubmission); protocolReviewDocument .getProtocolOnlineReview() .setSubmissionIdFk(protocolSubmission.getSubmissionId()); protocolReviewDocument .getProtocolOnlineReview() .setProtocolOnlineReviewStatusCode(getProtocolOLRSavedStatusCodeHook()); protocolReviewDocument .getProtocolOnlineReview() .setDateRequested( dateRequested == null ? new Date((new java.util.Date()).getTime()) : dateRequested); protocolReviewDocument.getProtocolOnlineReview().setDateDue(dateDue); protocolReviewDocument .getProtocolOnlineReview() .setProtocolReviewerId(protocolReviewer.getProtocolReviewerId()); protocolReviewDocument.getProtocolOnlineReview().setProtocolReviewer(protocolReviewer); docHeader.setDocumentDescription(documentDescription); docHeader.setOrganizationDocumentNumber(documentOrganizationDocumentNumber); docHeader.setExplanation(documentExplanation); documentService.saveDocument(protocolReviewDocument); return protocolReviewDocument; }
/** * 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()); }
/** * @see * org.kuali.rice.ken.service.NotificationWorkflowDocumentService#clearAllFyisAndAcknowledgeNotificationWorkflowDocument(java.lang.String, * org.kuali.rice.ken.document.kew.NotificationWorkflowDocument, java.lang.String) */ public void clearAllFyisAndAcknowledgeNotificationWorkflowDocument( String initiatorUserId, WorkflowDocument workflowDocument, String annotation) { List<ActionRequest> reqs = workflowDocument.getRootActionRequests(); for (int i = 0; i < reqs.size(); i++) { LOG.info("Action Request[" + i + "] = " + reqs.get(i).getActionRequested()); if (reqs.get(i).getActionRequested().equals(ActionRequestType.ACKNOWLEDGE)) { workflowDocument.acknowledge(annotation); } else if (reqs.get(i).getActionRequested().equals(ActionRequestType.FYI)) { workflowDocument.logAnnotation(annotation); workflowDocument.fyi(); } else { throw new WorkflowRuntimeException( "Invalid notification action request in workflow document (" + workflowDocument.getDocumentId() + ") was encountered. Should be either an acknowledge or fyi and was not."); } } }
/** * Tests that an exception is not thrown if you try to execute a "route" command on a document you * did not initiate. */ @Test public void testRouteDefaultDocumentAsNonInitiatorUser() throws Exception { WorkflowDocument firstDocument = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), DOCUMENT_TYPE_NAME); WorkflowDocument document = WorkflowDocumentFactory.loadDocument( getPrincipalIdForName("user2"), firstDocument.getDocumentId()); try { document.route(""); fail("Exception should have been thrown."); } catch (Exception e) { e.printStackTrace(); } assertFalse("Document should not be ENROUTE.", document.isEnroute()); // assertFalse("There should not be a request to user2.", // document.isApprovalRequested()); // // // verify that there are no actions taken // Collection actionTakens = // KEWServiceLocator.getActionTakenService().findByDocumentId(document.getDocumentId()); // assertEquals("There should be 0 actions taken.", 0, actionTakens.size()); }
/** * Creates a new document by document type name. The principal name passed in will be used as the * document initiator. If the initiatorPrincipalNm is null or blank, the current user will be * used. * * @see org.kuali.rice.krad.service.DocumentService#getNewDocument(String, String) */ @Override public Document getNewDocument(String documentTypeName, String initiatorPrincipalNm) throws WorkflowException { // argument validation String watchName = "DocumentServiceImpl.getNewDocument"; StopWatch watch = new StopWatch(); watch.start(); if (LOG.isDebugEnabled()) { LOG.debug(watchName + ": started"); } if (StringUtils.isBlank(documentTypeName)) { throw new IllegalArgumentException("invalid (blank) documentTypeName"); } if (GlobalVariables.getUserSession() == null) { throw new IllegalStateException( "GlobalVariables must be populated with a valid UserSession before a new document can be created"); } // get the class for this docTypeName Class<? extends Document> documentClass = getDocumentClassByTypeName(documentTypeName); // get the initiator Person initiator = null; if (StringUtils.isBlank(initiatorPrincipalNm)) { initiator = GlobalVariables.getUserSession().getPerson(); } else { initiator = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(initiatorPrincipalNm); if (initiator == null) { initiator = GlobalVariables.getUserSession().getPerson(); } } // get the authorization DocumentAuthorizer documentAuthorizer = getDocumentDictionaryService().getDocumentAuthorizer(documentTypeName); DocumentPresentationController documentPresentationController = getDocumentDictionaryService().getDocumentPresentationController(documentTypeName); // make sure this person is authorized to initiate if (LOG.isDebugEnabled()) { LOG.debug( "calling canInitiate from getNewDocument(" + documentTypeName + "," + initiatorPrincipalNm + ")"); } if (!documentPresentationController.canInitiate(documentTypeName) || !documentAuthorizer.canInitiate(documentTypeName, initiator)) { throw new DocumentAuthorizationException( initiator.getPrincipalName(), "initiate", documentTypeName); } // initiate new workflow entry, get the workflow doc WorkflowDocument workflowDocument = getWorkflowDocumentService().createWorkflowDocument(documentTypeName, initiator); UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(), workflowDocument); // create a new document header object DocumentHeader documentHeader = new DocumentHeader(); documentHeader.setWorkflowDocument(workflowDocument); documentHeader.setDocumentNumber(workflowDocument.getDocumentId()); // build Document of specified type Document document = null; try { // all maintenance documents have same class if (MaintenanceDocumentBase.class.isAssignableFrom(documentClass)) { Class<?>[] defaultConstructor = new Class[] {String.class}; Constructor<? extends Document> cons = documentClass.getConstructor(defaultConstructor); if (cons == null) { throw new ConfigurationException( "Could not find constructor with document type name parameter needed for Maintenance Document Base class"); } document = cons.newInstance(documentTypeName); } else { // non-maintenance document document = documentClass.newInstance(); } } catch (IllegalAccessException e) { throw new RuntimeException("Error instantiating Document", e); } catch (InstantiationException e) { throw new RuntimeException("Error instantiating Document", e); } catch (SecurityException e) { throw new RuntimeException("Error instantiating Maintenance Document", e); } catch (NoSuchMethodException e) { throw new RuntimeException( "Error instantiating Maintenance Document: No constructor with String parameter found", e); } catch (IllegalArgumentException e) { throw new RuntimeException("Error instantiating Maintenance Document", e); } catch (InvocationTargetException e) { throw new RuntimeException("Error instantiating Maintenance Document", e); } document.setDocumentHeader(documentHeader); document.setDocumentNumber(documentHeader.getDocumentNumber()); watch.stop(); if (LOG.isDebugEnabled()) { LOG.debug(watchName + ": " + watch.toString()); } return document; }
@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()); }
/** * Implements by instantiating a NotificationWorkflowDocument, which in turn interacts with * Workflow to set it up with an initiator of the passed in user id. * * @see * org.kuali.rice.ken.service.NotificationWorkflowDocumentService#createAndAdHocRouteNotificationWorkflowDocument(org.kuali.rice.ken.bo.NotificationMessageDelivery, * java.lang.String, java.lang.String, java.lang.String) */ public String createAndAdHocRouteNotificationWorkflowDocument( NotificationMessageDelivery messageDelivery, String initiatorUserId, String recipientUserId, String annotation) { // obtain a workflow user object first // WorkflowIdDTO initiator = new WorkflowIdDTO(initiatorUserId); // now construct the workflow document, which will interact with workflow WorkflowDocument document; if (StringUtils.isNotBlank(messageDelivery.getNotification().getDocTypeName())) { document = NotificationWorkflowDocument.createNotificationDocument( initiatorUserId, messageDelivery.getNotification().getDocTypeName()); } else { document = NotificationWorkflowDocument.createNotificationDocument(initiatorUserId); } // this is our loose foreign key to our message delivery record in notification document.setApplicationDocumentId(messageDelivery.getId().toString()); // document.setAppDocId(messageDelivery.getId().toString()); // now add the content of the notification as XML to the document document.setApplicationContent( messageContentService.generateNotificationMessage( messageDelivery.getNotification(), messageDelivery.getUserRecipientId())); if (!StringUtils.isBlank(messageDelivery.getNotification().getTitle())) { document.setTitle(messageDelivery.getNotification().getTitle()); } else { LOG.error( "Encountered notification with no title set: Message Delivery #" + messageDelivery.getId() + ", Notification #" + messageDelivery.getNotification().getId()); } // now set up the ad hoc route String actionRequested; if (NotificationConstants.DELIVERY_TYPES.ACK.equals( messageDelivery.getNotification().getDeliveryType())) { actionRequested = NotificationConstants.KEW_CONSTANTS.ACK_AD_HOC_ROUTE; } else { actionRequested = NotificationConstants.KEW_CONSTANTS.FYI_AD_HOC_ROUTE; } // Clarification of ad hoc route call // param 1 - actionRequested will be either ACK or FYI // param 2 - annotation is whatever text we pass in to describe the transaction - this will be // system generated // param 3 - recipient is the person who will receive this request // param 4 - this is the responsibilityParty (a.k.a the system that produced this request), so // we'll put the producer name in there // param 5 - this is the "force action" requests - if set to true, this will be delivered to the // recipients list regardless of // whether the recipient has already taken action on this request; in our case, this // doesn't really apply at this point in time, // so we'll set to true just to be safe // recipientUserId will always be a principal ID due to code changes in // NotificationMessageDeliveryResolverServiceImpl.buildCompleteRecipientList() Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(recipientUserId); document.adHocToPrincipal( ActionRequestType.fromCode(actionRequested), annotation, principal.getPrincipalId(), messageDelivery.getNotification().getProducer().getName(), true); // now actually route it along its way document.route(annotation); return document.getDocumentId(); }