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    }