1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.impl.action;
17
18 import org.apache.commons.collections.CollectionUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.log4j.Logger;
21 import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
22 import org.kuali.rice.core.api.exception.RiceRuntimeException;
23 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
24 import org.kuali.rice.core.api.uif.RemotableAttributeError;
25 import org.kuali.rice.core.api.uif.RemotableAttributeErrorContract;
26 import org.kuali.rice.core.api.util.io.SerializationUtils;
27 import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
28 import org.kuali.rice.kew.actionitem.ActionItem;
29 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
30 import org.kuali.rice.kew.actionrequest.KimPrincipalRecipient;
31 import org.kuali.rice.kew.actionrequest.Recipient;
32 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
33 import org.kuali.rice.kew.api.KewApiConstants;
34 import org.kuali.rice.kew.api.KewApiServiceLocator;
35 import org.kuali.rice.kew.api.WorkflowRuntimeException;
36 import org.kuali.rice.kew.api.action.ActionRequest;
37 import org.kuali.rice.kew.api.action.ActionRequestType;
38 import org.kuali.rice.kew.api.action.ActionType;
39 import org.kuali.rice.kew.api.action.AdHocRevoke;
40 import org.kuali.rice.kew.api.action.AdHocToGroup;
41 import org.kuali.rice.kew.api.action.AdHocToGroup_v2_1_2;
42 import org.kuali.rice.kew.api.action.AdHocToPrincipal;
43 import org.kuali.rice.kew.api.action.AdHocToPrincipal_v2_1_2;
44 import org.kuali.rice.kew.api.action.DocumentActionParameters;
45 import org.kuali.rice.kew.api.action.DocumentActionResult;
46 import org.kuali.rice.kew.api.action.InvalidActionTakenException;
47 import org.kuali.rice.kew.api.action.MovePoint;
48 import org.kuali.rice.kew.api.action.RequestedActions;
49 import org.kuali.rice.kew.api.action.ReturnPoint;
50 import org.kuali.rice.kew.api.action.RoutingReportCriteria;
51 import org.kuali.rice.kew.api.action.ValidActions;
52 import org.kuali.rice.kew.api.action.WorkflowDocumentActionsService;
53 import org.kuali.rice.kew.api.doctype.DocumentTypeService;
54 import org.kuali.rice.kew.api.doctype.IllegalDocumentTypeException;
55 import org.kuali.rice.kew.api.document.Document;
56 import org.kuali.rice.kew.api.document.DocumentContentUpdate;
57 import org.kuali.rice.kew.api.document.DocumentDetail;
58 import org.kuali.rice.kew.api.document.DocumentUpdate;
59 import org.kuali.rice.kew.api.document.PropertyDefinition;
60 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeIndexingQueue;
61 import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
62 import org.kuali.rice.kew.api.exception.WorkflowException;
63 import org.kuali.rice.kew.definition.AttributeDefinition;
64 import org.kuali.rice.kew.doctype.bo.DocumentType;
65 import org.kuali.rice.kew.dto.DTOConverter;
66 import org.kuali.rice.kew.engine.ActivationContext;
67 import org.kuali.rice.kew.engine.node.RouteNode;
68 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
69 import org.kuali.rice.kew.engine.simulation.SimulationCriteria;
70 import org.kuali.rice.kew.engine.simulation.SimulationResults;
71 import org.kuali.rice.kew.engine.simulation.SimulationWorkflowEngine;
72 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
73 import org.kuali.rice.kew.rule.WorkflowAttributeXmlValidator;
74 import org.kuali.rice.kew.rule.WorkflowRuleAttribute;
75 import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute;
76 import org.kuali.rice.kew.service.KEWServiceLocator;
77 import org.kuali.rice.kim.api.identity.principal.Principal;
78 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
79 import org.kuali.rice.krad.util.KRADConstants;
80
81 import java.util.ArrayList;
82 import java.util.Collections;
83 import java.util.HashMap;
84 import java.util.HashSet;
85 import java.util.List;
86 import java.util.Map;
87 import java.util.Set;
88
89
90
91
92
93
94
95 public class WorkflowDocumentActionsServiceImpl implements WorkflowDocumentActionsService {
96
97 private static final Logger LOG = Logger.getLogger(WorkflowDocumentActionsServiceImpl.class);
98
99 private DocumentTypeService documentTypeService;
100
101 private static final DocumentActionCallback ACKNOWLEDGE_CALLBACK = new StandardDocumentActionCallback() {
102 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
103 String annotation) throws WorkflowException {
104 return KEWServiceLocator.getWorkflowDocumentService().acknowledgeDocument(principalId, documentBo,
105 annotation);
106 }
107
108 public String getActionName() {
109 return ActionType.ACKNOWLEDGE.getLabel();
110 }
111 };
112
113 private static final DocumentActionCallback APPROVE_CALLBACK = new StandardDocumentActionCallback() {
114 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
115 String annotation) throws WorkflowException {
116 return KEWServiceLocator.getWorkflowDocumentService().approveDocument(principalId, documentBo, annotation);
117 }
118
119 public String getActionName() {
120 return ActionType.APPROVE.getLabel();
121 }
122 };
123
124 private static final DocumentActionCallback CANCEL_CALLBACK = new StandardDocumentActionCallback() {
125 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
126 String annotation) throws WorkflowException {
127 return KEWServiceLocator.getWorkflowDocumentService().cancelDocument(principalId, documentBo, annotation);
128 }
129
130 public String getActionName() {
131 return ActionType.CANCEL.getLabel();
132 }
133 };
134
135 private static final DocumentActionCallback FYI_CALLBACK = new StandardDocumentActionCallback() {
136 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
137 String annotation) throws WorkflowException {
138 return KEWServiceLocator.getWorkflowDocumentService().clearFYIDocument(principalId, documentBo, annotation);
139 }
140
141 public String getActionName() {
142 return ActionType.FYI.getLabel();
143 }
144 };
145
146 private static final DocumentActionCallback COMPLETE_CALLBACK = new StandardDocumentActionCallback() {
147 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
148 String annotation) throws WorkflowException {
149 return KEWServiceLocator.getWorkflowDocumentService().completeDocument(principalId, documentBo, annotation);
150 }
151
152 public String getActionName() {
153 return ActionType.COMPLETE.getLabel();
154 }
155 };
156
157 private static final DocumentActionCallback DISAPPROVE_CALLBACK = new StandardDocumentActionCallback() {
158 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
159 String annotation) throws WorkflowException {
160 return KEWServiceLocator.getWorkflowDocumentService().disapproveDocument(principalId, documentBo,
161 annotation);
162 }
163
164 public String getActionName() {
165 return ActionType.DISAPPROVE.getLabel();
166 }
167 };
168
169 private static final DocumentActionCallback ROUTE_CALLBACK = new StandardDocumentActionCallback() {
170 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
171 String annotation) throws WorkflowException {
172 return KEWServiceLocator.getWorkflowDocumentService().routeDocument(principalId, documentBo, annotation);
173 }
174
175 public String getActionName() {
176 return ActionType.ROUTE.getLabel();
177 }
178 };
179
180 private static final DocumentActionCallback BLANKET_APPROVE_CALLBACK = new StandardDocumentActionCallback() {
181 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
182 String annotation) throws WorkflowException {
183 return KEWServiceLocator.getWorkflowDocumentService().blanketApproval(principalId, documentBo, annotation,
184 new HashSet<String>());
185 }
186
187 public String getActionName() {
188 return ActionType.BLANKET_APPROVE.getLabel();
189 }
190 };
191
192 private static final DocumentActionCallback SAVE_CALLBACK = new StandardDocumentActionCallback() {
193 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
194 String annotation) throws WorkflowException {
195 return KEWServiceLocator.getWorkflowDocumentService().saveDocument(principalId, documentBo, annotation);
196 }
197
198 public String getActionName() {
199 return ActionType.SAVE.getLabel();
200 }
201 };
202
203 private static final DocumentActionCallback PLACE_IN_EXCEPTION_CALLBACK = new StandardDocumentActionCallback() {
204 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
205 String annotation) throws WorkflowException {
206 return KEWServiceLocator.getWorkflowDocumentService().placeInExceptionRouting(principalId, documentBo,
207 annotation);
208 }
209
210 public String getActionName() {
211 return "Place In Exception";
212 }
213 };
214
215 protected DocumentRouteHeaderValue init(DocumentActionParameters parameters) {
216 String documentId = parameters.getDocumentId();
217 String principalId = parameters.getPrincipalId();
218 DocumentUpdate documentUpdate = parameters.getDocumentUpdate();
219 DocumentContentUpdate documentContentUpdate = parameters.getDocumentContentUpdate();
220 incomingParamCheck(documentId, "documentId");
221 incomingParamCheck(principalId, "principalId");
222 if (LOG.isDebugEnabled()) {
223 LOG.debug("Initializing Document from incoming documentId: " + documentId);
224 }
225 KEWServiceLocator.getRouteHeaderService().lockRouteHeader(documentId);
226
227 DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
228 if (document == null) {
229 throw new RiceIllegalArgumentException("Failed to locate a document for document id: " + documentId);
230 }
231 boolean modified = false;
232 if (documentUpdate != null) {
233 document.applyDocumentUpdate(documentUpdate);
234 modified = true;
235 }
236 if (documentContentUpdate != null) {
237 String newDocumentContent = DTOConverter.buildUpdatedDocumentContent(document.getDocContent(),
238 documentContentUpdate, document.getDocumentTypeName());
239 document.setDocContent(newDocumentContent);
240 modified = true;
241 }
242
243 if (modified) {
244 document = KEWServiceLocator.getRouteHeaderService().saveRouteHeader(document);
245
246
247
248
249
250
251
252
253
254
255
256
257
258 this.saveRouteNodeInstances(document);
259
260 }
261
262 return document;
263 }
264
265
266
267
268
269
270 private void saveRouteNodeInstances(DocumentRouteHeaderValue routeHeader) {
271
272 List<RouteNodeInstance> routeNodes = routeHeader.getInitialRouteNodeInstances();
273 List<RouteNodeInstance> persistedRouteNodes = new ArrayList<RouteNodeInstance>();
274 RouteNodeInstance persistedRni = null;
275 if (routeNodes != null && !routeNodes.isEmpty()) {
276 for (RouteNodeInstance rni : routeNodes) {
277 persistedRni = KEWServiceLocator.getRouteNodeService().save(rni);
278 persistedRouteNodes.add(persistedRni);
279 }
280 }
281 routeHeader.setInitialRouteNodeInstances(persistedRouteNodes);
282 }
283
284 @Override
285 public Document create(String documentTypeName,
286 String initiatorPrincipalId, DocumentUpdate documentUpdate,
287 DocumentContentUpdate documentContentUpdate)
288 throws RiceIllegalArgumentException, IllegalDocumentTypeException, InvalidActionTakenException {
289
290 incomingParamCheck(documentTypeName, "documentTypeName");
291 incomingParamCheck(initiatorPrincipalId, "initiatorPrincipalId");
292
293 if (LOG.isDebugEnabled()) {
294 LOG.debug("Create Document [documentTypeName=" + documentTypeName + ", initiatorPrincipalId="
295 + initiatorPrincipalId + "]");
296 }
297
298 String documentTypeId = documentTypeService.getIdByName(documentTypeName);
299 if (documentTypeId == null) {
300 throw new RiceIllegalArgumentException("Failed to locate a document type with the given name: "
301 + documentTypeName);
302 }
303
304 DocumentRouteHeaderValue documentBo = new DocumentRouteHeaderValue();
305 documentBo.setDocumentTypeId(documentTypeId);
306 documentBo.setInitiatorWorkflowId(initiatorPrincipalId);
307 if (documentUpdate != null) {
308 documentBo.setDocTitle(documentUpdate.getTitle());
309 documentBo.setAppDocId(documentUpdate.getApplicationDocumentId());
310 }
311 if (documentContentUpdate != null) {
312 String newDocumentContent = DTOConverter.buildUpdatedDocumentContent(null, documentContentUpdate,
313 documentTypeName);
314 documentBo.setDocContent(newDocumentContent);
315 }
316
317 try {
318 documentBo = KEWServiceLocator.getWorkflowDocumentService()
319 .createDocument(initiatorPrincipalId, documentBo);
320 } catch (WorkflowException e) {
321
322 translateException(e);
323 }
324 return DocumentRouteHeaderValue.to(documentBo);
325 }
326
327 @Override
328 public ValidActions determineValidActions(String documentId, String principalId) {
329 incomingParamCheck(documentId, "documentId");
330 incomingParamCheck(principalId, "principalId");
331 DocumentRouteHeaderValue documentBo = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
332 if (documentBo == null) {
333 throw new RiceIllegalArgumentException("Failed to locate a document for document id: " + documentId);
334 }
335 return determineValidActionsInternal(documentBo, principalId);
336 }
337
338 protected ValidActions determineValidActionsInternal(DocumentRouteHeaderValue documentBo, String principalId) {
339 Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(principalId);
340 return KEWServiceLocator.getActionRegistry().getValidActions(principal, documentBo);
341 }
342
343 @Override
344 public boolean isValidAction(String actionTypeCode, String documentId, String principalId)
345 throws RiceIllegalArgumentException {
346 incomingParamCheck(actionTypeCode, "actionTypeCode");
347 incomingParamCheck(documentId, "documentId");
348 incomingParamCheck(principalId, "principalId");
349
350 DocumentRouteHeaderValue documentBo = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
351 if (documentBo == null) {
352 throw new RiceIllegalArgumentException("Failed to locate a document for document id: " + documentId);
353 }
354
355 return determineValidActionInternal(actionTypeCode, documentBo, principalId);
356 }
357
358 protected boolean determineValidActionInternal(String actionTypeCode, DocumentRouteHeaderValue documentBo,
359 String principalId) {
360 Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(principalId);
361 return KEWServiceLocator.getActionRegistry().isValidAction(actionTypeCode, principal, documentBo);
362 }
363
364 @Override
365 public RequestedActions determineRequestedActions(String documentId, String principalId) {
366 incomingParamCheck(documentId, "documentId");
367 incomingParamCheck(principalId, "principalId");
368 DocumentRouteHeaderValue documentBo = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
369 if (documentBo == null) {
370 throw new RiceIllegalArgumentException("Failed to locate a document for document id: " + documentId);
371 }
372 KEWServiceLocator.getIdentityHelperService().validatePrincipalId(principalId);
373 return determineRequestedActionsInternal(documentBo, principalId);
374 }
375
376 protected RequestedActions determineRequestedActionsInternal(DocumentRouteHeaderValue documentBo, String principalId) {
377 Map<String, String> actionsRequested = KEWServiceLocator.getActionRequestService().getActionsRequested(documentBo,
378 principalId, true);
379 boolean completeRequested = false;
380 boolean approveRequested = false;
381 boolean acknowledgeRequested = false;
382 boolean fyiRequested = false;
383 for (String actionRequestCode : actionsRequested.keySet()) {
384 if (ActionRequestType.FYI.getCode().equals(actionRequestCode)) {
385 fyiRequested = Boolean.parseBoolean(actionsRequested.get(actionRequestCode));
386 } else if (ActionRequestType.ACKNOWLEDGE.getCode().equals(actionRequestCode)) {
387 acknowledgeRequested = Boolean.parseBoolean(actionsRequested.get(actionRequestCode));
388 } else if (ActionRequestType.APPROVE.getCode().equals(actionRequestCode)) {
389 approveRequested = Boolean.parseBoolean(actionsRequested.get(actionRequestCode));
390 } else if (ActionRequestType.COMPLETE.getCode().equals(actionRequestCode)) {
391 completeRequested = Boolean.parseBoolean(actionsRequested.get(actionRequestCode));
392 }
393 }
394 return RequestedActions.create(completeRequested, approveRequested, acknowledgeRequested, fyiRequested);
395 }
396
397 @Override
398 public DocumentDetail executeSimulation(RoutingReportCriteria reportCriteria) {
399 incomingParamCheck(reportCriteria, "reportCriteria");
400 if ( LOG.isDebugEnabled() ) {
401 LOG.debug("Executing routing report [docId=" + reportCriteria.getDocumentId() + ", docTypeName=" + reportCriteria.getDocumentTypeName() + "]");
402 }
403 SimulationCriteria criteria = SimulationCriteria.from(reportCriteria);
404
405 return DTOConverter.convertDocumentDetailNew(KEWServiceLocator.getRoutingReportService().report(criteria));
406 }
407
408 protected DocumentActionResult constructDocumentActionResult(DocumentRouteHeaderValue documentBo, String principalId) {
409 Document document = DocumentRouteHeaderValue.to(documentBo);
410 ValidActions validActions = determineValidActionsInternal(documentBo, principalId);
411 RequestedActions requestedActions = determineRequestedActionsInternal(documentBo, principalId);
412 return DocumentActionResult.create(document, validActions, requestedActions);
413 }
414
415 @Override
416 public DocumentActionResult acknowledge(DocumentActionParameters parameters) {
417 incomingParamCheck(parameters, "parameters");
418 return executeActionInternal(parameters, ACKNOWLEDGE_CALLBACK);
419 }
420
421 @Override
422 public DocumentActionResult approve(DocumentActionParameters parameters) {
423 incomingParamCheck(parameters, "parameters");
424 return executeActionInternal(parameters, APPROVE_CALLBACK);
425 }
426
427 @Override
428 public DocumentActionResult adHocToPrincipal(DocumentActionParameters parameters,
429 final AdHocToPrincipal adHocToPrincipal) {
430 incomingParamCheck(parameters, "parameters");
431 incomingParamCheck(adHocToPrincipal, "adHocToPrincipal");
432 return executeActionInternal(parameters,
433 new DocumentActionCallback() {
434 @Override
435 public String getLogMessage(String documentId, String principalId, String annotation) {
436 return "AdHoc Route To Principal [principalId=" + principalId +
437 ", docId=" + documentId +
438 ", actionRequest=" + adHocToPrincipal.getActionRequested() +
439 ", nodeName=" + adHocToPrincipal.getNodeName() +
440 ", targetPrincipalId=" + adHocToPrincipal.getTargetPrincipalId() +
441 ", forceAction=" + adHocToPrincipal.isForceAction() +
442 ", annotation=" + annotation +
443 ", requestLabel=" + adHocToPrincipal.getRequestLabel() + "]";
444 }
445
446 @Override
447 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
448 String principalId, String annotation) throws WorkflowException {
449 return KEWServiceLocator.getWorkflowDocumentService().adHocRouteDocumentToPrincipal(
450 principalId,
451 documentBo,
452 adHocToPrincipal.getActionRequested().getCode(),
453 adHocToPrincipal.getNodeName(),
454 adHocToPrincipal.getPriority(),
455 annotation,
456 adHocToPrincipal.getTargetPrincipalId(),
457 adHocToPrincipal.getResponsibilityDescription(),
458 adHocToPrincipal.isForceAction(),
459 adHocToPrincipal.getRequestLabel());
460 }
461 });
462 }
463
464 @Override
465 public DocumentActionResult adHocToPrincipal(DocumentActionParameters parameters, AdHocToPrincipal_v2_1_2 adHocToPrincipal) {
466 return adHocToPrincipal(parameters, AdHocToPrincipal_v2_1_2.to(adHocToPrincipal));
467 }
468
469 @Override
470 public DocumentActionResult adHocToGroup(DocumentActionParameters parameters,
471 final AdHocToGroup adHocToGroup) {
472 incomingParamCheck(parameters, "parameters");
473 incomingParamCheck(adHocToGroup, "adHocToGroup");
474 return executeActionInternal(parameters,
475 new DocumentActionCallback() {
476 @Override
477 public String getLogMessage(String documentId, String principalId, String annotation) {
478 return "AdHoc Route To Group [principalId=" + principalId +
479 ", docId=" + documentId +
480 ", actionRequest=" + adHocToGroup.getActionRequested() +
481 ", nodeName=" + adHocToGroup.getNodeName() +
482 ", targetGroupId=" + adHocToGroup.getTargetGroupId() +
483 ", forceAction=" + adHocToGroup.isForceAction() +
484 ", annotation=" + annotation +
485 ", requestLabel=" + adHocToGroup.getRequestLabel() + "]";
486 }
487
488 @Override
489 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
490 String principalId, String annotation) throws WorkflowException {
491 return KEWServiceLocator.getWorkflowDocumentService().adHocRouteDocumentToGroup(principalId,
492 documentBo,
493 adHocToGroup.getActionRequested().getCode(),
494 adHocToGroup.getNodeName(),
495 adHocToGroup.getPriority(),
496 annotation,
497 adHocToGroup.getTargetGroupId(),
498 adHocToGroup.getResponsibilityDescription(),
499 adHocToGroup.isForceAction(),
500 adHocToGroup.getRequestLabel());
501 }
502 });
503 }
504
505 @Override
506 public DocumentActionResult adHocToGroup(DocumentActionParameters parameters, AdHocToGroup_v2_1_2 adHocToGroup) {
507 return adHocToGroup(parameters, AdHocToGroup_v2_1_2.to(adHocToGroup));
508 }
509
510 @Override
511 public DocumentActionResult revokeAdHocRequestById(DocumentActionParameters parameters,
512 final String actionRequestId) {
513 incomingParamCheck(parameters, "parameters");
514 incomingParamCheck(actionRequestId, "actionRequestId");
515 return executeActionInternal(parameters,
516 new DocumentActionCallback() {
517 @Override
518 public String getLogMessage(String documentId, String principalId, String annotation) {
519 return "Revoke AdHoc from Principal [principalId=" + principalId +
520 ", documentId=" + documentId +
521 ", annotation=" + annotation +
522 ", actionRequestId=" + actionRequestId + "]";
523 }
524
525 @Override
526 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
527 String principalId, String annotation) throws WorkflowException {
528 return KEWServiceLocator.getWorkflowDocumentService().revokeAdHocRequests(principalId,
529 documentBo, actionRequestId, annotation);
530 }
531 });
532 }
533
534 @Override
535 public DocumentActionResult revokeAdHocRequests(DocumentActionParameters parameters,
536 final AdHocRevoke revoke) {
537 incomingParamCheck(parameters, "parameters");
538 incomingParamCheck(revoke, "revoke");
539 return executeActionInternal(parameters,
540 new DocumentActionCallback() {
541 @Override
542 public String getLogMessage(String documentId, String principalId, String annotation) {
543 return "Revoke AdHoc Requests [principalId=" + principalId +
544 ", docId=" + documentId +
545 ", annotation=" + annotation +
546 ", revoke=" + revoke.toString() + "]";
547 }
548
549 @Override
550 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
551 String principalId, String annotation) throws WorkflowException {
552 return KEWServiceLocator.getWorkflowDocumentService().revokeAdHocRequests(principalId,
553 documentBo, revoke, annotation);
554 }
555 });
556 }
557
558 @Override
559 public DocumentActionResult revokeAllAdHocRequests(DocumentActionParameters parameters) {
560 incomingParamCheck(parameters, "parameters");
561 return executeActionInternal(parameters,
562 new DocumentActionCallback() {
563 @Override
564 public String getLogMessage(String documentId, String principalId, String annotation) {
565 return "Revoke All AdHoc Requests [principalId=" + principalId +
566 ", docId=" + documentId +
567 ", annotation=" + annotation + "]";
568 }
569
570 @Override
571 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
572 String principalId, String annotation) throws WorkflowException {
573 return KEWServiceLocator.getWorkflowDocumentService().revokeAdHocRequests(principalId,
574 documentBo, (AdHocRevoke) null, annotation);
575 }
576 });
577 }
578
579 @Override
580 public DocumentActionResult cancel(DocumentActionParameters parameters) {
581 incomingParamCheck(parameters, "parameters");
582 return executeActionInternal(parameters, CANCEL_CALLBACK);
583 }
584
585 @Override
586 public DocumentActionResult recall(DocumentActionParameters parameters, final boolean cancel) {
587 incomingParamCheck(parameters, "parameters");
588 incomingParamCheck(cancel, "cancel");
589 return executeActionInternal(parameters, new StandardDocumentActionCallback() {
590 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
591 String annotation) throws WorkflowException {
592 return KEWServiceLocator.getWorkflowDocumentService().recallDocument(principalId, documentBo, annotation, cancel);
593 }
594 public String getActionName() {
595 return ActionType.RECALL.getLabel();
596 }
597 });
598 }
599
600 @Override
601 public DocumentActionResult clearFyi(DocumentActionParameters parameters) {
602 incomingParamCheck(parameters, "parameters");
603 return executeActionInternal(parameters, FYI_CALLBACK);
604 }
605
606 @Override
607 public DocumentActionResult complete(DocumentActionParameters parameters) {
608 incomingParamCheck(parameters, "parameters");
609 return executeActionInternal(parameters, COMPLETE_CALLBACK);
610 }
611
612 @Override
613 public DocumentActionResult disapprove(DocumentActionParameters parameters) {
614 incomingParamCheck(parameters, "parameters");
615 return executeActionInternal(parameters, DISAPPROVE_CALLBACK);
616 }
617
618 @Override
619 public DocumentActionResult route(DocumentActionParameters parameters) {
620 incomingParamCheck(parameters, "parameters");
621 return executeActionInternal(parameters, ROUTE_CALLBACK);
622 }
623
624 @Override
625 public DocumentActionResult blanketApprove(DocumentActionParameters parameters) {
626 incomingParamCheck(parameters, "parameters");
627 return executeActionInternal(parameters, BLANKET_APPROVE_CALLBACK);
628 }
629
630 @Override
631 public DocumentActionResult blanketApproveToNodes(DocumentActionParameters parameters,
632 final Set<String> nodeNames) {
633 incomingParamCheck(parameters, "parameters");
634 incomingParamCheck(nodeNames, "nodeNames");
635 return executeActionInternal(parameters,
636 new DocumentActionCallback() {
637 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
638 String principalId, String annotation) throws WorkflowException {
639 return KEWServiceLocator.getWorkflowDocumentService().blanketApproval(principalId, documentBo,
640 annotation, nodeNames);
641 }
642
643 public String getLogMessage(String documentId, String principalId, String annotation) {
644 return "Blanket Approve [principalId=" + principalId + ", documentId=" + documentId
645 + ", annotation=" + annotation + ", nodeNames=" + nodeNames + "]";
646 }
647 });
648 }
649
650 @Override
651 public DocumentActionResult returnToPreviousNode(DocumentActionParameters parameters,
652 final ReturnPoint returnPoint) {
653 incomingParamCheck(parameters, "parameters");
654 incomingParamCheck(returnPoint, "returnPoint");
655 return executeActionInternal(parameters,
656 new DocumentActionCallback() {
657 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
658 String principalId, String annotation) throws WorkflowException {
659 return KEWServiceLocator.getWorkflowDocumentService().returnDocumentToPreviousNode(principalId,
660 documentBo, returnPoint.getNodeName(), annotation);
661 }
662
663 public String getLogMessage(String documentId, String principalId, String annotation) {
664 return "Return to Previous [principalId=" + principalId + ", documentId=" + documentId
665 + ", annotation=" + annotation + ", destNodeName=" + returnPoint.getNodeName() + "]";
666 }
667 });
668 }
669
670 @Override
671 public DocumentActionResult move(DocumentActionParameters parameters,
672 final MovePoint movePoint) {
673 incomingParamCheck(parameters, "parameters");
674 incomingParamCheck(movePoint, "movePoint");
675 return executeActionInternal(parameters,
676 new DocumentActionCallback() {
677 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
678 String principalId, String annotation) throws WorkflowException {
679 return KEWServiceLocator.getWorkflowDocumentService().moveDocument(principalId, documentBo,
680 movePoint, annotation);
681 }
682
683 public String getLogMessage(String documentId, String principalId, String annotation) {
684 return "Move Document [principalId=" + principalId + ", documentId=" + documentId
685 + ", annotation=" + annotation + ", movePoint=" + movePoint + "]";
686 }
687 });
688 }
689
690 @Override
691 public DocumentActionResult takeGroupAuthority(DocumentActionParameters parameters,
692 final String groupId) {
693 incomingParamCheck(parameters, "parameters");
694 incomingParamCheck(groupId, "groupId");
695 return executeActionInternal(parameters,
696 new StandardDocumentActionCallback() {
697 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
698 String principalId, String annotation) throws WorkflowException {
699 return KEWServiceLocator.getWorkflowDocumentService().takeGroupAuthority(principalId,
700 documentBo, groupId, annotation);
701 }
702
703 public String getActionName() {
704 return ActionType.TAKE_GROUP_AUTHORITY.getLabel();
705 }
706 });
707 }
708
709 @Override
710 public DocumentActionResult releaseGroupAuthority(DocumentActionParameters parameters,
711 final String groupId) {
712 incomingParamCheck(parameters, "parameters");
713 incomingParamCheck(groupId, "groupId");
714 return executeActionInternal(parameters,
715 new StandardDocumentActionCallback() {
716 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
717 String principalId, String annotation) throws WorkflowException {
718 return KEWServiceLocator.getWorkflowDocumentService().releaseGroupAuthority(principalId,
719 documentBo, groupId, annotation);
720 }
721
722 public String getActionName() {
723 return ActionType.RELEASE_GROUP_AUTHORITY.getLabel();
724 }
725 });
726
727 }
728
729 @Override
730 public DocumentActionResult save(DocumentActionParameters parameters) {
731 incomingParamCheck(parameters, "parameters");
732 return executeActionInternal(parameters, SAVE_CALLBACK);
733 }
734
735 @Override
736 public DocumentActionResult saveDocumentData(DocumentActionParameters parameters) {
737 incomingParamCheck(parameters, "parameters");
738 return executeActionInternal(parameters, new DocumentActionCallback() {
739
740 @Override
741 public String getLogMessage(String documentId, String principalId, String annotation) {
742 return "Saving Routing Data [principalId=" + principalId + ", docId=" + documentId + "]";
743 }
744
745 @Override
746 public DocumentRouteHeaderValue doInDocumentBo(
747 DocumentRouteHeaderValue documentBo, String principalId,
748 String annotation) throws WorkflowException {
749 return KEWServiceLocator.getWorkflowDocumentService().saveRoutingData(principalId, documentBo);
750 }
751 });
752 }
753
754 @Override
755 public Document delete(String documentId, String principalId) {
756 incomingParamCheck(documentId, "documentId");
757 incomingParamCheck(principalId, "principalId");
758 DocumentRouteHeaderValue documentBo = init(DocumentActionParameters.create(documentId, principalId, null));
759 if (LOG.isDebugEnabled()) {
760 LOG.debug("Delete [principalId=" + principalId + ", documentId=" + documentId + "]");
761 }
762 Document document = null;
763 try {
764 document = DocumentRouteHeaderValue.to(documentBo);
765 KEWServiceLocator.getWorkflowDocumentService().deleteDocument(principalId, documentBo);
766
767 } catch (WorkflowException e) {
768 translateException(e);
769 }
770 return document;
771 }
772
773 @Override
774 public void logAnnotation(String documentId, String principalId, String annotation) {
775 incomingParamCheck(documentId, "documentId");
776 incomingParamCheck(principalId, "principalId");
777 incomingParamCheck(annotation, "annotation");
778 DocumentRouteHeaderValue documentBo = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
779 try {
780 KEWServiceLocator.getWorkflowDocumentService().logDocumentAction(principalId, documentBo, annotation);
781 } catch (WorkflowException e) {
782 translateException(e);
783 }
784 }
785
786 @Override
787 public void initiateIndexing(String documentId) {
788 incomingParamCheck(documentId, "documentId");
789 DocumentRouteHeaderValue documentBo = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
790 if (documentBo.getDocumentType().hasSearchableAttributes()) {
791 DocumentAttributeIndexingQueue queue = KewApiServiceLocator.getDocumentAttributeIndexingQueue(documentBo.getDocumentType().getApplicationId());
792 queue.indexDocument(documentId);
793 }
794 }
795
796 @Override
797 public DocumentActionResult superUserBlanketApprove(DocumentActionParameters parameters,
798 final boolean executePostProcessor) {
799 incomingParamCheck(parameters, "parameters");
800 return executeActionInternal(parameters,
801 new DocumentActionCallback() {
802 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
803 String principalId, String annotation) throws WorkflowException {
804 return KEWServiceLocator.getWorkflowDocumentService().superUserApprove(principalId, documentBo,
805 annotation, executePostProcessor);
806 }
807
808 public String getLogMessage(String documentId, String principalId, String annotation) {
809 return "SU Blanket Approve [principalId=" + principalId + ", documentId=" + documentId
810 + ", annotation=" + annotation + "]";
811 }
812 });
813 }
814
815 @Override
816 public DocumentActionResult superUserNodeApprove(DocumentActionParameters parameters,
817 final boolean executePostProcessor, final String nodeName) {
818 incomingParamCheck(parameters, "parameters");
819 incomingParamCheck(nodeName, "nodeName");
820 return executeActionInternal(parameters,
821 new DocumentActionCallback() {
822 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
823 String principalId, String annotation) throws WorkflowException {
824 return KEWServiceLocator.getWorkflowDocumentService().superUserNodeApproveAction(principalId,
825 documentBo, nodeName, annotation, executePostProcessor);
826 }
827
828 public String getLogMessage(String documentId, String principalId, String annotation) {
829 return "SU Node Approve Action [principalId=" + principalId + ", documentId=" + documentId
830 + ", nodeName=" + nodeName + ", annotation=" + annotation + "]";
831 }
832 });
833
834 }
835
836 @Override
837 public DocumentActionResult superUserTakeRequestedAction(DocumentActionParameters parameters,
838 final boolean executePostProcessor, final String actionRequestId) {
839 incomingParamCheck(parameters, "parameters");
840 incomingParamCheck(actionRequestId, "actionRequestId");
841 return executeActionInternal(parameters,
842 new DocumentActionCallback() {
843 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
844 String principalId, String annotation) throws WorkflowException {
845 return KEWServiceLocator.getWorkflowDocumentService().superUserActionRequestApproveAction(
846 principalId, documentBo, actionRequestId, annotation,
847 executePostProcessor);
848 }
849
850 public String getLogMessage(String documentId, String principalId, String annotation) {
851 return "SU Take Requested Action [principalId=" + principalId + ", docume tId=" + documentId
852 + ", actionRequestId=" + actionRequestId + ", annotation=" + annotation + "]";
853 }
854 });
855 }
856
857 @Override
858 public DocumentActionResult superUserDisapprove(DocumentActionParameters parameters,
859 final boolean executePostProcessor) {
860 incomingParamCheck(parameters, "parameters");
861 return executeActionInternal(parameters,
862 new DocumentActionCallback() {
863 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
864 String principalId, String annotation) throws WorkflowException {
865 return KEWServiceLocator.getWorkflowDocumentService().superUserDisapproveAction(principalId,
866 documentBo, annotation, executePostProcessor);
867 }
868
869 public String getLogMessage(String documentId, String principalId, String annotation) {
870 return "SU Disapprove [principalId=" + principalId + ", documentId=" + documentId
871 + ", annotation=" + annotation + "]";
872 }
873 });
874 }
875
876 @Override
877 public DocumentActionResult superUserCancel(DocumentActionParameters parameters, final boolean executePostProcessor) {
878 incomingParamCheck(parameters, "parameters");
879 return executeActionInternal(parameters,
880 new DocumentActionCallback() {
881 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
882 String principalId, String annotation) throws WorkflowException {
883 return KEWServiceLocator.getWorkflowDocumentService().superUserCancelAction(principalId,
884 documentBo, annotation, executePostProcessor);
885 }
886
887 public String getLogMessage(String documentId, String principalId, String annotation) {
888 return "SU Cancel [principalId=" + principalId + ", documentId=" + documentId + ", annotation="
889 + annotation + "]";
890 }
891 });
892 }
893
894 @Override
895 public DocumentActionResult superUserReturnToPreviousNode(DocumentActionParameters parameters,
896 final boolean executePostProcessor, final ReturnPoint returnPoint) {
897 incomingParamCheck(parameters, "parameters");
898 incomingParamCheck(returnPoint, "returnPoint");
899 return executeActionInternal(parameters,
900 new DocumentActionCallback() {
901 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
902 String principalId, String annotation) throws WorkflowException {
903 return KEWServiceLocator.getWorkflowDocumentService().superUserReturnDocumentToPreviousNode(
904 principalId, documentBo, returnPoint.getNodeName(), annotation, executePostProcessor);
905 }
906
907 public String getLogMessage(String documentId, String principalId, String annotation) {
908 return "SU Return to Previous Node [principalId=" + principalId + ", documentId=" + documentId
909 + ", annotation=" + annotation + ", returnPoint=" + returnPoint + "]";
910 }
911 });
912
913 }
914
915 @Override
916 public DocumentActionResult placeInExceptionRouting(DocumentActionParameters parameters) {
917 incomingParamCheck(parameters, "parameters");
918 return executeActionInternal(parameters, PLACE_IN_EXCEPTION_CALLBACK);
919 }
920
921 @Override
922 public boolean documentWillHaveAtLeastOneActionRequest(RoutingReportCriteria reportCriteria, List<String> actionRequestedCodes, boolean ignoreCurrentActionRequests) {
923 incomingParamCheck(reportCriteria, "reportCriteria");
924 incomingParamCheck(actionRequestedCodes, "actionRequestedCodes");
925 try {
926 SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
927 SimulationCriteria criteria = SimulationCriteria.from(reportCriteria);
928
929 criteria.setActivateRequests(Boolean.TRUE);
930 SimulationResults results = simulationEngine.runSimulation(criteria);
931 List<ActionRequestValue> actionRequestsToProcess = results.getSimulatedActionRequests();
932 if (!ignoreCurrentActionRequests) {
933 actionRequestsToProcess.addAll(results.getDocument().getActionRequests());
934 }
935 for (ActionRequestValue actionRequest : actionRequestsToProcess) {
936 if (actionRequest.isDone()) {
937
938 continue;
939 }
940
941 if (CollectionUtils.isEmpty(actionRequestedCodes) ) {
942
943 return true;
944 }
945
946 for (String requestedActionRequestCode : actionRequestedCodes) {
947 if (requestedActionRequestCode.equals(actionRequest.getActionRequested())) {
948 boolean satisfiesDestinationUserCriteria = (criteria.getDestinationRecipients().isEmpty()) || (isRecipientRoutedRequest(actionRequest,criteria.getDestinationRecipients()));
949 if (satisfiesDestinationUserCriteria) {
950 if (StringUtils.isBlank(criteria.getDestinationNodeName())) {
951 return true;
952 } else if (StringUtils.equals(criteria.getDestinationNodeName(),actionRequest.getNodeInstance().getName())) {
953 return true;
954 }
955 }
956 }
957 }
958 }
959 return false;
960 } catch (Exception ex) {
961 String error = "Problems evaluating documentWillHaveAtLeastOneActionRequest: " + ex.getMessage();
962 LOG.error(error,ex);
963 if (ex instanceof RuntimeException) {
964 throw (RuntimeException)ex;
965 }
966 throw new RuntimeException(error, ex);
967 }
968 }
969
970 private boolean isRecipientRoutedRequest(ActionRequestValue actionRequest, List<Recipient> recipients) throws WorkflowException {
971 for (Recipient recipient : recipients) {
972 if (actionRequest.isRecipientRoutedRequest(recipient)) {
973 return true;
974 }
975 }
976 return false;
977 }
978
979 @Override
980 public void reResolveRoleByDocTypeName(String documentTypeName, String roleName, String qualifiedRoleNameLabel) {
981 incomingParamCheck(documentTypeName, "documentTypeName");
982 incomingParamCheck(roleName, "roleName");
983 incomingParamCheck(qualifiedRoleNameLabel, "qualifiedRoleNameLabel");
984 if ( LOG.isDebugEnabled() ) {
985 LOG.debug("Re-resolving Role [docTypeName=" + documentTypeName + ", roleName=" + roleName + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel + "]");
986 }
987 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
988 if (org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
989 KEWServiceLocator.getRoleService().reResolveRole(documentType, roleName);
990 } else {
991 KEWServiceLocator.getRoleService().reResolveQualifiedRole(documentType, roleName, qualifiedRoleNameLabel);
992 }
993 }
994
995 public void reResolveRoleByDocumentId(String documentId, String roleName, String qualifiedRoleNameLabel) {
996 incomingParamCheck(documentId, "documentId");
997 incomingParamCheck(roleName, "roleName");
998 incomingParamCheck(qualifiedRoleNameLabel, "qualifiedRoleNameLabel");
999 if ( LOG.isDebugEnabled() ) {
1000 LOG.debug("Re-resolving Role [documentId=" + documentId + ", roleName=" + roleName + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel + "]");
1001 }
1002 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
1003 if (org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
1004 KEWServiceLocator.getRoleService().reResolveRole(routeHeader, roleName);
1005 } else {
1006 KEWServiceLocator.getRoleService().reResolveQualifiedRole(routeHeader, roleName, qualifiedRoleNameLabel);
1007 }
1008 }
1009
1010 @Override
1011 public List<RemotableAttributeError> validateWorkflowAttributeDefinition(
1012 WorkflowAttributeDefinition definition) {
1013 if (definition == null) {
1014 throw new RiceIllegalArgumentException("definition was null");
1015 }
1016 if ( LOG.isDebugEnabled() ) {
1017 LOG.debug("Validating WorkflowAttributeDefinition [attributeName="+definition.getAttributeName()+"]");
1018 }
1019 AttributeDefinition attributeDefinition = DTOConverter.convertWorkflowAttributeDefinition(definition);
1020 WorkflowRuleAttribute attribute = null;
1021 if (attributeDefinition != null) {
1022 attribute = (WorkflowRuleAttribute) GlobalResourceLoader.getObject(attributeDefinition.getObjectDefinition());
1023 }
1024 if (attribute instanceof GenericXMLRuleAttribute) {
1025 Map<String, String> attributePropMap = new HashMap<String, String>();
1026 GenericXMLRuleAttribute xmlAttribute = (GenericXMLRuleAttribute)attribute;
1027 xmlAttribute.setExtensionDefinition(attributeDefinition.getExtensionDefinition());
1028 for (PropertyDefinition propertyDefinition : definition.getPropertyDefinitions()) {
1029 attributePropMap.put(propertyDefinition.getName(), propertyDefinition.getValue());
1030 }
1031 xmlAttribute.setParamMap(attributePropMap);
1032 }
1033 List<RemotableAttributeError> errors = new ArrayList<RemotableAttributeError>();
1034
1035 if (attribute instanceof WorkflowAttributeXmlValidator) {
1036 List<? extends RemotableAttributeErrorContract> validationErrors = ((WorkflowAttributeXmlValidator)attribute).validateClientRoutingData();
1037 if (validationErrors != null) {
1038 for (RemotableAttributeErrorContract validationError : validationErrors) {
1039 errors.add(RemotableAttributeError.Builder.create(validationError).build());
1040 }
1041 }
1042 }
1043 return errors;
1044 }
1045
1046 @Override
1047 public boolean isFinalApprover(String documentId, String principalId) {
1048 incomingParamCheck(documentId, "documentId");
1049 incomingParamCheck(principalId, "principalId");
1050 if ( LOG.isDebugEnabled() ) {
1051 LOG.debug("Evaluating isFinalApprover [docId=" + documentId + ", principalId=" + principalId + "]");
1052 }
1053 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
1054 List<ActionRequestValue> requests = KEWServiceLocator.getActionRequestService().findPendingByDoc(documentId);
1055 List<RouteNode> finalApproverNodes = KEWServiceLocator.getRouteNodeService().findFinalApprovalRouteNodes(routeHeader.getDocumentType().getDocumentTypeId());
1056 if (finalApproverNodes.isEmpty()) {
1057 if ( LOG.isDebugEnabled() ) {
1058 LOG.debug("Could not locate final approval nodes for document " + documentId);
1059 }
1060 return false;
1061 }
1062 Set<String> finalApproverNodeNames = new HashSet<String>();
1063 for (RouteNode node : finalApproverNodes) {
1064 finalApproverNodeNames.add(node.getRouteNodeName());
1065 }
1066
1067 int approveRequest = 0;
1068 for (ActionRequestValue request : requests) {
1069 RouteNodeInstance nodeInstance = request.getNodeInstance();
1070 if (nodeInstance == null) {
1071 if ( LOG.isDebugEnabled() ) {
1072 LOG.debug("Found an action request on the document with a null node instance, indicating EXCEPTION routing.");
1073 }
1074 return false;
1075 }
1076 if (finalApproverNodeNames.contains(nodeInstance.getRouteNode().getRouteNodeName())) {
1077 if (request.isApproveOrCompleteRequest()) {
1078 approveRequest++;
1079 if ( LOG.isDebugEnabled() ) {
1080 LOG.debug("Found request is approver " + request.getActionRequestId());
1081 }
1082 if (! request.isRecipientRoutedRequest(principalId)) {
1083 if ( LOG.isDebugEnabled() ) {
1084 LOG.debug("Action Request not for user " + principalId);
1085 }
1086 return false;
1087 }
1088 }
1089 }
1090 }
1091
1092 if (approveRequest == 0) {
1093 return false;
1094 }
1095 if ( LOG.isDebugEnabled() ) {
1096 LOG.debug("Principal "+principalId+" is final approver for document " + documentId);
1097 }
1098 return true;
1099 }
1100
1101 @Override
1102 public boolean routeNodeHasApproverActionRequest(String documentTypeName, String docContent, String nodeName) {
1103 incomingParamCheck(documentTypeName, "documentTypeName");
1104 incomingParamCheck(docContent, "docContent");
1105 incomingParamCheck(nodeName, "nodeName");
1106 if ( LOG.isDebugEnabled() ) {
1107 LOG.debug("Evaluating routeNodeHasApproverActionRequest [docTypeName=" + documentTypeName + ", nodeName=" + nodeName + "]");
1108 }
1109 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
1110 RouteNode routeNode = KEWServiceLocator.getRouteNodeService().findRouteNodeByName(documentType.getDocumentTypeId(), nodeName);
1111 return routeNodeHasApproverActionRequest(documentType, docContent, routeNode, new Integer(KewApiConstants.INVALID_ROUTE_LEVEL));
1112 }
1113
1114
1115
1116
1117
1118 private boolean routeNodeHasApproverActionRequest(DocumentType documentType, String docContent, RouteNode node, Integer routeLevel) {
1119 incomingParamCheck(documentType, "documentType");
1120 incomingParamCheck(docContent, "docContent");
1121 incomingParamCheck(node, "node");
1122 incomingParamCheck(routeLevel, "routeLevel");
1123
1124
1125
1126
1127
1128
1129
1130 RoutingReportCriteria.Builder builder = RoutingReportCriteria.Builder.createByDocumentTypeName(documentType.getName());
1131 builder.setNodeNames(Collections.singletonList(node.getName()));
1132 builder.setXmlContent(docContent);
1133 DocumentDetail docDetail = executeSimulation(builder.build());
1134 if (docDetail != null) {
1135 for (ActionRequest actionRequest : docDetail.getActionRequests()) {
1136 if (actionRequest.isApprovalRequest()) {
1137 return true;
1138 }
1139 }
1140 }
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160 return false;
1161 }
1162
1163 @Override
1164 public boolean isLastApproverAtNode(String documentId, String principalId, String nodeName) {
1165 incomingParamCheck(documentId, "documentId");
1166 incomingParamCheck(principalId, "principalId");
1167 incomingParamCheck(nodeName, "nodeName");
1168 if ( LOG.isDebugEnabled() ) {
1169 LOG.debug("Evaluating isLastApproverAtNode [docId=" + documentId + ", principalId=" + principalId + ", nodeName=" + nodeName + "]");
1170 }
1171 loadDocument(documentId);
1172
1173
1174
1175 Boolean activateFirst = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(
1176 KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.FEATURE_DETAIL_TYPE, KewApiConstants.IS_LAST_APPROVER_ACTIVATE_FIRST_IND);
1177 if (activateFirst == null) {
1178 activateFirst = Boolean.FALSE;
1179 }
1180
1181 List<ActionRequestValue> requests = KEWServiceLocator.getActionRequestService().findPendingByDocRequestCdNodeName(documentId, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, nodeName);
1182 if (requests == null || requests.isEmpty()) {
1183 return false;
1184 }
1185
1186
1187 List<ActionRequestValue> copiedRequests = new ArrayList<ActionRequestValue>();
1188 for (ActionRequestValue request : requests) {
1189 ActionRequestValue actionRequest = (ActionRequestValue) SerializationUtils.deepCopy(
1190 (ActionRequestValue) request);
1191
1192 for (ActionItem actionItem : actionRequest.getActionItems()) {
1193 actionRequest.getSimulatedActionItems().add((ActionItem) SerializationUtils.deepCopy(actionItem));
1194 }
1195 copiedRequests.add(actionRequest);
1196 }
1197
1198 List<ActionRequestValue> savedRequests = new ArrayList<ActionRequestValue>();
1199 ActivationContext activationContext = new ActivationContext(ActivationContext.CONTEXT_IS_SIMULATION);
1200 for (ActionRequestValue request : copiedRequests) {
1201 if (activateFirst.booleanValue() && !request.isActive()) {
1202 request = KEWServiceLocator.getActionRequestService().activateRequest(request, activationContext);
1203 }
1204 if (request.isUserRequest() && request.getPrincipalId().equals(principalId)) {
1205 request = KEWServiceLocator.getActionRequestService().deactivateRequest(null, request, activationContext);
1206 } else if (request.isGroupRequest() && KimApiServiceLocator.getGroupService().isMemberOfGroup(principalId, request.getGroup().getId())) {
1207 request = KEWServiceLocator.getActionRequestService().deactivateRequest(null, request, activationContext);
1208 }
1209 savedRequests.add(request);
1210 }
1211 boolean allDeactivated = true;
1212 for (ActionRequestValue actionRequest: savedRequests) {
1213 allDeactivated = allDeactivated && actionRequest.isDeactivated();
1214 }
1215 return allDeactivated;
1216 }
1217
1218 @Override
1219 public boolean isUserInRouteLog(String documentId, String principalId, boolean lookFuture) {
1220 incomingParamCheck(documentId, "documentId");
1221 incomingParamCheck(principalId, "principalId");
1222 return isUserInRouteLogWithOptionalFlattening(documentId, principalId, lookFuture, false);
1223 }
1224
1225 @Override
1226 public boolean isUserInRouteLogWithOptionalFlattening(String documentId, String principalId, boolean lookFuture, boolean flattenNodes) {
1227 incomingParamCheck(documentId, "documentId");
1228 incomingParamCheck(principalId, "principalId");
1229 boolean authorized = false;
1230 if ( LOG.isDebugEnabled() ) {
1231 LOG.debug("Evaluating isUserInRouteLog [docId=" + documentId + ", principalId=" + principalId + ", lookFuture=" + lookFuture + "]");
1232 }
1233 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
1234 if (routeHeader == null) {
1235 throw new IllegalArgumentException("Document for documentId: " + documentId + " does not exist");
1236 }
1237 Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(principalId);
1238 if (principal == null) {
1239 throw new IllegalArgumentException("Principal for principalId: " + principalId + " does not exist");
1240 }
1241 List<ActionTakenValue> actionsTaken = KEWServiceLocator.getActionTakenService().findByDocumentIdPrincipalId(documentId, principal.getPrincipalId());
1242
1243 if(routeHeader.getInitiatorWorkflowId().equals(principal.getPrincipalId())){
1244 return true;
1245 }
1246
1247 if (!actionsTaken.isEmpty()) {
1248 LOG.debug("found action taken by user");
1249 authorized = true;
1250 }
1251
1252 List<ActionRequestValue> actionRequests = KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
1253 if (actionRequestListHasPrincipal(principal, actionRequests)) {
1254 authorized = true;
1255 }
1256
1257 if (!lookFuture || authorized) {
1258 return authorized;
1259 }
1260
1261
1262 SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
1263 SimulationCriteria criteria = SimulationCriteria.createSimulationCritUsingDocumentId(documentId);
1264 criteria.setDestinationNodeName(null);
1265 criteria.getDestinationRecipients().add(new KimPrincipalRecipient(principal));
1266 criteria.setFlattenNodes(flattenNodes);
1267
1268 try {
1269 SimulationResults results = simulationEngine.runSimulation(criteria);
1270 if (actionRequestListHasPrincipal(principal, results.getSimulatedActionRequests())) {
1271 authorized = true;
1272 }
1273 } catch (Exception e) {
1274 throw new RiceRuntimeException(e);
1275 }
1276
1277 return authorized;
1278 }
1279
1280 private boolean actionRequestListHasPrincipal(Principal principal, List<ActionRequestValue> actionRequests) {
1281 for (ActionRequestValue actionRequest : actionRequests) {
1282 if (actionRequest.isRecipientRoutedRequest(new KimPrincipalRecipient(principal))) {
1283 return true;
1284 }
1285 }
1286 return false;
1287 }
1288
1289 public List<String> getPrincipalIdsInRouteLog(String documentId, boolean lookFuture) {
1290 if (StringUtils.isEmpty(documentId)) {
1291 throw new IllegalArgumentException("documentId passed in is null or blank");
1292 }
1293 Set<String> principalIds = new HashSet<String>();
1294 try {
1295 if ( LOG.isDebugEnabled() ) {
1296 LOG.debug("Evaluating isUserInRouteLog [docId=" + documentId + ", lookFuture=" + lookFuture + "]");
1297 }
1298 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
1299 List<ActionTakenValue> actionsTakens =
1300 (List<ActionTakenValue>)KEWServiceLocator.getActionTakenService().findByDocumentId(documentId);
1301
1302 principalIds.add(routeHeader.getInitiatorWorkflowId());
1303 for(ActionTakenValue actionTaken: actionsTakens){
1304 principalIds.add(actionTaken.getPrincipalId());
1305 }
1306 List<ActionRequestValue> actionRequests =
1307 KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
1308 for(ActionRequestValue actionRequest: actionRequests){
1309 principalIds.addAll(getPrincipalIdsForActionRequest(actionRequest));
1310 }
1311 if (!lookFuture) {
1312 return new ArrayList<String>(principalIds);
1313 }
1314 SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
1315 SimulationCriteria criteria = SimulationCriteria.createSimulationCritUsingDocumentId(documentId);
1316 criteria.setDestinationNodeName(null);
1317 SimulationResults results = simulationEngine.runSimulation(criteria);
1318 actionRequests = (List<ActionRequestValue>)results.getSimulatedActionRequests();
1319 for(ActionRequestValue actionRequest: actionRequests){
1320 principalIds.addAll(getPrincipalIdsForActionRequest(actionRequest));
1321 }
1322 } catch (Exception ex) {
1323 LOG.warn("Problems getting principalIds in Route Log for documentId: "+documentId+". Exception:"+ex.getMessage(),ex);
1324 }
1325 return new ArrayList<String>(principalIds);
1326 }
1327
1328 private DocumentRouteHeaderValue loadDocument(String documentId) {
1329 return KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
1330 }
1331
1332
1333
1334
1335
1336
1337
1338 private List<String> getPrincipalIdsForActionRequest(ActionRequestValue actionRequest) {
1339 List<String> results = Collections.emptyList();
1340 if (actionRequest.getPrincipalId() != null) {
1341 results = Collections.singletonList(actionRequest.getPrincipalId());
1342 } else if (actionRequest.getGroupId() != null) {
1343 List<String> principalIdsForGroup =
1344 KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequest.getGroupId());
1345 if (principalIdsForGroup != null) {
1346 results = principalIdsForGroup;
1347 }
1348 }
1349 return results;
1350 }
1351
1352 private void incomingParamCheck(Object object, String name) {
1353 if (object == null) {
1354 throw new RiceIllegalArgumentException(name + " was null");
1355 } else if (object instanceof String
1356 && StringUtils.isBlank((String) object)) {
1357 throw new RiceIllegalArgumentException(name + " was blank");
1358 }
1359 }
1360
1361 public void setDocumentTypeService(DocumentTypeService documentTypeService) {
1362 this.documentTypeService = documentTypeService;
1363 }
1364
1365
1366
1367
1368
1369 private void translateException(WorkflowException e) {
1370 if (e instanceof org.kuali.rice.kew.api.exception.InvalidActionTakenException) {
1371 throw new InvalidActionTakenException(e.getMessage(), e);
1372 }
1373 throw new WorkflowRuntimeException(e.getMessage(), e);
1374 }
1375
1376 protected DocumentActionResult executeActionInternal(DocumentActionParameters parameters,
1377 DocumentActionCallback callback) {
1378 if (parameters == null) {
1379 throw new RiceIllegalArgumentException("Document action parameters was null.");
1380 }
1381 if (LOG.isDebugEnabled()) {
1382 LOG.debug(callback.getLogMessage(parameters.getDocumentId(), parameters.getPrincipalId(),
1383 parameters.getAnnotation()));
1384 }
1385 DocumentRouteHeaderValue documentBo = init(parameters);
1386 try {
1387 documentBo = callback.doInDocumentBo(documentBo, parameters.getPrincipalId(), parameters.getAnnotation());
1388 } catch (WorkflowException e) {
1389
1390 translateException(e);
1391 }
1392 return constructDocumentActionResult(documentBo, parameters.getPrincipalId());
1393 }
1394
1395 protected static interface DocumentActionCallback {
1396
1397 DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
1398 String annotation) throws WorkflowException;
1399
1400 String getLogMessage(String documentId, String principalId, String annotation);
1401
1402 }
1403
1404 protected static abstract class StandardDocumentActionCallback implements DocumentActionCallback {
1405
1406 public final String getLogMessage(String documentId, String principalId, String annotation) {
1407 return getActionName() + " [principalId=" + principalId + ", documentId=" + documentId + ", annotation="
1408 + annotation + "]";
1409 }
1410
1411 protected abstract String getActionName();
1412
1413 }
1414
1415 }