View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.engine;
17  
18  import static org.junit.Assert.assertEquals;
19  import static org.junit.Assert.assertNotNull;
20  import static org.junit.Assert.assertTrue;
21  
22  import java.io.Serializable;
23  
24  import javax.xml.namespace.QName;
25  
26  import org.junit.Test;
27  import org.kuali.rice.kew.api.WorkflowDocument;
28  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
29  import org.kuali.rice.kew.api.WorkflowRuntimeException;
30  import org.kuali.rice.kew.engine.node.Branch;
31  import org.kuali.rice.kew.engine.node.BranchState;
32  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
33  import org.kuali.rice.kew.framework.postprocessor.ProcessDocReport;
34  import org.kuali.rice.kew.messaging.MessageServiceNames;
35  import org.kuali.rice.kew.messaging.exceptionhandling.DocumentMessageExceptionHandler;
36  import org.kuali.rice.kew.postprocessor.DefaultPostProcessor;
37  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
38  import org.kuali.rice.kew.service.KEWServiceLocator;
39  import org.kuali.rice.kew.test.KEWTestCase;
40  import org.kuali.rice.kew.test.TestUtilities;
41  import org.kuali.rice.kew.api.KewApiConstants;
42  import org.kuali.rice.ksb.api.KsbApiServiceLocator;
43  import org.kuali.rice.ksb.api.bus.support.JavaServiceDefinition;
44  import org.kuali.rice.ksb.messaging.service.KSBJavaService;
45  import org.kuali.rice.test.BaselineTestCase;
46  
47  @BaselineTestCase.BaselineMode(BaselineTestCase.Mode.CLEAR_DB)
48  public class StandardWorkflowEngineTest extends KEWTestCase {
49  
50  	protected void loadTestData() throws Exception {
51  		loadXmlFile("EngineConfig.xml");
52  	}
53  
54  	/**
55  	 * Tests that the proper state is set up on the root branch in the document
56  	 * to indicate that both PROCESSED and FINAL callbacks have been made into
57  	 * the post processor.
58  	 */
59  	@Test public void testSystemBranchState() throws Exception {
60  		// route the document to final
61  		WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "SimpleDocType");
62  		document.route("");
63  		assertTrue("Document should be final.", document.isFinal());
64  
65  		// now look at the branch state
66  		DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId());
67  		Branch rootBranch = routeHeader.getRootBranch();
68  		assertNotNull(rootBranch);
69  		BranchState processedBranchState = rootBranch.getBranchState(KewApiConstants.POST_PROCESSOR_PROCESSED_KEY);
70  		BranchState finalBranchState = rootBranch.getBranchState(KewApiConstants.POST_PROCESSOR_FINAL_KEY);
71  		assertNotNull(processedBranchState);
72  		assertNotNull(finalBranchState);
73  		assertEquals("true", processedBranchState.getValue());
74  		assertEquals("true", finalBranchState.getValue());
75  		assertEquals(1, TestPostProcessor.processedCount);
76  		assertEquals(1, TestPostProcessor.finalCount);
77  	}
78  
79  	/**
80  	 * Tests that a FINAL document can go into exception routing and recover
81  	 * properly while only calling the PROCESSED and FINAL callbacks once.
82  	 */
83  	@Test public void testFinalDocumentExceptionRoutingRecovery() throws Exception {
84  
85  		// route the document to final
86  		WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "SimpleDocType");
87  		document.route("");
88  		assertTrue("Document should be final.", document.isFinal());
89  		assertEquals(1, TestPostProcessor.processedCount);
90  		assertEquals(1, TestPostProcessor.finalCount);
91  
92  		// now queue up an exploder which should push the document into
93  		// exception routing
94  		JavaServiceDefinition serviceDef = new JavaServiceDefinition();
95  		serviceDef.setPriority(new Integer(1));
96  		serviceDef.setQueue(true);
97  		serviceDef.setRetryAttempts(0);
98  		serviceDef.setServiceInterface(KSBJavaService.class.getName());
99  		serviceDef.setServiceName(new QName("KEW", "exploader"));
100 		serviceDef.setService(new ImTheExploderProcessor());
101 
102 		serviceDef.setMessageExceptionHandler(DocumentMessageExceptionHandler.class.getName());
103 		serviceDef.validate();
104 		KsbApiServiceLocator.getServiceBus().publishService(serviceDef, true);
105 
106 		KSBJavaService exploderAsService = (KSBJavaService) MessageServiceNames.getServiceAsynchronously(new QName("KEW", "exploader"), KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId()));
107 		exploderAsService.invoke("");
108 		TestUtilities.waitForExceptionRouting();
109 
110 		// the document should be in exception routing now
111 		document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
112 		assertTrue("Document should be in exception routing.", document.isException());
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 = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
121 		assertTrue("Document should be final.", document.isFinal());
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 (KewApiConstants.ROUTE_HEADER_PROCESSED_CD.equals(statusChangeEvent.getNewRouteStatus())) {
143 				processedCount++;
144 			} else if (KewApiConstants.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 }