001 /*
002 * Copyright 2005-2007 The Kuali Foundation
003 *
004 *
005 * Licensed under the Educational Community License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.opensource.org/licenses/ecl2.php
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.kuali.rice.kew.engine;
018
019 import java.io.Serializable;
020
021 import javax.xml.namespace.QName;
022
023 import org.junit.Test;
024 import org.kuali.rice.kew.dto.NetworkIdDTO;
025 import org.kuali.rice.kew.engine.node.Branch;
026 import org.kuali.rice.kew.engine.node.BranchState;
027 import org.kuali.rice.kew.exception.WorkflowRuntimeException;
028 import org.kuali.rice.kew.messaging.MessageServiceNames;
029 import org.kuali.rice.kew.messaging.exceptionhandling.DocumentMessageExceptionHandler;
030 import org.kuali.rice.kew.postprocessor.DefaultPostProcessor;
031 import org.kuali.rice.kew.postprocessor.DocumentRouteStatusChange;
032 import org.kuali.rice.kew.postprocessor.ProcessDocReport;
033 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
034 import org.kuali.rice.kew.service.KEWServiceLocator;
035 import org.kuali.rice.kew.service.WorkflowDocument;
036 import org.kuali.rice.kew.test.KEWTestCase;
037 import org.kuali.rice.kew.test.TestUtilities;
038 import org.kuali.rice.kew.util.KEWConstants;
039 import org.kuali.rice.ksb.messaging.JavaServiceDefinition;
040 import org.kuali.rice.ksb.messaging.service.KSBJavaService;
041 import org.kuali.rice.ksb.service.KSBServiceLocator;
042
043
044 public class StandardWorkflowEngineTest extends KEWTestCase {
045
046 protected void loadTestData() throws Exception {
047 loadXmlFile("EngineConfig.xml");
048 }
049
050 /**
051 * Tests that the proper state is set up on the root branch in the document
052 * to indicate that both PROCESSED and FINAL callbacks have been made into
053 * the post processor.
054 */
055 @Test public void testSystemBranchState() throws Exception {
056 // route the document to final
057 WorkflowDocument document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "SimpleDocType");
058 document.routeDocument("");
059 assertTrue("Document should be final.", document.stateIsFinal());
060
061 // now look at the branch state
062 DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(document.getRouteHeaderId());
063 Branch rootBranch = routeHeader.getRootBranch();
064 assertNotNull(rootBranch);
065 BranchState processedBranchState = rootBranch.getBranchState(KEWConstants.POST_PROCESSOR_PROCESSED_KEY);
066 BranchState finalBranchState = rootBranch.getBranchState(KEWConstants.POST_PROCESSOR_FINAL_KEY);
067 assertNotNull(processedBranchState);
068 assertNotNull(finalBranchState);
069 assertEquals("true", processedBranchState.getValue());
070 assertEquals("true", finalBranchState.getValue());
071 assertEquals(1, TestPostProcessor.processedCount);
072 assertEquals(1, TestPostProcessor.finalCount);
073 }
074
075 /**
076 * Tests that a FINAL document can go into exception routing and recover
077 * properly while only calling the PROCESSED and FINAL callbacks once.
078 */
079 @Test public void testFinalDocumentExceptionRoutingRecovery() throws Exception {
080
081 // route the document to final
082 WorkflowDocument document = new WorkflowDocument(new NetworkIdDTO("ewestfal"), "SimpleDocType");
083 document.routeDocument("");
084 assertTrue("Document should be final.", document.stateIsFinal());
085 assertEquals(1, TestPostProcessor.processedCount);
086 assertEquals(1, TestPostProcessor.finalCount);
087
088 // now queue up an exploder which should push the document into
089 // exception routing
090 JavaServiceDefinition serviceDef = new JavaServiceDefinition();
091 serviceDef.setPriority(new Integer(1));
092 serviceDef.setQueue(true);
093 serviceDef.setRetryAttempts(0);
094 serviceDef.setServiceInterface(KSBJavaService.class.getName());
095 serviceDef.setServiceName(new QName("KEW", "exploader"));
096 serviceDef.setService(new ImTheExploderProcessor());
097
098 serviceDef.setMessageExceptionHandler(DocumentMessageExceptionHandler.class.getName());
099 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 }