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