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