View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    *
4    *
5    * Licensed under the Educational Community License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.opensource.org/licenses/ecl2.php
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.kuali.rice.kew.engine;
18  
19  import java.io.Serializable;
20  
21  import javax.xml.namespace.QName;
22  
23  import org.junit.Test;
24  import org.kuali.rice.kew.dto.NetworkIdDTO;
25  import org.kuali.rice.kew.engine.node.Branch;
26  import org.kuali.rice.kew.engine.node.BranchState;
27  import org.kuali.rice.kew.exception.WorkflowRuntimeException;
28  import org.kuali.rice.kew.messaging.MessageServiceNames;
29  import org.kuali.rice.kew.messaging.exceptionhandling.DocumentMessageExceptionHandler;
30  import org.kuali.rice.kew.postprocessor.DefaultPostProcessor;
31  import org.kuali.rice.kew.postprocessor.DocumentRouteStatusChange;
32  import org.kuali.rice.kew.postprocessor.ProcessDocReport;
33  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
34  import org.kuali.rice.kew.service.KEWServiceLocator;
35  import org.kuali.rice.kew.service.WorkflowDocument;
36  import org.kuali.rice.kew.test.KEWTestCase;
37  import org.kuali.rice.kew.test.TestUtilities;
38  import org.kuali.rice.kew.util.KEWConstants;
39  import org.kuali.rice.ksb.messaging.JavaServiceDefinition;
40  import org.kuali.rice.ksb.messaging.service.KSBJavaService;
41  import org.kuali.rice.ksb.service.KSBServiceLocator;
42  
43  
44  public class StandardWorkflowEngineTest extends KEWTestCase {
45  
46  	protected void loadTestData() throws Exception {
47  		loadXmlFile("EngineConfig.xml");
48  	}
49  
50  	/**
51  	 * Tests that the proper state is set up on the root branch in the document
52  	 * to indicate that both PROCESSED and FINAL callbacks have been made into
53  	 * the post processor.
54  	 */
55  	@Test public void testSystemBranchState() throws Exception {
56  		// route the document to final
57  		WorkflowDocument document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "SimpleDocType");
58  		document.routeDocument("");
59  		assertTrue("Document should be final.", document.stateIsFinal());
60  
61  		// now look at the branch state
62  		DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getRouteHeaderId());
63  		Branch rootBranch = routeHeader.getRootBranch();
64  		assertNotNull(rootBranch);
65  		BranchState processedBranchState = rootBranch.getBranchState(KEWConstants.POST_PROCESSOR_PROCESSED_KEY);
66  		BranchState finalBranchState = rootBranch.getBranchState(KEWConstants.POST_PROCESSOR_FINAL_KEY);
67  		assertNotNull(processedBranchState);
68  		assertNotNull(finalBranchState);
69  		assertEquals("true", processedBranchState.getValue());
70  		assertEquals("true", finalBranchState.getValue());
71  		assertEquals(1, TestPostProcessor.processedCount);
72  		assertEquals(1, TestPostProcessor.finalCount);
73  	}
74  
75  	/**
76  	 * Tests that a FINAL document can go into exception routing and recover
77  	 * properly while only calling the PROCESSED and FINAL callbacks once.
78  	 */
79  	@Test public void testFinalDocumentExceptionRoutingRecovery() throws Exception {
80  
81  		// route the document to final
82  		WorkflowDocument document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "SimpleDocType");
83  		document.routeDocument("");
84  		assertTrue("Document should be final.", document.stateIsFinal());
85  		assertEquals(1, TestPostProcessor.processedCount);
86  		assertEquals(1, TestPostProcessor.finalCount);
87  
88  		// now queue up an exploder which should push the document into
89  		// exception routing
90  		JavaServiceDefinition serviceDef = new JavaServiceDefinition();
91  		serviceDef.setPriority(new Integer(1));
92  		serviceDef.setQueue(true);
93  		serviceDef.setRetryAttempts(0);
94  		serviceDef.setServiceInterface(KSBJavaService.class.getName());
95  		serviceDef.setServiceName(new QName("KEW", "exploader"));
96  		serviceDef.setService(new ImTheExploderProcessor());
97  
98  		serviceDef.setMessageExceptionHandler(DocumentMessageExceptionHandler.class.getName());
99  		serviceDef.validate();
100 		KSBServiceLocator.getServiceDeployer().registerService(serviceDef, true);
101 
102 		KSBJavaService exploderAsService = (KSBJavaService) MessageServiceNames.getServiceAsynchronously(new QName("KEW", "exploader"), KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getRouteHeaderId()));
103 		exploderAsService.invoke("");
104 		// we need to make the exploder a service to get this going again...
105 		// SpringServiceLocator.getRouteQueueService().requeueDocument(document.getRouteHeaderId(),
106 		// ImTheExploderProcessor.class.getName());
107 		// fail("Should have exploded!!!");
108 		TestUtilities.waitForExceptionRouting();
109 
110 		// the document should be in exception routing now
111 		document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), document.getRouteHeaderId());
112 		assertTrue("Document should be in exception routing.", document.stateIsException());
113 		assertEquals(1, TestPostProcessor.processedCount);
114 		assertEquals(1, TestPostProcessor.finalCount);
115 
116 		assertTrue("ewestfal should have a complete request.", document.isCompletionRequested());
117 		document.complete("");
118 
119 		// the document should be final once again
120 		document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), document.getRouteHeaderId());
121 		assertTrue("Document should be final.", document.stateIsFinal());
122 		assertEquals(1, TestPostProcessor.processedCount);
123 		assertEquals(1, TestPostProcessor.finalCount);
124 	}
125 
126 	public void tearDown() throws Exception {
127 	    try {
128 		TestPostProcessor.resetProcessedCount();
129 		TestPostProcessor.resetFinalCount();
130 	    } finally {
131 		super.tearDown();
132 	    }
133 	}
134 
135 	public static class TestPostProcessor extends DefaultPostProcessor {
136 
137 		public static int finalCount = 0;
138 
139 		public static int processedCount = 0;
140 
141 		public ProcessDocReport doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) throws Exception {
142 			if (KEWConstants.ROUTE_HEADER_PROCESSED_CD.equals(statusChangeEvent.getNewRouteStatus())) {
143 				processedCount++;
144 			} else if (KEWConstants.ROUTE_HEADER_FINAL_CD.equals(statusChangeEvent.getNewRouteStatus())) {
145 				finalCount++;
146 			}
147 			return new ProcessDocReport(true);
148 		}
149 
150 		public static void resetProcessedCount() {
151 			processedCount = 0;
152 		}
153 
154 		public static void resetFinalCount() {
155 			finalCount = 0;
156 		}
157 	}
158 
159 	public static class ImTheExploderProcessor implements KSBJavaService {
160 
161 		public void invoke(Serializable payLoad) {
162 			throw new WorkflowRuntimeException("I'm the Exploder!!!");
163 		}
164 
165 	}
166 
167 }