1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.routelog.web;
17
18 import org.apache.struts.action.ActionForm;
19 import org.apache.struts.action.ActionForward;
20 import org.apache.struts.action.ActionMapping;
21 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
22 import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
23 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
24 import org.kuali.rice.kew.api.KewApiServiceLocator;
25 import org.kuali.rice.kew.api.WorkflowRuntimeException;
26 import org.kuali.rice.kew.api.action.ActionRequest;
27 import org.kuali.rice.kew.api.action.ActionRequestStatus;
28 import org.kuali.rice.kew.api.action.RoutingReportCriteria;
29 import org.kuali.rice.kew.api.document.DocumentDetail;
30 import org.kuali.rice.kew.api.document.node.RouteNodeInstanceState;
31 import org.kuali.rice.kew.api.exception.InvalidActionTakenException;
32 import org.kuali.rice.kew.doctype.SecuritySession;
33 import org.kuali.rice.kew.doctype.service.DocumentSecurityService;
34 import org.kuali.rice.kew.dto.DTOConverter.RouteNodeInstanceLoader;
35 import org.kuali.rice.kew.engine.node.Branch;
36 import org.kuali.rice.kew.engine.node.NodeState;
37 import org.kuali.rice.kew.engine.node.RouteNode;
38 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
39 import org.kuali.rice.kew.engine.node.service.RouteNodeService;
40 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
41 import org.kuali.rice.kew.service.KEWServiceLocator;
42 import org.kuali.rice.kew.util.Utilities;
43 import org.kuali.rice.kew.web.KewKualiAction;
44 import org.kuali.rice.krad.UserSession;
45 import org.kuali.rice.krad.util.GlobalVariables;
46
47 import javax.servlet.http.HttpServletRequest;
48 import javax.servlet.http.HttpServletResponse;
49 import java.util.ArrayList;
50 import java.util.Collection;
51 import java.util.Collections;
52 import java.util.Comparator;
53 import java.util.HashMap;
54 import java.util.HashSet;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.Set;
58
59
60
61
62
63
64
65 public class RouteLogAction extends KewKualiAction {
66
67 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RouteLogAction.class);
68 private static Comparator<ActionRequestValue> ROUTE_LOG_ACTION_REQUEST_SORTER = new Utilities.RouteLogActionRequestSorter();
69
70 @Override
71 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
72
73 RouteLogForm rlForm = (RouteLogForm) form;
74 String documentId = null;
75 if (! org.apache.commons.lang.StringUtils.isEmpty(rlForm.getDocumentId())) {
76 documentId = rlForm.getDocumentId();
77 } else if (! org.apache.commons.lang.StringUtils.isEmpty(rlForm.getDocId())) {
78 documentId =rlForm.getDocId();
79 } else {
80 throw new WorkflowRuntimeException("No paramater provided to fetch document");
81 }
82
83 DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
84
85 DocumentSecurityService security = KEWServiceLocator.getDocumentSecurityService();
86 if (!security.routeLogAuthorized(getUserSession().getPrincipalId(), routeHeader, new SecuritySession(GlobalVariables.getUserSession().getPrincipalId()))) {
87 return mapping.findForward("NotAuthorized");
88 }
89
90 fixActionRequestsPositions(routeHeader);
91 populateRouteLogFormActionRequests(rlForm, routeHeader);
92
93 rlForm.setLookFuture(routeHeader.getDocumentType().getLookIntoFuturePolicy().getPolicyValue().booleanValue());
94
95 if (rlForm.isShowFuture()) {
96 try {
97 populateRouteLogFutureRequests(rlForm, routeHeader);
98 } catch (Exception e) {
99 String errorMsg = "Unable to determine Future Action Requests";
100 LOG.info(errorMsg,e);
101 rlForm.setShowFutureError(errorMsg);
102 }
103 }
104 request.setAttribute("routeHeader", routeHeader);
105
106
107
108 boolean isAuthorizedToAddRouteLogMessage = KEWServiceLocator.getDocumentTypePermissionService()
109 .canAddRouteLogMessage(GlobalVariables.getUserSession().getPrincipalId(), routeHeader);
110 if (isAuthorizedToAddRouteLogMessage) {
111 rlForm.setEnableLogAction(true);
112 } else {
113 rlForm.setEnableLogAction(false);
114 }
115
116 return super.execute(mapping, rlForm, request, response);
117 }
118
119 @SuppressWarnings("unchecked")
120 public void populateRouteLogFormActionRequests(RouteLogForm rlForm, DocumentRouteHeaderValue routeHeader) {
121 List<ActionRequestValue> rootRequests = getActionRequestService().getRootRequests(routeHeader.getActionRequests());
122 Collections.sort(rootRequests, ROUTE_LOG_ACTION_REQUEST_SORTER);
123 rootRequests = switchActionRequestPositionsIfPrimaryDelegatesPresent(rootRequests);
124 int arCount = 0;
125 for ( ActionRequestValue actionRequest : rootRequests ) {
126 if (actionRequest.isPending()) {
127 arCount++;
128
129 if (ActionRequestStatus.INITIALIZED.getCode().equals(actionRequest.getStatus())) {
130 actionRequest.setDisplayStatus("PENDING");
131 } else if (ActionRequestStatus.ACTIVATED.getCode().equals(actionRequest.getStatus())) {
132 actionRequest.setDisplayStatus("IN ACTION LIST");
133 }
134 }
135 }
136 rlForm.setRootRequests(rootRequests);
137 rlForm.setPendingActionRequestCount(arCount);
138 }
139
140 @SuppressWarnings("unchecked")
141 private ActionRequestValue switchActionRequestPositionIfPrimaryDelegatePresent( ActionRequestValue actionRequest ) {
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 if (!actionRequest.isRoleRequest()) {
158 List<ActionRequestValue> primaryDelegateRequests = actionRequest.getPrimaryDelegateRequests();
159
160 if ( primaryDelegateRequests.size() != 1) {
161 return actionRequest;
162 }
163 ActionRequestValue primaryDelegateRequest = primaryDelegateRequests.get(0);
164 actionRequest.getChildrenRequests().remove(primaryDelegateRequest);
165 primaryDelegateRequest.setChildrenRequests(actionRequest.getChildrenRequests());
166 primaryDelegateRequest.setParentActionRequest(actionRequest.getParentActionRequest());
167 primaryDelegateRequest.setParentActionRequestId(actionRequest.getParentActionRequestId());
168
169 actionRequest.setChildrenRequests( new ArrayList<ActionRequestValue>(0) );
170 actionRequest.setParentActionRequest(primaryDelegateRequest);
171 actionRequest.setParentActionRequestId(primaryDelegateRequest.getActionRequestId());
172
173 primaryDelegateRequest.getChildrenRequests().add(0, actionRequest);
174
175 for (ActionRequestValue delegateRequest : primaryDelegateRequest.getChildrenRequests()) {
176 delegateRequest.setParentActionRequest(primaryDelegateRequest);
177 delegateRequest.setParentActionRequestId(primaryDelegateRequest.getActionRequestId());
178 }
179
180 return primaryDelegateRequest;
181 }
182
183 return actionRequest;
184 }
185
186 private List<ActionRequestValue> switchActionRequestPositionsIfPrimaryDelegatesPresent( Collection<ActionRequestValue> actionRequests ) {
187 List<ActionRequestValue> results = new ArrayList<ActionRequestValue>( actionRequests.size() );
188 for ( ActionRequestValue actionRequest : actionRequests ) {
189 results.add( switchActionRequestPositionIfPrimaryDelegatePresent(actionRequest) );
190 }
191 return results;
192 }
193
194 @SuppressWarnings("unchecked")
195 private void fixActionRequestsPositions(DocumentRouteHeaderValue routeHeader) {
196 for (ActionTakenValue actionTaken : routeHeader.getActionsTaken()) {
197 Collections.sort((List<ActionRequestValue>) actionTaken.getActionRequests(), ROUTE_LOG_ACTION_REQUEST_SORTER);
198 actionTaken.setActionRequests( actionTaken.getActionRequests() );
199 }
200 }
201
202
203
204
205
206
207
208
209
210 public void populateRouteLogFutureRequests(RouteLogForm rlForm, DocumentRouteHeaderValue document) throws Exception {
211
212 RoutingReportCriteria reportCriteria = RoutingReportCriteria.Builder.createByDocumentId(document.getDocumentId()).build();
213 String applicationId = document.getDocumentType().getApplicationId();
214
215
216 Set<String> preexistingActionRequestIds = getActionRequestIds(document);
217
218
219 DocumentDetail documentDetail = KewApiServiceLocator.getWorkflowDocumentActionsService(applicationId).executeSimulation(reportCriteria);
220
221
222 List<ActionRequestValue> futureActionRequests =
223 reconstituteActionRequestValues(documentDetail, preexistingActionRequestIds);
224
225 Collections.sort(futureActionRequests, ROUTE_LOG_ACTION_REQUEST_SORTER);
226
227 futureActionRequests = switchActionRequestPositionsIfPrimaryDelegatesPresent(futureActionRequests);
228
229 int pendingActionRequestCount = 0;
230 for (ActionRequestValue actionRequest: futureActionRequests) {
231 if (actionRequest.isPending()) {
232 pendingActionRequestCount++;
233
234 if (ActionRequestStatus.INITIALIZED.getCode().equals(actionRequest.getStatus())) {
235 actionRequest.setDisplayStatus("PENDING");
236 } else if (ActionRequestStatus.ACTIVATED.getCode().equals(actionRequest.getStatus())) {
237 actionRequest.setDisplayStatus("IN ACTION LIST");
238 }
239 }
240 }
241
242 rlForm.setFutureRootRequests(futureActionRequests);
243 rlForm.setFutureActionRequestCount(pendingActionRequestCount);
244 }
245
246
247
248
249
250
251 @SuppressWarnings("unchecked")
252 private Set<String> getActionRequestIds(DocumentRouteHeaderValue document) {
253 Set<String> actionRequestIds = new HashSet<String>();
254
255 List<ActionRequestValue> actionRequests =
256 KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(document.getDocumentId());
257
258 if (actionRequests != null) {
259 for (ActionRequestValue actionRequest : actionRequests) {
260 if (actionRequest.getActionRequestId() != null) {
261 actionRequestIds.add(actionRequest.getActionRequestId());
262 }
263 }
264 }
265 return actionRequestIds;
266 }
267
268
269
270
271
272
273
274
275 private List<ActionRequestValue> reconstituteActionRequestValues(DocumentDetail documentDetail,
276 Set<String> preexistingActionRequestIds) {
277
278 RouteNodeInstanceFabricator routeNodeInstanceFabricator =
279 new RouteNodeInstanceFabricator(KEWServiceLocator.getRouteNodeService());
280
281 if (documentDetail.getRouteNodeInstances() != null && !documentDetail.getRouteNodeInstances().isEmpty()) {
282 for (org.kuali.rice.kew.api.document.node.RouteNodeInstance routeNodeInstanceVO : documentDetail.getRouteNodeInstances()) {
283 routeNodeInstanceFabricator.importRouteNodeInstanceDTO(routeNodeInstanceVO);
284 }
285 }
286
287 List<ActionRequest> actionRequestVOs = documentDetail.getActionRequests();
288 List<ActionRequestValue> futureActionRequests = new ArrayList<ActionRequestValue>();
289 if (actionRequestVOs != null) {
290 for (ActionRequest actionRequestVO : actionRequestVOs) {
291 if (actionRequestVO != null) {
292 if (!preexistingActionRequestIds.contains(actionRequestVO.getId())) {
293 ActionRequestValue converted = ActionRequestValue.from(actionRequestVO,
294 routeNodeInstanceFabricator);
295 futureActionRequests.add(converted);
296 }
297 }
298 }
299 }
300 return futureActionRequests;
301 }
302
303 private ActionRequestService getActionRequestService() {
304 return (ActionRequestService) KEWServiceLocator.getService(KEWServiceLocator.ACTION_REQUEST_SRV);
305 }
306
307 private UserSession getUserSession() {
308 return GlobalVariables.getUserSession();
309 }
310
311
312
313
314
315
316
317
318 private static class RouteNodeInstanceFabricator implements RouteNodeInstanceLoader {
319
320 private Map<String,Branch> branches = new HashMap<String, Branch>();
321 private Map<String, RouteNodeInstance> routeNodeInstances =
322 new HashMap<String, RouteNodeInstance>();
323 private Map<String,RouteNode> routeNodes = new HashMap<String, RouteNode>();
324 private Map<String,NodeState> nodeStates = new HashMap<String, NodeState>();
325
326 private RouteNodeService routeNodeService;
327
328
329
330
331
332
333 public RouteNodeInstanceFabricator(RouteNodeService routeNodeService) {
334 this.routeNodeService = routeNodeService;
335 }
336
337
338
339
340
341
342
343
344 public void importRouteNodeInstanceDTO(org.kuali.rice.kew.api.document.node.RouteNodeInstance nodeInstanceDTO) {
345 _importRouteNodeInstanceDTO(nodeInstanceDTO);
346 }
347
348
349
350
351
352
353
354
355
356
357 private RouteNodeInstance _importRouteNodeInstanceDTO(org.kuali.rice.kew.api.document.node.RouteNodeInstance nodeInstanceDTO) {
358 if (nodeInstanceDTO == null) {
359 return null;
360 }
361 RouteNodeInstance nodeInstance = new RouteNodeInstance();
362 nodeInstance.setActive(nodeInstanceDTO.isActive());
363
364 nodeInstance.setComplete(nodeInstanceDTO.isComplete());
365 nodeInstance.setDocumentId(nodeInstanceDTO.getDocumentId());
366 nodeInstance.setInitial(nodeInstanceDTO.isInitial());
367
368 Branch branch = getBranch(nodeInstanceDTO.getBranchId());
369 nodeInstance.setBranch(branch);
370
371 if (nodeInstanceDTO.getRouteNodeId() != null) {
372 RouteNode routeNode = routeNodeService.findRouteNodeById(nodeInstanceDTO.getRouteNodeId());
373
374 if (routeNode == null) {
375 routeNode = getRouteNode(nodeInstanceDTO.getRouteNodeId());
376 routeNode.setNodeType(nodeInstanceDTO.getName());
377 }
378
379 nodeInstance.setRouteNode(routeNode);
380
381 if (routeNode.getBranch() != null) {
382 branch.setName(routeNode.getBranch().getName());
383 }
384 }
385
386 RouteNodeInstance process = getRouteNodeInstance(nodeInstanceDTO.getProcessId());
387 nodeInstance.setProcess(process);
388
389 nodeInstance.setRouteNodeInstanceId(nodeInstanceDTO.getId());
390
391 List<NodeState> nodeState = new ArrayList<NodeState>();
392 if (nodeInstanceDTO.getState() != null) {
393 for (RouteNodeInstanceState stateDTO : nodeInstanceDTO.getState()) {
394 NodeState state = getNodeState(stateDTO.getId());
395 if (state != null) {
396 state.setKey(stateDTO.getKey());
397 state.setValue(stateDTO.getValue());
398 state.setStateId(stateDTO.getId());
399 state.setNodeInstance(nodeInstance);
400 nodeState.add(state);
401 }
402 }
403 }
404 nodeInstance.setState(nodeState);
405
406 List<RouteNodeInstance> nextNodeInstances = new ArrayList<RouteNodeInstance>();
407
408
409 for (org.kuali.rice.kew.api.document.node.RouteNodeInstance nextNodeInstanceVO : nodeInstanceDTO.getNextNodeInstances()) {
410
411 nextNodeInstances.add(_importRouteNodeInstanceDTO(nextNodeInstanceVO));
412 }
413 nodeInstance.setNextNodeInstances(nextNodeInstances);
414
415 routeNodeInstances.put(nodeInstance.getRouteNodeInstanceId(), nodeInstance);
416 return nodeInstance;
417 }
418
419
420
421
422
423
424
425 @Override
426 public RouteNodeInstance load(String routeNodeInstanceID) {
427 return routeNodeInstances.get(routeNodeInstanceID);
428 }
429
430
431
432
433
434
435
436
437 private Branch getBranch(String branchId) {
438 Branch result = null;
439
440 if (branchId != null) {
441
442 if (!branches.containsKey(branchId)) {
443 result = new Branch();
444 result.setBranchId(branchId);
445 branches.put(branchId, result);
446 } else {
447 result = branches.get(branchId);
448 }
449 }
450 return result;
451 }
452
453
454
455
456
457
458
459 private RouteNode getRouteNode(String routeNodeId) {
460 RouteNode result = null;
461
462 if (routeNodeId != null) {
463
464 if (!routeNodes.containsKey(routeNodeId)) {
465 result = new RouteNode();
466 result.setRouteNodeId(routeNodeId);
467 routeNodes.put(routeNodeId, result);
468 } else {
469 result = routeNodes.get(routeNodeId);
470 }
471 }
472 return result;
473 }
474
475
476
477
478
479
480
481 public RouteNodeInstance getRouteNodeInstance(String routeNodeInstanceId) {
482 RouteNodeInstance result = null;
483
484 if (routeNodeInstanceId != null) {
485
486 if (!routeNodeInstances.containsKey(routeNodeInstanceId)) {
487 result = new RouteNodeInstance();
488 result.setRouteNodeInstanceId(routeNodeInstanceId);
489 routeNodeInstances.put(routeNodeInstanceId, result);
490 } else {
491 result = routeNodeInstances.get(routeNodeInstanceId);
492 }
493 }
494 return result;
495 }
496
497
498
499
500
501
502
503 private NodeState getNodeState(String nodeStateId) {
504 NodeState result = null;
505
506 if (nodeStateId != null) {
507
508 if (!nodeStates.containsKey(nodeStateId)) {
509 result = new NodeState();
510 result.setNodeStateId(nodeStateId);
511 nodeStates.put(nodeStateId, result);
512 } else {
513 result = nodeStates.get(nodeStateId);
514 }
515 }
516 return result;
517 }
518
519 }
520
521
522
523
524
525
526 public ActionForward logActionMessageInRouteLog(ActionMapping mapping, ActionForm form, HttpServletRequest request,
527 HttpServletResponse response) throws Exception {
528 RouteLogForm routeLogForm = (RouteLogForm) form;
529
530 String documentId = null;
531 if (!org.apache.commons.lang.StringUtils.isEmpty(routeLogForm.getDocumentId())) {
532 documentId = routeLogForm.getDocumentId();
533 } else if (!org.apache.commons.lang.StringUtils.isEmpty(routeLogForm.getDocId())) {
534 documentId = routeLogForm.getDocId();
535 } else {
536 throw new WorkflowRuntimeException("No paramater provided to fetch document");
537 }
538
539 DocumentRouteHeaderValue routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
540
541
542 boolean isAuthorizedToAddRouteLogMessage = KEWServiceLocator.getDocumentTypePermissionService()
543 .canAddRouteLogMessage(GlobalVariables.getUserSession().getPrincipalId(), routeHeader);
544
545 if (!isAuthorizedToAddRouteLogMessage) {
546 throw new InvalidActionTakenException("Principal with name '"
547 + GlobalVariables.getUserSession().getPrincipalName()
548 + "' is not authorized to add route log messages for documents of type '"
549 + routeHeader.getDocumentType().getName());
550 }
551
552 LOG.info("Logging new action message for user " + GlobalVariables.getUserSession().getPrincipalName()
553 + ", route header " + routeHeader);
554 KEWServiceLocator.getWorkflowDocumentService().logDocumentAction(
555 GlobalVariables.getUserSession().getPrincipalId(), routeHeader,
556 routeLogForm.getNewRouteLogActionMessage());
557
558 routeLogForm.setNewRouteLogActionMessage("");
559
560
561 routeHeader = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId, true);
562 fixActionRequestsPositions(routeHeader);
563 request.setAttribute("routeHeader", routeHeader);
564
565 return mapping.findForward(getDefaultMapping());
566 }
567
568 }