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