1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.service.impl;
17
18 import org.apache.log4j.Logger;
19 import org.apache.ojb.broker.OptimisticLockException;
20 import org.kuali.rice.kew.api.KewApiConstants;
21 import org.kuali.rice.kew.api.action.ActionType;
22 import org.kuali.rice.kew.api.exception.WorkflowException;
23 import org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent;
24 import org.kuali.rice.kew.framework.postprocessor.AfterProcessEvent;
25 import org.kuali.rice.kew.framework.postprocessor.BeforeProcessEvent;
26 import org.kuali.rice.kew.framework.postprocessor.DeleteEvent;
27 import org.kuali.rice.kew.framework.postprocessor.DocumentLockingEvent;
28 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
29 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
30 import org.kuali.rice.kew.framework.postprocessor.ProcessDocReport;
31 import org.kuali.rice.krad.UserSession;
32 import org.kuali.rice.krad.document.Document;
33 import org.kuali.rice.krad.service.DocumentService;
34 import org.kuali.rice.krad.service.PostProcessorService;
35 import org.kuali.rice.krad.util.GlobalVariables;
36 import org.kuali.rice.krad.util.KRADConstants;
37 import org.kuali.rice.krad.util.ObjectUtils;
38 import org.springframework.transaction.annotation.Transactional;
39
40 import java.util.List;
41 import java.util.concurrent.Callable;
42
43
44
45
46
47
48 @Transactional
49 public class PostProcessorServiceImpl implements PostProcessorService {
50
51 private static Logger LOG = Logger.getLogger(PostProcessorServiceImpl.class);
52
53 private DocumentService documentService;
54
55
56
57
58 @Override
59 public ProcessDocReport doRouteStatusChange(final DocumentRouteStatusChange statusChangeEvent) throws Exception {
60 return GlobalVariables.doInNewGlobalVariables(establishPostProcessorUserSession(),
61 new Callable<ProcessDocReport>() {
62 public ProcessDocReport call() throws Exception {
63
64 try {
65 if (LOG.isInfoEnabled()) {
66 LOG.info(new StringBuffer("started handling route status change from ").append(
67 statusChangeEvent.getOldRouteStatus()).append(" to ").append(
68 statusChangeEvent.getNewRouteStatus()).append(" for document ").append(
69 statusChangeEvent.getDocumentId()));
70 }
71
72 Document document = documentService.getByDocumentHeaderId(
73 statusChangeEvent.getDocumentId());
74 if (document == null) {
75 if (!KewApiConstants.ROUTE_HEADER_CANCEL_CD.equals(
76 statusChangeEvent.getNewRouteStatus())) {
77 throw new RuntimeException(
78 "unable to load document " + statusChangeEvent.getDocumentId());
79 }
80 } else {
81 document.doRouteStatusChange(statusChangeEvent);
82
83
84
85
86
87
88
89
90 if (!document.getDocumentHeader().getWorkflowDocument().isSaved()) {
91 documentService.updateDocument(document);
92 }
93 }
94 if (LOG.isInfoEnabled()) {
95 LOG.info(new StringBuffer("finished handling route status change from ").append(
96 statusChangeEvent.getOldRouteStatus()).append(" to ").append(
97 statusChangeEvent.getNewRouteStatus()).append(" for document ").append(
98 statusChangeEvent.getDocumentId()));
99 }
100 } catch (Exception e) {
101 logAndRethrow("route status", e);
102 }
103 return new ProcessDocReport(true, "");
104 }
105 });
106 }
107
108
109
110
111 public ProcessDocReport doRouteLevelChange(final DocumentRouteLevelChange levelChangeEvent) throws Exception {
112 return GlobalVariables.doInNewGlobalVariables(establishPostProcessorUserSession(),
113 new Callable<ProcessDocReport>() {
114 public ProcessDocReport call() throws Exception {
115
116
117
118
119 try {
120 if (LOG.isDebugEnabled()) {
121 LOG.debug(new StringBuffer("started handling route level change from ").append(
122 levelChangeEvent.getOldNodeName()).append(" to ").append(
123 levelChangeEvent.getNewNodeName()).append(" for document ").append(
124 levelChangeEvent.getDocumentId()));
125 }
126
127 Document document = documentService.getByDocumentHeaderId(levelChangeEvent.getDocumentId());
128 if (document == null) {
129 throw new RuntimeException(
130 "unable to load document " + levelChangeEvent.getDocumentId());
131 }
132 document.populateDocumentForRouting();
133 document.doRouteLevelChange(levelChangeEvent);
134 document.getDocumentHeader().getWorkflowDocument().saveDocumentData();
135 if (LOG.isDebugEnabled()) {
136 LOG.debug(new StringBuffer("finished handling route level change from ").append(
137 levelChangeEvent.getOldNodeName()).append(" to ").append(
138 levelChangeEvent.getNewNodeName()).append(" for document ").append(
139 levelChangeEvent.getDocumentId()));
140 }
141 } catch (Exception e) {
142 logAndRethrow("route level", e);
143 }
144 return new ProcessDocReport(true, "");
145 }
146 });
147 }
148
149
150
151
152 @Override
153 public ProcessDocReport doDeleteRouteHeader(DeleteEvent event) throws Exception {
154 return new ProcessDocReport(true, "");
155 }
156
157
158
159
160 @Override
161 public ProcessDocReport doActionTaken(final ActionTakenEvent event) throws Exception {
162 return GlobalVariables.doInNewGlobalVariables(establishPostProcessorUserSession(), new Callable<ProcessDocReport>() {
163 public ProcessDocReport call() throws Exception {
164 try {
165 if ( LOG.isDebugEnabled() ) {
166 LOG.debug(new StringBuffer("started doing action taken for action taken code").append(event.getActionTaken().getActionTaken()).append(" for document ").append(event.getDocumentId()));
167 }
168 Document document = documentService.getByDocumentHeaderId(event.getDocumentId());
169 if (ObjectUtils.isNull(document)) {
170
171 if (!KewApiConstants.ACTION_TAKEN_CANCELED.equals(event.getActionTaken())) {
172 LOG.warn("doActionTaken() Unable to load document with id " + event.getDocumentId() +
173 " using action taken code '" + KewApiConstants.ACTION_TAKEN_CD.get(event.getActionTaken().getActionTaken()));
174
175 }
176 } else {
177 document.doActionTaken(event);
178 if ( LOG.isDebugEnabled() ) {
179 LOG.debug(new StringBuffer("finished doing action taken for action taken code").append(event.getActionTaken().getActionTaken()).append(" for document ").append(event.getDocumentId()));
180 }
181 }
182 }
183 catch (Exception e) {
184 logAndRethrow("do action taken", e);
185 }
186 return new ProcessDocReport(true, "");
187
188 }
189 });
190 }
191
192
193
194
195 @Override
196 public ProcessDocReport afterActionTaken(final ActionType performed, final ActionTakenEvent event) throws Exception {
197 return GlobalVariables.doInNewGlobalVariables(establishPostProcessorUserSession(), new Callable<ProcessDocReport>() {
198 public ProcessDocReport call() throws Exception {
199 try {
200 if ( LOG.isDebugEnabled() ) {
201 LOG.debug(new StringBuffer("started doing after action taken for action performed code " + performed.getCode() + " and action taken code ").append(event.getActionTaken().getActionTaken()).append(" for document ").append(event.getDocumentId()));
202 }
203 Document document = documentService.getByDocumentHeaderId(event.getDocumentId());
204 if (ObjectUtils.isNull(document)) {
205
206 if (!KewApiConstants.ACTION_TAKEN_CANCELED.equals(event.getActionTaken())) {
207 LOG.warn("afterActionTaken() Unable to load document with id " + event.getDocumentId() +
208 " using action taken code '" + KewApiConstants.ACTION_TAKEN_CD.get(event.getActionTaken().getActionTaken()));
209
210 }
211 } else {
212 document.afterActionTaken(performed, event);
213 if ( LOG.isDebugEnabled() ) {
214 LOG.debug(new StringBuffer("finished doing after action taken for action taken code").append(event.getActionTaken().getActionTaken()).append(" for document ").append(event.getDocumentId()));
215 }
216 }
217 }
218 catch (Exception e) {
219 logAndRethrow("do action taken", e);
220 }
221 return new ProcessDocReport(true, "");
222
223 }
224 });
225 }
226
227
228
229
230
231
232
233 @Override
234 public ProcessDocReport afterProcess(final AfterProcessEvent event) throws Exception {
235 return GlobalVariables.doInNewGlobalVariables(establishPostProcessorUserSession(),
236 new Callable<ProcessDocReport>() {
237 public ProcessDocReport call() throws Exception {
238
239 try {
240 if (LOG.isDebugEnabled()) {
241 LOG.debug(new StringBuffer("started after process method for document ").append(
242 event.getDocumentId()));
243 }
244
245 Document document = documentService.getByDocumentHeaderId(event.getDocumentId());
246 if (ObjectUtils.isNull(document)) {
247
248 LOG.warn("afterProcess() Unable to load document with id "
249 + event.getDocumentId()
250 + "... ignoring post processing");
251 } else {
252 document.afterWorkflowEngineProcess(event.isSuccessfullyProcessed());
253 if (LOG.isDebugEnabled()) {
254 LOG.debug(new StringBuffer("finished after process method for document ").append(
255 event.getDocumentId()));
256 }
257 }
258 } catch (Exception e) {
259 logAndRethrow("after process", e);
260 }
261 return new ProcessDocReport(true, "");
262 }
263 });
264 }
265
266
267
268
269
270
271
272 @Override
273 public ProcessDocReport beforeProcess(final BeforeProcessEvent event) throws Exception {
274 return GlobalVariables.doInNewGlobalVariables(establishPostProcessorUserSession(),
275 new Callable<ProcessDocReport>() {
276 public ProcessDocReport call() throws Exception {
277
278 try {
279 if (LOG.isDebugEnabled()) {
280 LOG.debug(new StringBuffer("started before process method for document ").append(
281 event.getDocumentId()));
282 }
283 Document document = documentService.getByDocumentHeaderId(event.getDocumentId());
284 if (ObjectUtils.isNull(document)) {
285
286 LOG.warn("beforeProcess() Unable to load document with id "
287 + event.getDocumentId()
288 + "... ignoring post processing");
289 } else {
290 document.beforeWorkflowEngineProcess();
291 if (LOG.isDebugEnabled()) {
292 LOG.debug(new StringBuffer("finished before process method for document ").append(
293 event.getDocumentId()));
294 }
295 }
296 } catch (Exception e) {
297 logAndRethrow("before process", e);
298 }
299 return new ProcessDocReport(true, "");
300 }
301 });
302 }
303
304
305
306
307
308
309
310 public List<String> getDocumentIdsToLock(final DocumentLockingEvent event) throws Exception {
311 return GlobalVariables.doInNewGlobalVariables(establishPostProcessorUserSession(),
312 new Callable<List<String>>() {
313 public List<String> call() throws Exception {
314
315 try {
316 if (LOG.isDebugEnabled()) {
317 LOG.debug(new StringBuffer("started get document ids to lock method for document ")
318 .append(event.getDocumentId()));
319 }
320 Document document = documentService.getByDocumentHeaderId(event.getDocumentId());
321 if (ObjectUtils.isNull(document)) {
322
323 LOG.warn("getDocumentIdsToLock() Unable to load document with id "
324 + event.getDocumentId()
325 + "... ignoring post processing");
326 } else {
327 List<String> documentIdsToLock = document.getWorkflowEngineDocumentIdsToLock();
328 if (LOG.isDebugEnabled()) {
329 LOG.debug(new StringBuffer("finished get document ids to lock method for document ")
330 .append(event.getDocumentId()));
331 }
332 if (documentIdsToLock == null) {
333 return null;
334 }
335 return documentIdsToLock;
336 }
337 } catch (Exception e) {
338 logAndRethrow("before process", e);
339 }
340 return null;
341 }
342 });
343 }
344
345 private void logAndRethrow(String changeType, Exception e) throws RuntimeException {
346 LOG.error("caught exception while handling " + changeType + " change", e);
347 logOptimisticDetails(5, e);
348
349 throw new RuntimeException("post processor caught exception while handling " + changeType + " change: " + e.getMessage(), e);
350 }
351
352
353
354
355
356
357
358 private void logOptimisticDetails(int depth, Throwable t) {
359 if ((depth > 0) && (t != null)) {
360 if (t instanceof OptimisticLockException) {
361 OptimisticLockException o = (OptimisticLockException) t;
362
363 LOG.error("source of OptimisticLockException = " + o.getSourceObject().getClass().getName() + " ::= " + o.getSourceObject());
364 }
365 else {
366 Throwable cause = t.getCause();
367 if (cause != t) {
368 logOptimisticDetails(--depth, cause);
369 }
370 }
371 }
372 }
373
374
375
376
377
378 public final void setDocumentService(DocumentService documentService) {
379 this.documentService = documentService;
380 }
381
382
383
384
385 protected UserSession establishPostProcessorUserSession() throws WorkflowException {
386 if (GlobalVariables.getUserSession() == null) {
387 return new UserSession(KRADConstants.SYSTEM_USER);
388 } else {
389 return GlobalVariables.getUserSession();
390 }
391 }
392 }