View Javadoc
1   /**
2    * Copyright 2005-2014 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.KewApiServiceLocator;
28  import org.kuali.rice.kew.api.WorkflowDocument;
29  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
30  import org.kuali.rice.kew.api.WorkflowRuntimeException;
31  import org.kuali.rice.kew.engine.node.Branch;
32  import org.kuali.rice.kew.engine.node.BranchState;
33  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
34  import org.kuali.rice.kew.framework.postprocessor.ProcessDocReport;
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         DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getDocumentId());
107         String applicationId = routeHeader.getDocumentType().getApplicationId();
108 
109         KSBJavaService exploderAsService = (KSBJavaService) KsbApiServiceLocator.getMessageHelper().getServiceAsynchronously(new QName(
110                 "KEW", "exploader"), null, null, routeHeader.getDocumentId(), null);
111         exploderAsService.invoke("");
112 		TestUtilities.waitForExceptionRouting();
113 
114 		// the document should be in exception routing now
115 		document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
116 		assertTrue("Document should be in exception routing.", document.isException());
117 		assertEquals(1, TestPostProcessor.processedCount);
118 		assertEquals(1, TestPostProcessor.finalCount);
119 
120 		assertTrue("ewestfal should have a complete request.", document.isCompletionRequested());
121 		document.complete("");
122 
123 		// the document should be final once again
124 		document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
125 		assertTrue("Document should be final.", document.isFinal());
126 		assertEquals(1, TestPostProcessor.processedCount);
127 		assertEquals(1, TestPostProcessor.finalCount);
128 	}
129 
130 	public void tearDown() throws Exception {
131 	    try {
132 		TestPostProcessor.resetProcessedCount();
133 		TestPostProcessor.resetFinalCount();
134 	    } finally {
135 		super.tearDown();
136 	    }
137 	}
138 
139 	public static class TestPostProcessor extends DefaultPostProcessor {
140 
141 		public static int finalCount = 0;
142 
143 		public static int processedCount = 0;
144 
145 		public ProcessDocReport doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) throws Exception {
146 			if (KewApiConstants.ROUTE_HEADER_PROCESSED_CD.equals(statusChangeEvent.getNewRouteStatus())) {
147 				processedCount++;
148 			} else if (KewApiConstants.ROUTE_HEADER_FINAL_CD.equals(statusChangeEvent.getNewRouteStatus())) {
149 				finalCount++;
150 			}
151 			return new ProcessDocReport(true);
152 		}
153 
154 		public static void resetProcessedCount() {
155 			processedCount = 0;
156 		}
157 
158 		public static void resetFinalCount() {
159 			finalCount = 0;
160 		}
161 	}
162 
163 	public static class ImTheExploderProcessor implements KSBJavaService {
164 
165 		public void invoke(Serializable payLoad) {
166 			throw new WorkflowRuntimeException("I'm the Exploder!!!");
167 		}
168 
169 	}
170 
171 }