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