1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.postprocessor;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.apache.commons.lang.StringUtils;
28 import org.custommonkey.xmlunit.XMLAssert;
29 import org.custommonkey.xmlunit.XMLUnit;
30 import org.junit.Test;
31 import org.kuali.rice.kew.api.WorkflowDocument;
32 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
33 import org.kuali.rice.kew.api.action.ActionRequestType;
34 import org.kuali.rice.kew.doctype.bo.DocumentType;
35 import org.kuali.rice.kew.framework.postprocessor.AfterProcessEvent;
36 import org.kuali.rice.kew.framework.postprocessor.DocumentLockingEvent;
37 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
38 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
39 import org.kuali.rice.kew.framework.postprocessor.ProcessDocReport;
40 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
41 import org.kuali.rice.kew.service.KEWServiceLocator;
42 import org.kuali.rice.kew.test.KEWTestCase;
43 import org.kuali.rice.kew.api.KewApiConstants;
44 import org.kuali.rice.test.BaselineTestCase;
45 import org.springframework.transaction.TransactionStatus;
46 import org.springframework.transaction.support.TransactionCallback;
47 import org.springframework.transaction.support.TransactionTemplate;
48
49 @BaselineTestCase.BaselineMode(BaselineTestCase.Mode.NONE)
50 public class PostProcessorTest extends KEWTestCase {
51
52 private static final String APPLICATION_CONTENT = "<some><application>content</application></some>";
53 private static final String DOC_TITLE = "The Doc Title";
54
55 protected void loadTestData() throws Exception {
56 loadXmlFile("PostProcessorConfig.xml");
57 }
58
59
60
61
62
63
64
65
66
67
68
69 @Test public void testModifyDocumentInPostProcessor() throws Exception {
70 XMLUnit.setIgnoreWhitespace(true);
71 WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "testModifyDocumentInPostProcessor");
72 document.saveDocument("");
73 assertEquals("application content should be empty initially", "", document.getApplicationContent());
74 assertTrue("Doc title should be empty initially", StringUtils.isBlank(document.getTitle()));
75
76
77 document.route("");
78 assertEquals("Should have transitioned nodes twice", 2, DocumentModifyingPostProcessor.levelChanges);
79 assertTrue("SHould have called the processed status change", DocumentModifyingPostProcessor.processedChange);
80 assertTrue("Document should be final.", document.isFinal());
81 XMLAssert.assertXMLEqual("Application content should have been sucessfully modified.", APPLICATION_CONTENT, document.getApplicationContent());
82
83
84 assertEquals("Wrong doc title", DOC_TITLE, document.getTitle());
85
86
87 assertNotNull("SHould have routed a document from the post processor.", DocumentModifyingPostProcessor.routedDocumentId);
88 document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), DocumentModifyingPostProcessor.routedDocumentId);
89 assertTrue("document should be enroute", document.isEnroute());
90 assertEquals("Document should have 1 pending request.", 1, KEWServiceLocator.getActionRequestService().findPendingByDoc(document.getDocumentId()).size());
91 assertTrue("ewestfal should have an approve request.", document.isApprovalRequested());
92 document.approve("");
93 assertTrue("Document should be final.", document.isFinal());
94 }
95
96
97
98
99
100
101
102
103
104
105 @Test public void testEmptyPostProcessor() throws Exception {
106 WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "testEmptyPostProcessor");
107 document.saveDocument("");
108 assertEquals("application content should be empty initially", "", document.getApplicationContent());
109 assertTrue("Doc title should be empty initially", StringUtils.isBlank(document.getTitle()));
110
111 assertTrue("Document should be final.", document.isFinal());
112
113 DocumentType testEmptyDocType = KEWServiceLocator.getDocumentTypeService().findByName("testEmptyPostProcessor");
114 assertTrue("Post Processor should be set to 'none'", StringUtils.equals("none", testEmptyDocType.getPostProcessorName()));
115 assertTrue("Post Processor should be of type DefaultPostProcessor", testEmptyDocType.getPostProcessor() instanceof org.kuali.rice.kew.postprocessor.DefaultPostProcessor);
116 }
117
118 private static boolean shouldReturnDocumentIdsToLock = false;
119 private static String documentAId = null;
120 private static String documentBId = null;
121 private static UpdateDocumentThread updateDocumentThread = null;
122
123 protected String getPrincipalIdForName(String principalName) {
124 return KEWServiceLocator.getIdentityHelperService()
125 .getIdForPrincipalName(principalName);
126 }
127
128
129
130
131
132 @Test public void testGetDocumentIdsToLock() throws Exception {
133
134
135
136
137
138
139
140
141
142
143 WorkflowDocument documentB = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType");
144 documentB.saveDocument("");
145 documentBId = documentB.getDocumentId();
146 updateDocumentThread = new UpdateDocumentThread(documentBId);
147
148
149 WorkflowDocument documentA = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "testGetDocumentIdsToLock");
150 documentA.adHocToPrincipal(ActionRequestType.APPROVE, "", getPrincipalIdForName("rkirkend"), "", true);
151
152 try {
153 documentA.route("");
154 fail("An exception should have been thrown as the result of an optimistic lock!");
155 } catch (Exception e) {
156 e.printStackTrace();
157 }
158
159
160
161
162
163 shouldReturnDocumentIdsToLock = true;
164
165 documentB = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestDocumentType");
166 documentB.saveDocument("");
167 documentBId = documentB.getDocumentId();
168 updateDocumentThread = new UpdateDocumentThread(documentBId);
169
170
171 documentA = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "testGetDocumentIdsToLock");
172 documentA.adHocToPrincipal(ActionRequestType.APPROVE, "", getPrincipalIdForName("rkirkend"), "", true);
173
174 documentA.route("");
175 documentA = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("rkirkend"), documentA.getDocumentId());
176 assertTrue("rkirkend should have approve request", documentA.isApprovalRequested());
177
178 }
179
180 public static class DocumentModifyingPostProcessor extends DefaultPostProcessor {
181
182 public static boolean processedChange = false;
183 public static int levelChanges = 0;
184 public static String routedDocumentId;
185
186 protected String getPrincipalIdForName(String principalName) {
187 return KEWServiceLocator.getIdentityHelperService()
188 .getIdForPrincipalName(principalName);
189 }
190
191 public ProcessDocReport doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) throws Exception {
192 if (KewApiConstants.ROUTE_HEADER_PROCESSED_CD.equals(statusChangeEvent.getNewRouteStatus())) {
193 WorkflowDocument document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), statusChangeEvent.getDocumentId());
194 document.setApplicationContent(APPLICATION_CONTENT);
195 document.setTitle(DOC_TITLE);
196 document.saveDocumentData();
197
198 WorkflowDocument ppDocument = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user1"), "testModifyDocumentInPostProcessor");
199 routedDocumentId = ppDocument.getDocumentId();
200
201 ppDocument.adHocToPrincipal(ActionRequestType.APPROVE, "AdHoc", "", "2001", "", true);
202 ppDocument.route("");
203 processedChange = true;
204 }
205 return new ProcessDocReport(true);
206 }
207
208 public ProcessDocReport doRouteLevelChange(DocumentRouteLevelChange levelChangeEvent) throws Exception {
209 levelChanges++;
210 WorkflowDocument document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), levelChangeEvent.getDocumentId());
211 document.setTitle("Current level change: " + levelChanges);
212 document.saveDocumentData();
213 return new ProcessDocReport(true);
214 }
215
216 }
217
218 public static class GetDocumentIdsToLockPostProcessor extends DefaultPostProcessor {
219
220 protected String getPrincipalIdForName(String principalName) {
221 return KEWServiceLocator.getIdentityHelperService()
222 .getIdForPrincipalName(principalName);
223 }
224
225 @Override
226 public List<String> getDocumentIdsToLock(DocumentLockingEvent lockingEvent) throws Exception {
227 WorkflowDocument document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), lockingEvent.getDocumentId());
228 if (shouldReturnDocumentIdsToLock) {
229 List<String> docIds = new ArrayList<String>();
230 docIds.add(documentBId);
231 return docIds;
232 }
233 return null;
234 }
235
236 @Override
237 public ProcessDocReport afterProcess(AfterProcessEvent event) throws Exception {
238 WorkflowDocument wfDocument = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), event.getDocumentId());
239 if (wfDocument.isEnroute()) {
240
241 DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentBId);
242
243 new Thread(updateDocumentThread).start();
244
245 Thread.sleep(5000);
246
247 KEWServiceLocator.getRouteHeaderService().saveRouteHeader(document);
248 }
249 return super.afterProcess(event);
250 }
251
252
253
254 }
255
256
257
258
259
260
261 private class UpdateDocumentThread implements Runnable {
262 private String documentId;
263 public UpdateDocumentThread(String documentId) {
264 this.documentId = documentId;
265 }
266 public void run() {
267 TransactionTemplate template = new TransactionTemplate(KEWServiceLocator.getPlatformTransactionManager());
268 template.execute(new TransactionCallback() {
269 public Object doInTransaction(TransactionStatus status) {
270 KEWServiceLocator.getRouteHeaderService().lockRouteHeader(documentId, true);
271 DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
272 KEWServiceLocator.getRouteHeaderService().saveRouteHeader(document);
273 return null;
274 }
275 });
276 }
277 }
278
279 }