001 /** 002 * Copyright 2005-2011 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.rice.kew.engine; 017 018 019 import static org.junit.Assert.assertEquals; 020 import static org.junit.Assert.assertNotNull; 021 import static org.junit.Assert.assertNull; 022 import static org.junit.Assert.assertTrue; 023 024 import java.util.Collection; 025 import java.util.List; 026 027 import org.junit.Test; 028 import org.kuali.rice.kew.api.WorkflowDocument; 029 import org.kuali.rice.kew.api.WorkflowDocumentFactory; 030 import org.kuali.rice.kew.engine.node.DynamicNode; 031 import org.kuali.rice.kew.engine.node.DynamicResult; 032 import org.kuali.rice.kew.engine.node.NodeState; 033 import org.kuali.rice.kew.engine.node.RouteNode; 034 import org.kuali.rice.kew.engine.node.RouteNodeInstance; 035 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 036 import org.kuali.rice.kew.service.KEWServiceLocator; 037 import org.kuali.rice.kew.test.KEWTestCase; 038 039 040 public class DynamicRoutingTest extends KEWTestCase { 041 042 private static final String SEQ_DOC_TYPE_NAME = "DynSeqDocType"; 043 private static final String INIT = "Initial"; 044 private static final String FIRST = "First"; 045 private static final String DYNAMIC_SEQ = "DynSeq"; 046 private static final String SUB_REQUESTS = "SubRequests"; 047 private static final String LAST = "Last"; 048 049 protected void loadTestData() throws Exception { 050 loadXmlFile("EngineConfig.xml"); 051 } 052 053 @Test public void testDynamicParallelRoute() throws Exception { 054 WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), SEQ_DOC_TYPE_NAME); 055 document.saveDocumentData(); 056 assertTrue("Document should be initiated", document.isInitiated()); 057 assertEquals("Should be no action requests.", 0, document.getRootActionRequests().size()); 058 Collection nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId()); 059 assertEquals("Wrong number of active nodes.", 1, nodeInstances.size()); 060 assertEquals("Wrong active node.", INIT, ((RouteNodeInstance) nodeInstances.iterator().next()).getRouteNode().getRouteNodeName()); 061 document.route(""); 062 063 document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("bmcgough"), document.getDocumentId()); 064 assertTrue("Approve should be requested.", document.isApprovalRequested()); 065 document.approve(""); 066 067 nodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(document.getDocumentId()); 068 assertEquals("Wrong number of active nodes.", 1, nodeInstances.size()); 069 document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("pmckown"), document.getDocumentId()); 070 assertTrue("Approve should be requested.", document.isApprovalRequested()); 071 document.approve(""); 072 073 document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("temay"), document.getDocumentId()); 074 assertTrue("Approve should be requested.", document.isApprovalRequested()); 075 document.approve(""); 076 077 document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("jhopf"), document.getDocumentId()); 078 assertTrue("Approve should be requested.", document.isApprovalRequested()); 079 document.approve(""); 080 081 document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), document.getDocumentId()); 082 assertTrue("Approve should be requested.", document.isApprovalRequested()); 083 document.approve(""); 084 085 // document = WorkflowDocumentFactory.loadDocument(new NetworkIdVO("ewestfal"), document.getDocumentId()); 086 // assertTrue("Document should be final.", document.isFinal()); 087 088 verifyRoutingPath(document.getDocumentId()); 089 } 090 091 private void verifyRoutingPath(String documentId) { 092 DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId); 093 List initial = document.getInitialRouteNodeInstances(); 094 assertEquals(1, initial.size()); 095 RouteNodeInstance init = (RouteNodeInstance) initial.get(0); 096 assertEquals(INIT, init.getRouteNode().getRouteNodeName()); 097 assertEquals(0, init.getPreviousNodeInstances().size()); 098 099 List next = init.getNextNodeInstances(); 100 assertEquals(1, next.size()); 101 RouteNodeInstance first = (RouteNodeInstance) next.get(0); 102 assertEquals(FIRST, first.getRouteNode().getRouteNodeName()); 103 assertEquals(1, first.getPreviousNodeInstances().size()); 104 105 next = first.getNextNodeInstances(); 106 assertEquals(1, next.size()); 107 RouteNodeInstance pmckownNode = (RouteNodeInstance) next.get(0); 108 assertEquals(SUB_REQUESTS, pmckownNode.getRouteNode().getRouteNodeName()); 109 assertEquals(1, pmckownNode.getPreviousNodeInstances().size()); 110 assertInSubProcess(pmckownNode); 111 112 next = pmckownNode.getNextNodeInstances(); 113 assertEquals(1, next.size()); 114 RouteNodeInstance temayNode = (RouteNodeInstance) next.get(0); 115 assertEquals(SUB_REQUESTS, temayNode.getRouteNode().getRouteNodeName()); 116 assertEquals(1, temayNode.getPreviousNodeInstances().size()); 117 assertInSubProcess(temayNode); 118 119 next = temayNode.getNextNodeInstances(); 120 assertEquals(1, next.size()); 121 RouteNodeInstance jhopfNode = (RouteNodeInstance) next.get(0); 122 assertEquals(SUB_REQUESTS, jhopfNode.getRouteNode().getRouteNodeName()); 123 assertEquals(1, jhopfNode.getPreviousNodeInstances().size()); 124 assertInSubProcess(jhopfNode); 125 126 next = jhopfNode.getNextNodeInstances(); 127 assertEquals(1, next.size()); 128 RouteNodeInstance last = (RouteNodeInstance) next.get(0); 129 assertNull(last.getProcess()); 130 assertEquals(LAST, last.getRouteNode().getRouteNodeName()); 131 assertEquals(1, last.getPreviousNodeInstances().size()); 132 assertEquals(0, last.getNextNodeInstances().size()); 133 } 134 135 private void assertInSubProcess(RouteNodeInstance nodeInstance) { 136 RouteNodeInstance subProcess = nodeInstance.getProcess(); 137 assertNotNull(subProcess); 138 assertEquals(DYNAMIC_SEQ, subProcess.getRouteNode().getRouteNodeName()); 139 } 140 141 public static class MockSequentialDynamicNode implements DynamicNode { 142 143 public DynamicResult transitioningInto(RouteContext context, RouteNodeInstance process, RouteHelper helper) throws Exception { 144 RouteNodeInstance routeNodeInstance = context.getNodeInstance(); 145 RouteNode dynamicRequestNode = helper.getNodeFactory().getRouteNode(context, SUB_REQUESTS); 146 RouteNodeInstance dynamicRequestNodeInstance1 = helper.getNodeFactory().createRouteNodeInstance(context.getDocument().getDocumentId(), dynamicRequestNode); 147 dynamicRequestNodeInstance1.addNodeState(new NodeState("role", "pmckown")); 148 RouteNodeInstance dynamicRequestNodeInstance2 = helper.getNodeFactory().createRouteNodeInstance(context.getDocument().getDocumentId(), dynamicRequestNode); 149 dynamicRequestNodeInstance2.addNodeState(new NodeState("role", "temay")); 150 RouteNodeInstance dynamicRequestNodeInstance3 = helper.getNodeFactory().createRouteNodeInstance(context.getDocument().getDocumentId(), dynamicRequestNode); 151 dynamicRequestNodeInstance3.addNodeState(new NodeState("role", "jhopf")); 152 dynamicRequestNodeInstance1.addNextNodeInstance(dynamicRequestNodeInstance2); 153 dynamicRequestNodeInstance2.addNextNodeInstance(dynamicRequestNodeInstance3); 154 routeNodeInstance.addNodeState(new NodeState("beenHere", "val")); 155 return new DynamicResult(true, dynamicRequestNodeInstance1); 156 } 157 158 public DynamicResult transitioningOutOf(RouteContext context, RouteHelper helper) throws Exception { 159 return new DynamicResult(true, null); 160 } 161 } 162 }