1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.kuali.rice.kew.actions;
18
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Set;
23
24 import org.apache.log4j.MDC;
25 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
26 import org.kuali.rice.kew.actionrequest.Recipient;
27 import org.kuali.rice.kew.actions.asyncservices.BlanketApproveProcessorService;
28 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
29 import org.kuali.rice.kew.doctype.bo.DocumentType;
30 import org.kuali.rice.kew.engine.BlanketApproveEngine;
31 import org.kuali.rice.kew.engine.CompatUtils;
32 import org.kuali.rice.kew.engine.RouteContext;
33 import org.kuali.rice.kew.engine.node.RouteNode;
34 import org.kuali.rice.kew.engine.node.service.RouteNodeService;
35 import org.kuali.rice.kew.exception.InvalidActionTakenException;
36 import org.kuali.rice.kew.exception.WorkflowRuntimeException;
37 import org.kuali.rice.kew.messaging.MessageServiceNames;
38 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
39 import org.kuali.rice.kew.service.KEWServiceLocator;
40 import org.kuali.rice.kew.util.KEWConstants;
41 import org.kuali.rice.kew.util.Utilities;
42 import org.kuali.rice.kim.bo.entity.KimPrincipal;
43
44
45
46
47
48
49
50 public class BlanketApproveAction extends ActionTakenEvent {
51
52 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BlanketApproveAction.class);
53 private Set nodeNames;
54
55 public BlanketApproveAction(DocumentRouteHeaderValue rh, KimPrincipal principal) {
56 super(KEWConstants.ACTION_TAKEN_BLANKET_APPROVE_CD, rh, principal);
57
58 setQueueDocumentAfterAction(false);
59
60 }
61
62 public BlanketApproveAction(DocumentRouteHeaderValue rh, KimPrincipal principal, String annotation, Integer routeLevel) {
63 this(rh, principal, annotation, convertRouteLevel(rh.getDocumentType(), routeLevel));
64 }
65
66 public BlanketApproveAction(DocumentRouteHeaderValue rh, KimPrincipal principal, String annotation, String nodeName) {
67 this(rh, principal, annotation, Utilities.asSet(nodeName));
68 }
69
70 public BlanketApproveAction(DocumentRouteHeaderValue rh, KimPrincipal principal, String annotation, Set nodeNames) {
71 super(KEWConstants.ACTION_TAKEN_BLANKET_APPROVE_CD, rh, principal, annotation);
72 this.nodeNames = (nodeNames == null ? new HashSet() : nodeNames);
73 setQueueDocumentAfterAction(false);
74 }
75
76 private static Set convertRouteLevel(DocumentType documentType, Integer routeLevel) {
77 Set<String> nodeNames = new HashSet<String>();
78 if (routeLevel == null) {
79 return nodeNames;
80 }
81 RouteNode node = CompatUtils.getNodeForLevel(documentType, routeLevel);
82 if (node == null) {
83 throw new WorkflowRuntimeException("Could not locate a valid node for the given route level: " + routeLevel);
84 }
85 nodeNames.add(node.getRouteNodeName());
86 return nodeNames;
87 }
88
89
90
91
92 @Override
93 public String validateActionRules() {
94 return validateActionRules(getActionRequestService().findAllPendingRequests(routeHeader.getRouteHeaderId()));
95 }
96
97 public String validateActionRules(List<ActionRequestValue> actionRequests) {
98 if ( (nodeNames != null) && (!nodeNames.isEmpty()) ) {
99 String nodeName = isGivenNodeListValid();
100 if (!Utilities.isEmpty(nodeName)) {
101 return "Document already at or beyond route node " + nodeName;
102 }
103 }
104 if (!getRouteHeader().isValidActionToTake(getActionPerformedCode())) {
105 return "Document is not in a state to be approved";
106 }
107 List<ActionRequestValue> filteredActionRequests = filterActionRequestsByCode(actionRequests, KEWConstants.ACTION_REQUEST_COMPLETE_REQ);
108 if (!isActionCompatibleRequest(filteredActionRequests)) {
109 return "No request for the user is compatible with the BlanketApprove Action";
110 }
111
112 if (! KEWServiceLocator.getDocumentTypePermissionService().canBlanketApprove(getPrincipal().getPrincipalId(), getRouteHeader().getDocumentType(), getRouteHeader().getDocRouteStatus(), getRouteHeader().getInitiatorWorkflowId())) {
113 return "User is not authorized to BlanketApprove document";
114 }
115 return "";
116 }
117
118 private String isGivenNodeListValid() {
119 for (Iterator iterator = nodeNames.iterator(); iterator.hasNext();) {
120 String nodeName = (String) iterator.next();
121 if (nodeName == null) {
122 iterator.remove();
123 continue;
124 }
125 if (!getRouteNodeService().isNodeInPath(getRouteHeader(), nodeName)) {
126 return nodeName;
127 }
128 }
129 return "";
130 }
131
132 public void recordAction() throws InvalidActionTakenException {
133 MDC.put("docId", getRouteHeader().getRouteHeaderId());
134 updateSearchableAttributesIfPossible();
135
136 List<ActionRequestValue> actionRequests = getActionRequestService().findAllValidRequests(getPrincipal().getPrincipalId(), getRouteHeaderId(), KEWConstants.ACTION_REQUEST_COMPLETE_REQ);
137 String errorMessage = validateActionRules(actionRequests);
138 if (!Utilities.isEmpty(errorMessage)) {
139 throw new InvalidActionTakenException(errorMessage);
140 }
141
142 LOG.debug("Checking to see if the action is legal");
143
144 LOG.debug("Blanket approving document : " + annotation);
145
146 if (getRouteHeader().isStateInitiated() || getRouteHeader().isStateSaved()) {
147 markDocumentEnroute(getRouteHeader());
148 getRouteHeader().setRoutedByUserWorkflowId(getPrincipal().getPrincipalId());
149 }
150
151 LOG.debug("Record the blanket approval action");
152 Recipient delegator = findDelegatorForActionRequests(actionRequests);
153 ActionTakenValue actionTaken = saveActionTaken(delegator);
154
155 LOG.debug("Deactivate pending action requests for user");
156 getActionRequestService().deactivateRequests(actionTaken, actionRequests);
157 notifyActionTaken(actionTaken);
158
159 KEWServiceLocator.getRouteHeaderService().saveRouteHeader(getRouteHeader());
160
161
162
163
164
165
166 queueDeferredWork(actionTaken);
167 }
168
169 protected void queueDeferredWork(ActionTakenValue actionTaken) {
170 try {
171 final boolean shouldIndex = getRouteHeader().getDocumentType().hasSearchableAttributes() && RouteContext.getCurrentRouteContext().isSearchIndexingRequestedForContext();
172
173 BlanketApproveProcessorService blanketApprove = MessageServiceNames.getBlanketApproveProcessorService(routeHeader);
174 blanketApprove.doBlanketApproveWork(routeHeader.getRouteHeaderId(), getPrincipal().getPrincipalId(), actionTaken.getActionTakenId(), nodeNames, shouldIndex);
175
176
177
178
179
180
181
182
183 } catch (Exception e) {
184 LOG.error(e);
185 throw new WorkflowRuntimeException(e);
186 }
187
188
189 }
190
191 public void performDeferredBlanketApproveWork(ActionTakenValue actionTaken) throws Exception {
192
193 if (getRouteHeader().isInException()) {
194 LOG.debug("Moving document back to Enroute from Exception");
195
196 String oldStatus = getRouteHeader().getDocRouteStatus();
197 getRouteHeader().markDocumentEnroute();
198
199 String newStatus = getRouteHeader().getDocRouteStatus();
200 notifyStatusChange(newStatus, oldStatus);
201 }
202 new BlanketApproveEngine(nodeNames, actionTaken).process(getRouteHeader().getRouteHeaderId(), null);
203
204 queueDocumentProcessing();
205 }
206
207 protected void markDocumentEnroute(DocumentRouteHeaderValue routeHeader) throws InvalidActionTakenException {
208 String oldStatus = getRouteHeader().getDocRouteStatus();
209 getRouteHeader().markDocumentEnroute();
210
211 String newStatus = getRouteHeader().getDocRouteStatus();
212 notifyStatusChange(newStatus, oldStatus);
213 KEWServiceLocator.getRouteHeaderService().saveRouteHeader(getRouteHeader());
214 }
215
216 private RouteNodeService getRouteNodeService() {
217 return KEWServiceLocator.getRouteNodeService();
218 }
219 }