1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kns.service.impl;
17
18 import java.rmi.RemoteException;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.List;
22
23 import org.apache.commons.collections.ListUtils;
24 import org.apache.log4j.Logger;
25 import org.apache.ojb.broker.OptimisticLockException;
26 import org.kuali.rice.kew.dto.ActionTakenEventDTO;
27 import org.kuali.rice.kew.dto.AfterProcessEventDTO;
28 import org.kuali.rice.kew.dto.BeforeProcessEventDTO;
29 import org.kuali.rice.kew.dto.DeleteEventDTO;
30 import org.kuali.rice.kew.dto.DocumentLockingEventDTO;
31 import org.kuali.rice.kew.dto.DocumentRouteLevelChangeDTO;
32 import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
33 import org.kuali.rice.kew.exception.WorkflowException;
34 import org.kuali.rice.kew.util.KEWConstants;
35 import org.kuali.rice.kns.UserSession;
36 import org.kuali.rice.kns.document.Document;
37 import org.kuali.rice.kns.service.DateTimeService;
38 import org.kuali.rice.kns.service.DocumentService;
39 import org.kuali.rice.kns.service.PostProcessorService;
40 import org.kuali.rice.kns.util.GlobalVariables;
41 import org.kuali.rice.kns.util.KNSConstants;
42 import org.kuali.rice.kns.util.ObjectUtils;
43 import org.springframework.transaction.annotation.Transactional;
44
45
46
47
48
49
50
51 @Transactional
52 public class PostProcessorServiceImpl implements PostProcessorService {
53
54 private static Logger LOG = Logger.getLogger(PostProcessorServiceImpl.class);
55
56 private DocumentService documentService;
57 private DateTimeService dateTimeService;
58
59
60
61
62 public boolean doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) throws RemoteException {
63 try {
64 if ( LOG.isInfoEnabled() ) {
65 LOG.info(new StringBuffer("started handling route status change from ").append(statusChangeEvent.getOldRouteStatus()).append(" to ").append(statusChangeEvent.getNewRouteStatus()).append(" for document ").append(statusChangeEvent.getRouteHeaderId()));
66 }
67 establishGlobalVariables();
68 Document document = documentService.getByDocumentHeaderId(statusChangeEvent.getRouteHeaderId().toString());
69 if (document == null) {
70 if (!KEWConstants.ROUTE_HEADER_CANCEL_CD.equals(statusChangeEvent.getNewRouteStatus())) {
71 throw new RuntimeException("unable to load document " + statusChangeEvent.getRouteHeaderId());
72 }
73 }
74 else {
75 document.doRouteStatusChange(statusChangeEvent);
76
77
78
79
80
81
82
83
84 if (!document.getDocumentHeader().getWorkflowDocument().stateIsSaved()) {
85 documentService.updateDocument(document);
86 }
87 }
88 if ( LOG.isInfoEnabled() ) {
89 LOG.info(new StringBuffer("finished handling route status change from ").append(statusChangeEvent.getOldRouteStatus()).append(" to ").append(statusChangeEvent.getNewRouteStatus()).append(" for document ").append(statusChangeEvent.getRouteHeaderId()));
90 }
91 }
92 catch (Exception e) {
93 logAndRethrow("route status", e);
94 }
95 return true;
96 }
97
98
99
100
101 public boolean doRouteLevelChange(DocumentRouteLevelChangeDTO levelChangeEvent) throws RemoteException {
102
103
104
105 try {
106 if ( LOG.isDebugEnabled() ) {
107 LOG.debug(new StringBuffer("started handling route level change from ").append(levelChangeEvent.getOldNodeName()).append(" to ").append(levelChangeEvent.getNewNodeName()).append(" for document ").append(levelChangeEvent.getRouteHeaderId()));
108 }
109 establishGlobalVariables();
110 Document document = documentService.getByDocumentHeaderId(levelChangeEvent.getRouteHeaderId().toString());
111 if (document == null) {
112 throw new RuntimeException("unable to load document " + levelChangeEvent.getRouteHeaderId());
113 }
114 document.populateDocumentForRouting();
115 document.doRouteLevelChange(levelChangeEvent);
116 document.getDocumentHeader().getWorkflowDocument().saveRoutingData();
117 if ( LOG.isDebugEnabled() ) {
118 LOG.debug(new StringBuffer("finished handling route level change from ").append(levelChangeEvent.getOldNodeName()).append(" to ").append(levelChangeEvent.getNewNodeName()).append(" for document ").append(levelChangeEvent.getRouteHeaderId()));
119 }
120 }
121 catch (Exception e) {
122 logAndRethrow("route level", e);
123 }
124 return true;
125 }
126
127
128
129
130 public boolean doDeleteRouteHeader(DeleteEventDTO event) throws RemoteException {
131 return true;
132 }
133
134
135
136
137 public boolean doActionTaken(ActionTakenEventDTO event) throws RemoteException {
138 try {
139 if ( LOG.isDebugEnabled() ) {
140 LOG.debug(new StringBuffer("started doing action taken for action taken code").append(event.getActionTaken().getActionTaken()).append(" for document ").append(event.getRouteHeaderId()));
141 }
142 establishGlobalVariables();
143 Document document = documentService.getByDocumentHeaderId(event.getRouteHeaderId().toString());
144 if (ObjectUtils.isNull(document)) {
145
146 if (!KEWConstants.ACTION_TAKEN_CANCELED.equals(event.getActionTaken())) {
147 LOG.warn("doActionTaken() Unable to load document with id " + event.getRouteHeaderId() +
148 " using action taken code '" + KEWConstants.ACTION_TAKEN_CD.get(event.getActionTaken().getActionTaken()));
149
150 }
151 } else {
152 document.doActionTaken(event);
153 if ( LOG.isDebugEnabled() ) {
154 LOG.debug(new StringBuffer("finished doing action taken for action taken code").append(event.getActionTaken().getActionTaken()).append(" for document ").append(event.getRouteHeaderId()));
155 }
156 }
157 }
158 catch (Exception e) {
159 logAndRethrow("do action taken", e);
160 }
161 return true;
162 }
163
164
165
166
167
168
169
170 public boolean afterProcess(AfterProcessEventDTO event) throws Exception {
171 try {
172 if ( LOG.isDebugEnabled() ) {
173 LOG.debug(new StringBuffer("started after process method for document ").append(event.getRouteHeaderId()));
174 }
175 establishGlobalVariables();
176 Document document = documentService.getByDocumentHeaderId(event.getRouteHeaderId().toString());
177 if (ObjectUtils.isNull(document)) {
178
179 LOG.warn("afterProcess() Unable to load document with id " + event.getRouteHeaderId() + "... ignoring post processing");
180 } else {
181 document.afterWorkflowEngineProcess(event.isSuccessfullyProcessed());
182 if ( LOG.isDebugEnabled() ) {
183 LOG.debug(new StringBuffer("finished after process method for document ").append(event.getRouteHeaderId()));
184 }
185 }
186 }
187 catch (Exception e) {
188 logAndRethrow("after process", e);
189 }
190 return true;
191 }
192
193
194
195
196
197
198
199 public boolean beforeProcess(BeforeProcessEventDTO event) throws Exception {
200 try {
201 if ( LOG.isDebugEnabled() ) {
202 LOG.debug(new StringBuffer("started before process method for document ").append(event.getRouteHeaderId()));
203 }
204 establishGlobalVariables();
205 Document document = documentService.getByDocumentHeaderId(event.getRouteHeaderId().toString());
206 if (ObjectUtils.isNull(document)) {
207
208 LOG.warn("beforeProcess() Unable to load document with id " + event.getRouteHeaderId() + "... ignoring post processing");
209 } else {
210 document.beforeWorkflowEngineProcess();
211 if ( LOG.isDebugEnabled() ) {
212 LOG.debug(new StringBuffer("finished before process method for document ").append(event.getRouteHeaderId()));
213 }
214 }
215 }
216 catch (Exception e) {
217 logAndRethrow("before process", e);
218 }
219 return true;
220 }
221
222
223
224
225
226
227
228 public Long[] getDocumentIdsToLock(DocumentLockingEventDTO event) throws Exception {
229 try {
230 if ( LOG.isDebugEnabled() ) {
231 LOG.debug(new StringBuffer("started get document ids to lock method for document ").append(event.getRouteHeaderId()));
232 }
233 establishGlobalVariables();
234 Document document = documentService.getByDocumentHeaderId(event.getRouteHeaderId().toString());
235 if (ObjectUtils.isNull(document)) {
236
237 LOG.warn("getDocumentIdsToLock() Unable to load document with id " + event.getRouteHeaderId() + "... ignoring post processing");
238 } else {
239 List<Long> documentIdsToLock = document.getWorkflowEngineDocumentIdsToLock();
240 if ( LOG.isDebugEnabled() ) {
241 LOG.debug(new StringBuffer("finished get document ids to lock method for document ").append(event.getRouteHeaderId()));
242 }
243 if (documentIdsToLock == null) {
244 return null;
245 }
246 return documentIdsToLock.toArray(new Long[0]);
247
248 }
249 }
250 catch (Exception e) {
251 logAndRethrow("before process", e);
252 }
253 return null;
254 }
255
256 private void logAndRethrow(String changeType, Exception e) throws RuntimeException {
257 LOG.error("caught exception while handling " + changeType + " change", e);
258 logOptimisticDetails(5, e);
259
260 throw new RuntimeException("post processor caught exception while handling " + changeType + " change: " + e.getMessage(), e);
261 }
262
263
264
265
266
267
268
269 private void logOptimisticDetails(int depth, Throwable t) {
270 if ((depth > 0) && (t != null)) {
271 if (t instanceof OptimisticLockException) {
272 OptimisticLockException o = (OptimisticLockException) t;
273
274 LOG.error("source of OptimisticLockException = " + o.getSourceObject().getClass().getName() + " ::= " + o.getSourceObject());
275 }
276 else {
277 Throwable cause = t.getCause();
278 if (cause != t) {
279 logOptimisticDetails(--depth, cause);
280 }
281 }
282 }
283 }
284
285
286
287
288
289 public final void setDocumentService(DocumentService documentService) {
290 this.documentService = documentService;
291 }
292
293
294
295
296
297 public final void setDateTimeService(DateTimeService dateTimeService) {
298 this.dateTimeService = dateTimeService;
299 }
300
301
302
303
304 protected void establishGlobalVariables() throws WorkflowException {
305 if (GlobalVariables.getUserSession() == null) {
306 GlobalVariables.setUserSession(new UserSession(KNSConstants.SYSTEM_USER));
307 }
308 GlobalVariables.clear();
309 }
310
311 }