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().getNewValidActions(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 clearFyi(DocumentActionParameters parameters) {
551 incomingParamCheck(parameters, "parameters");
552 return executeActionInternal(parameters, FYI_CALLBACK);
553 }
554
555 @Override
556 public DocumentActionResult complete(DocumentActionParameters parameters) {
557 incomingParamCheck(parameters, "parameters");
558 return executeActionInternal(parameters, COMPLETE_CALLBACK);
559 }
560
561 @Override
562 public DocumentActionResult disapprove(DocumentActionParameters parameters) {
563 incomingParamCheck(parameters, "parameters");
564 return executeActionInternal(parameters, DISAPPROVE_CALLBACK);
565 }
566
567 @Override
568 public DocumentActionResult route(DocumentActionParameters parameters) {
569 incomingParamCheck(parameters, "parameters");
570 return executeActionInternal(parameters, ROUTE_CALLBACK);
571 }
572
573 @Override
574 public DocumentActionResult blanketApprove(DocumentActionParameters parameters) {
575 incomingParamCheck(parameters, "parameters");
576 return executeActionInternal(parameters, BLANKET_APPROVE_CALLBACK);
577 }
578
579 @Override
580 public DocumentActionResult blanketApproveToNodes(DocumentActionParameters parameters,
581 final Set<String> nodeNames) {
582 incomingParamCheck(parameters, "parameters");
583 incomingParamCheck(nodeNames, "nodeNames");
584 return executeActionInternal(parameters,
585 new DocumentActionCallback() {
586 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
587 String principalId, String annotation) throws WorkflowException {
588 return KEWServiceLocator.getWorkflowDocumentService().blanketApproval(principalId, documentBo,
589 annotation, nodeNames);
590 }
591
592 public String getLogMessage(String documentId, String principalId, String annotation) {
593 return "Blanket Approve [principalId=" + principalId + ", documentId=" + documentId
594 + ", annotation=" + annotation + ", nodeNames=" + nodeNames + "]";
595 }
596 });
597 }
598
599 @Override
600 public DocumentActionResult returnToPreviousNode(DocumentActionParameters parameters,
601 final ReturnPoint returnPoint) {
602 incomingParamCheck(parameters, "parameters");
603 incomingParamCheck(returnPoint, "returnPoint");
604 return executeActionInternal(parameters,
605 new DocumentActionCallback() {
606 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
607 String principalId, String annotation) throws WorkflowException {
608 return KEWServiceLocator.getWorkflowDocumentService().returnDocumentToPreviousNode(principalId,
609 documentBo, returnPoint.getNodeName(), annotation);
610 }
611
612 public String getLogMessage(String documentId, String principalId, String annotation) {
613 return "Return to Previous [principalId=" + principalId + ", documentId=" + documentId
614 + ", annotation=" + annotation + ", destNodeName=" + returnPoint.getNodeName() + "]";
615 }
616 });
617 }
618
619 @Override
620 public DocumentActionResult move(DocumentActionParameters parameters,
621 final MovePoint movePoint) {
622 incomingParamCheck(parameters, "parameters");
623 incomingParamCheck(movePoint, "movePoint");
624 return executeActionInternal(parameters,
625 new DocumentActionCallback() {
626 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
627 String principalId, String annotation) throws WorkflowException {
628 return KEWServiceLocator.getWorkflowDocumentService().moveDocument(principalId, documentBo,
629 movePoint, annotation);
630 }
631
632 public String getLogMessage(String documentId, String principalId, String annotation) {
633 return "Move Document [principalId=" + principalId + ", documentId=" + documentId
634 + ", annotation=" + annotation + ", movePoint=" + movePoint + "]";
635 }
636 });
637 }
638
639 @Override
640 public DocumentActionResult takeGroupAuthority(DocumentActionParameters parameters,
641 final String groupId) {
642 incomingParamCheck(parameters, "parameters");
643 incomingParamCheck(groupId, "groupId");
644 return executeActionInternal(parameters,
645 new StandardDocumentActionCallback() {
646 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
647 String principalId, String annotation) throws WorkflowException {
648 return KEWServiceLocator.getWorkflowDocumentService().takeGroupAuthority(principalId,
649 documentBo, groupId, annotation);
650 }
651
652 public String getActionName() {
653 return ActionType.TAKE_GROUP_AUTHORITY.getLabel();
654 }
655 });
656 }
657
658 @Override
659 public DocumentActionResult releaseGroupAuthority(DocumentActionParameters parameters,
660 final String groupId) {
661 incomingParamCheck(parameters, "parameters");
662 incomingParamCheck(groupId, "groupId");
663 return executeActionInternal(parameters,
664 new StandardDocumentActionCallback() {
665 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
666 String principalId, String annotation) throws WorkflowException {
667 return KEWServiceLocator.getWorkflowDocumentService().releaseGroupAuthority(principalId,
668 documentBo, groupId, annotation);
669 }
670
671 public String getActionName() {
672 return ActionType.RELEASE_GROUP_AUTHORITY.getLabel();
673 }
674 });
675
676 }
677
678 @Override
679 public DocumentActionResult save(DocumentActionParameters parameters) {
680 incomingParamCheck(parameters, "parameters");
681 return executeActionInternal(parameters, SAVE_CALLBACK);
682 }
683
684 @Override
685 public DocumentActionResult saveDocumentData(DocumentActionParameters parameters) {
686 incomingParamCheck(parameters, "parameters");
687 return executeActionInternal(parameters, new DocumentActionCallback() {
688
689 @Override
690 public String getLogMessage(String documentId, String principalId, String annotation) {
691 return "Saving Routing Data [principalId=" + principalId + ", docId=" + documentId + "]";
692 }
693
694 @Override
695 public DocumentRouteHeaderValue doInDocumentBo(
696 DocumentRouteHeaderValue documentBo, String principalId,
697 String annotation) throws WorkflowException {
698 return KEWServiceLocator.getWorkflowDocumentService().saveRoutingData(principalId, documentBo);
699 }
700 });
701 }
702
703 @Override
704 public Document delete(String documentId, String principalId) {
705 incomingParamCheck(documentId, "documentId");
706 incomingParamCheck(principalId, "principalId");
707 DocumentRouteHeaderValue documentBo = init(DocumentActionParameters.create(documentId, principalId, null));
708 if (LOG.isDebugEnabled()) {
709 LOG.debug("Delete [principalId=" + principalId + ", documentId=" + documentId + "]");
710 }
711 Document document = null;
712 try {
713 document = DocumentRouteHeaderValue.to(documentBo);
714 KEWServiceLocator.getWorkflowDocumentService().deleteDocument(principalId, documentBo);
715
716 } catch (WorkflowException e) {
717 translateException(e);
718 }
719 return document;
720 }
721
722 @Override
723 public void logAnnotation(String documentId, String principalId, String annotation) {
724 incomingParamCheck(documentId, "documentId");
725 incomingParamCheck(principalId, "principalId");
726 incomingParamCheck(annotation, "annotation");
727 DocumentRouteHeaderValue documentBo = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
728 try {
729 KEWServiceLocator.getWorkflowDocumentService().logDocumentAction(principalId, documentBo, annotation);
730 } catch (WorkflowException e) {
731 translateException(e);
732 }
733 }
734
735 @Override
736 public void initiateIndexing(String documentId) {
737 incomingParamCheck(documentId, "documentId");
738
739 throw new UnsupportedOperationException("implement me!!!");
740 }
741
742 @Override
743 public DocumentActionResult superUserBlanketApprove(DocumentActionParameters parameters,
744 final boolean executePostProcessor) {
745 incomingParamCheck(parameters, "parameters");
746 return executeActionInternal(parameters,
747 new DocumentActionCallback() {
748 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
749 String principalId, String annotation) throws WorkflowException {
750 return KEWServiceLocator.getWorkflowDocumentService().superUserApprove(principalId, documentBo,
751 annotation, executePostProcessor);
752 }
753
754 public String getLogMessage(String documentId, String principalId, String annotation) {
755 return "SU Blanket Approve [principalId=" + principalId + ", documentId=" + documentId
756 + ", annotation=" + annotation + "]";
757 }
758 });
759 }
760
761 @Override
762 public DocumentActionResult superUserNodeApprove(DocumentActionParameters parameters,
763 final boolean executePostProcessor, final String nodeName) {
764 incomingParamCheck(parameters, "parameters");
765 incomingParamCheck(nodeName, "nodeName");
766 return executeActionInternal(parameters,
767 new DocumentActionCallback() {
768 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
769 String principalId, String annotation) throws WorkflowException {
770 return KEWServiceLocator.getWorkflowDocumentService().superUserNodeApproveAction(principalId,
771 documentBo, nodeName, annotation, executePostProcessor);
772 }
773
774 public String getLogMessage(String documentId, String principalId, String annotation) {
775 return "SU Node Approve Action [principalId=" + principalId + ", documentId=" + documentId
776 + ", nodeName=" + nodeName + ", annotation=" + annotation + "]";
777 }
778 });
779
780 }
781
782 @Override
783 public DocumentActionResult superUserTakeRequestedAction(DocumentActionParameters parameters,
784 final boolean executePostProcessor, final String actionRequestId) {
785 incomingParamCheck(parameters, "parameters");
786 incomingParamCheck(actionRequestId, "actionRequestId");
787 return executeActionInternal(parameters,
788 new DocumentActionCallback() {
789 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
790 String principalId, String annotation) throws WorkflowException {
791 return KEWServiceLocator.getWorkflowDocumentService().superUserActionRequestApproveAction(
792 principalId, documentBo, actionRequestId, annotation,
793 executePostProcessor);
794 }
795
796 public String getLogMessage(String documentId, String principalId, String annotation) {
797 return "SU Take Requested Action [principalId=" + principalId + ", docume tId=" + documentId
798 + ", actionRequestId=" + actionRequestId + ", annotation=" + annotation + "]";
799 }
800 });
801 }
802
803 @Override
804 public DocumentActionResult superUserDisapprove(DocumentActionParameters parameters,
805 final boolean executePostProcessor) {
806 incomingParamCheck(parameters, "parameters");
807 return executeActionInternal(parameters,
808 new DocumentActionCallback() {
809 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
810 String principalId, String annotation) throws WorkflowException {
811 return KEWServiceLocator.getWorkflowDocumentService().superUserDisapproveAction(principalId,
812 documentBo, annotation, executePostProcessor);
813 }
814
815 public String getLogMessage(String documentId, String principalId, String annotation) {
816 return "SU Disapprove [principalId=" + principalId + ", documentId=" + documentId
817 + ", annotation=" + annotation + "]";
818 }
819 });
820 }
821
822 @Override
823 public DocumentActionResult superUserCancel(DocumentActionParameters parameters, final boolean executePostProcessor) {
824 incomingParamCheck(parameters, "parameters");
825 return executeActionInternal(parameters,
826 new DocumentActionCallback() {
827 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
828 String principalId, String annotation) throws WorkflowException {
829 return KEWServiceLocator.getWorkflowDocumentService().superUserCancelAction(principalId,
830 documentBo, annotation, executePostProcessor);
831 }
832
833 public String getLogMessage(String documentId, String principalId, String annotation) {
834 return "SU Cancel [principalId=" + principalId + ", documentId=" + documentId + ", annotation="
835 + annotation + "]";
836 }
837 });
838 }
839
840 @Override
841 public DocumentActionResult superUserReturnToPreviousNode(DocumentActionParameters parameters,
842 final boolean executePostProcessor, final ReturnPoint returnPoint) {
843 incomingParamCheck(parameters, "parameters");
844 incomingParamCheck(returnPoint, "returnPoint");
845 return executeActionInternal(parameters,
846 new DocumentActionCallback() {
847 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
848 String principalId, String annotation) throws WorkflowException {
849 return KEWServiceLocator.getWorkflowDocumentService().superUserReturnDocumentToPreviousNode(
850 principalId, documentBo, returnPoint.getNodeName(), annotation, executePostProcessor);
851 }
852
853 public String getLogMessage(String documentId, String principalId, String annotation) {
854 return "SU Return to Previous Node [principalId=" + principalId + ", documentId=" + documentId
855 + ", annotation=" + annotation + ", returnPoint=" + returnPoint + "]";
856 }
857 });
858
859 }
860
861 @Override
862 public DocumentActionResult placeInExceptionRouting(DocumentActionParameters parameters) {
863 incomingParamCheck(parameters, "parameters");
864 return executeActionInternal(parameters, PLACE_IN_EXCEPTION_CALLBACK);
865 }
866
867 @Override
868 public boolean documentWillHaveAtLeastOneActionRequest(RoutingReportCriteria reportCriteria, List<String> actionRequestedCodes, boolean ignoreCurrentActionRequests) {
869 incomingParamCheck(reportCriteria, "reportCriteria");
870 incomingParamCheck(actionRequestedCodes, "actionRequestedCodes");
871 try {
872 SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
873 SimulationCriteria criteria = SimulationCriteria.from(reportCriteria);
874
875 criteria.setActivateRequests(Boolean.TRUE);
876 SimulationResults results = simulationEngine.runSimulation(criteria);
877 List<ActionRequestValue> actionRequestsToProcess = results.getSimulatedActionRequests();
878 if (!ignoreCurrentActionRequests) {
879 actionRequestsToProcess.addAll(results.getDocument().getActionRequests());
880 }
881 for (ActionRequestValue actionRequest : actionRequestsToProcess) {
882 if (actionRequest.isDone()) {
883
884 continue;
885 }
886
887 if (CollectionUtils.isEmpty(actionRequestedCodes) ) {
888
889 return true;
890 }
891
892 for (String requestedActionRequestCode : actionRequestedCodes) {
893 if (requestedActionRequestCode.equals(actionRequest.getActionRequested())) {
894 boolean satisfiesDestinationUserCriteria = (criteria.getDestinationRecipients().isEmpty()) || (isRecipientRoutedRequest(actionRequest,criteria.getDestinationRecipients()));
895 if (satisfiesDestinationUserCriteria) {
896 if (StringUtils.isBlank(criteria.getDestinationNodeName())) {
897 return true;
898 } else if (StringUtils.equals(criteria.getDestinationNodeName(),actionRequest.getNodeInstance().getName())) {
899 return true;
900 }
901 }
902 }
903 }
904 }
905 return false;
906 } catch (Exception ex) {
907 String error = "Problems evaluating documentWillHaveAtLeastOneActionRequest: " + ex.getMessage();
908 LOG.error(error,ex);
909 if (ex instanceof RuntimeException) {
910 throw (RuntimeException)ex;
911 }
912 throw new RuntimeException(error, ex);
913 }
914 }
915
916 private boolean isRecipientRoutedRequest(ActionRequestValue actionRequest, List<Recipient> recipients) throws WorkflowException {
917 for (Recipient recipient : recipients) {
918 if (actionRequest.isRecipientRoutedRequest(recipient)) {
919 return true;
920 }
921 }
922 return false;
923 }
924
925 @Override
926 public void reResolveRoleByDocTypeName(String documentTypeName, String roleName, String qualifiedRoleNameLabel) {
927 incomingParamCheck(documentTypeName, "documentTypeName");
928 incomingParamCheck(roleName, "roleName");
929 incomingParamCheck(qualifiedRoleNameLabel, "qualifiedRoleNameLabel");
930 if ( LOG.isDebugEnabled() ) {
931 LOG.debug("Re-resolving Role [docTypeName=" + documentTypeName + ", roleName=" + roleName + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel + "]");
932 }
933 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
934 if (org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
935 KEWServiceLocator.getRoleService().reResolveRole(documentType, roleName);
936 } else {
937 KEWServiceLocator.getRoleService().reResolveQualifiedRole(documentType, roleName, qualifiedRoleNameLabel);
938 }
939 }
940
941 public void reResolveRoleByDocumentId(String documentId, String roleName, String qualifiedRoleNameLabel) {
942 incomingParamCheck(documentId, "documentId");
943 incomingParamCheck(roleName, "roleName");
944 incomingParamCheck(qualifiedRoleNameLabel, "qualifiedRoleNameLabel");
945 if ( LOG.isDebugEnabled() ) {
946 LOG.debug("Re-resolving Role [documentId=" + documentId + ", roleName=" + roleName + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel + "]");
947 }
948 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
949 if (org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
950 KEWServiceLocator.getRoleService().reResolveRole(routeHeader, roleName);
951 } else {
952 KEWServiceLocator.getRoleService().reResolveQualifiedRole(routeHeader, roleName, qualifiedRoleNameLabel);
953 }
954 }
955
956 @Override
957 public List<RemotableAttributeError> validateWorkflowAttributeDefinition(
958 WorkflowAttributeDefinition definition) {
959 if (definition == null) {
960 throw new RiceIllegalArgumentException("definition was null");
961 }
962 if ( LOG.isDebugEnabled() ) {
963 LOG.debug("Validating WorkflowAttributeDefinition [attributeName="+definition.getAttributeName()+"]");
964 }
965 AttributeDefinition attributeDefinition = DTOConverter.convertWorkflowAttributeDefinition(definition);
966 WorkflowRuleAttribute attribute = null;
967 if (attributeDefinition != null) {
968 attribute = (WorkflowRuleAttribute) GlobalResourceLoader.getObject(attributeDefinition.getObjectDefinition());
969 }
970 if (attribute instanceof GenericXMLRuleAttribute) {
971 Map<String, String> attributePropMap = new HashMap<String, String>();
972 GenericXMLRuleAttribute xmlAttribute = (GenericXMLRuleAttribute)attribute;
973 xmlAttribute.setExtensionDefinition(attributeDefinition.getExtensionDefinition());
974 for (PropertyDefinition propertyDefinition : definition.getPropertyDefinitions()) {
975 attributePropMap.put(propertyDefinition.getName(), propertyDefinition.getValue());
976 }
977 xmlAttribute.setParamMap(attributePropMap);
978 }
979 List<RemotableAttributeError> errors = new ArrayList<RemotableAttributeError>();
980
981 if (attribute instanceof WorkflowAttributeXmlValidator) {
982 List<? extends RemotableAttributeErrorContract> validationErrors = ((WorkflowAttributeXmlValidator)attribute).validateClientRoutingData();
983 if (validationErrors != null) {
984 for (RemotableAttributeErrorContract validationError : validationErrors) {
985 errors.add(RemotableAttributeError.Builder.create(validationError).build());
986 }
987 }
988 }
989 return errors;
990 }
991
992 @Override
993 public boolean isFinalApprover(String documentId, String principalId) {
994 incomingParamCheck(documentId, "documentId");
995 incomingParamCheck(principalId, "principalId");
996 if ( LOG.isDebugEnabled() ) {
997 LOG.debug("Evaluating isFinalApprover [docId=" + documentId + ", principalId=" + principalId + "]");
998 }
999 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
1000 List<ActionRequestValue> requests = KEWServiceLocator.getActionRequestService().findPendingByDoc(documentId);
1001 List<RouteNode> finalApproverNodes = KEWServiceLocator.getRouteNodeService().findFinalApprovalRouteNodes(routeHeader.getDocumentType().getDocumentTypeId());
1002 if (finalApproverNodes.isEmpty()) {
1003 if ( LOG.isDebugEnabled() ) {
1004 LOG.debug("Could not locate final approval nodes for document " + documentId);
1005 }
1006 return false;
1007 }
1008 Set<String> finalApproverNodeNames = new HashSet<String>();
1009 for (RouteNode node : finalApproverNodes) {
1010 finalApproverNodeNames.add(node.getRouteNodeName());
1011 }
1012
1013 int approveRequest = 0;
1014 for (ActionRequestValue request : requests) {
1015 RouteNodeInstance nodeInstance = request.getNodeInstance();
1016 if (nodeInstance == null) {
1017 if ( LOG.isDebugEnabled() ) {
1018 LOG.debug("Found an action request on the document with a null node instance, indicating EXCEPTION routing.");
1019 }
1020 return false;
1021 }
1022 if (finalApproverNodeNames.contains(nodeInstance.getRouteNode().getRouteNodeName())) {
1023 if (request.isApproveOrCompleteRequest()) {
1024 approveRequest++;
1025 if ( LOG.isDebugEnabled() ) {
1026 LOG.debug("Found request is approver " + request.getActionRequestId());
1027 }
1028 if (! request.isRecipientRoutedRequest(principalId)) {
1029 if ( LOG.isDebugEnabled() ) {
1030 LOG.debug("Action Request not for user " + principalId);
1031 }
1032 return false;
1033 }
1034 }
1035 }
1036 }
1037
1038 if (approveRequest == 0) {
1039 return false;
1040 }
1041 if ( LOG.isDebugEnabled() ) {
1042 LOG.debug("Principal "+principalId+" is final approver for document " + documentId);
1043 }
1044 return true;
1045 }
1046
1047 @Override
1048 public boolean routeNodeHasApproverActionRequest(String documentTypeName, String docContent, String nodeName) {
1049 incomingParamCheck(documentTypeName, "documentTypeName");
1050 incomingParamCheck(docContent, "docContent");
1051 incomingParamCheck(nodeName, "nodeName");
1052 if ( LOG.isDebugEnabled() ) {
1053 LOG.debug("Evaluating routeNodeHasApproverActionRequest [docTypeName=" + documentTypeName + ", nodeName=" + nodeName + "]");
1054 }
1055 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
1056 RouteNode routeNode = KEWServiceLocator.getRouteNodeService().findRouteNodeByName(documentType.getDocumentTypeId(), nodeName);
1057 return routeNodeHasApproverActionRequest(documentType, docContent, routeNode, new Integer(KewApiConstants.INVALID_ROUTE_LEVEL));
1058 }
1059
1060
1061
1062
1063
1064 private boolean routeNodeHasApproverActionRequest(DocumentType documentType, String docContent, RouteNode node, Integer routeLevel) {
1065 incomingParamCheck(documentType, "documentType");
1066 incomingParamCheck(docContent, "docContent");
1067 incomingParamCheck(node, "node");
1068 incomingParamCheck(routeLevel, "routeLevel");
1069
1070
1071
1072
1073
1074
1075
1076
1077 RoutingReportCriteria.Builder builder = RoutingReportCriteria.Builder.createByDocumentTypeName(documentType.getName());
1078 builder.setTargetNodeName(node.getName());
1079 builder.setXmlContent(docContent);
1080 DocumentDetail docDetail = executeSimulation(builder.build());
1081 if (docDetail != null) {
1082 for (ActionRequest actionRequest : docDetail.getActionRequests()) {
1083 if (actionRequest.isApprovalRequest()) {
1084 return true;
1085 }
1086 }
1087 }
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107 return false;
1108 }
1109
1110 @Override
1111 public boolean isLastApproverAtNode(String documentId, String principalId, String nodeName) {
1112 incomingParamCheck(documentId, "documentId");
1113 incomingParamCheck(principalId, "principalId");
1114 incomingParamCheck(nodeName, "nodeName");
1115 if ( LOG.isDebugEnabled() ) {
1116 LOG.debug("Evaluating isLastApproverAtNode [docId=" + documentId + ", principalId=" + principalId + ", nodeName=" + nodeName + "]");
1117 }
1118 loadDocument(documentId);
1119
1120
1121
1122 Boolean activateFirst = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(
1123 KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.FEATURE_DETAIL_TYPE, KewApiConstants.IS_LAST_APPROVER_ACTIVATE_FIRST_IND);
1124 if (activateFirst == null) {
1125 activateFirst = Boolean.FALSE;
1126 }
1127
1128 List<ActionRequestValue> requests = KEWServiceLocator.getActionRequestService().findPendingByDocRequestCdNodeName(documentId, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, nodeName);
1129 if (requests == null || requests.isEmpty()) {
1130 return false;
1131 }
1132
1133
1134 List<ActionRequestValue> copiedRequests = new ArrayList<ActionRequestValue>();
1135 for (ActionRequestValue request : requests) {
1136 ActionRequestValue actionRequest = (ActionRequestValue) ObjectUtils.deepCopy(
1137 (ActionRequestValue) request);
1138
1139 for (ActionItem actionItem : actionRequest.getActionItems()) {
1140 actionRequest.getSimulatedActionItems().add((ActionItem) ObjectUtils.deepCopy(actionItem));
1141 }
1142 copiedRequests.add(actionRequest);
1143 }
1144
1145 ActivationContext activationContext = new ActivationContext(ActivationContext.CONTEXT_IS_SIMULATION);
1146 for (ActionRequestValue request : copiedRequests) {
1147 if (activateFirst.booleanValue() && !request.isActive()) {
1148 KEWServiceLocator.getActionRequestService().activateRequest(request, activationContext);
1149 }
1150 if (request.isUserRequest() && request.getPrincipalId().equals(principalId)) {
1151 KEWServiceLocator.getActionRequestService().deactivateRequest(null, request, activationContext);
1152 } else if (request.isGroupRequest() && KimApiServiceLocator.getGroupService().isMemberOfGroup(principalId, request.getGroup().getId())) {
1153 KEWServiceLocator.getActionRequestService().deactivateRequest(null, request, activationContext);
1154 }
1155 }
1156 boolean allDeactivated = true;
1157 for (ActionRequestValue actionRequest: copiedRequests) {
1158 allDeactivated = allDeactivated && actionRequest.isDeactivated();
1159 }
1160 return allDeactivated;
1161 }
1162
1163 @Override
1164 public boolean isUserInRouteLog(String documentId, String principalId, boolean lookFuture) {
1165 incomingParamCheck(documentId, "documentId");
1166 incomingParamCheck(principalId, "principalId");
1167 return isUserInRouteLogWithOptionalFlattening(documentId, principalId, lookFuture, false);
1168 }
1169
1170 @Override
1171 public boolean isUserInRouteLogWithOptionalFlattening(String documentId, String principalId, boolean lookFuture, boolean flattenNodes) {
1172 incomingParamCheck(documentId, "documentId");
1173 incomingParamCheck(principalId, "principalId");
1174 boolean authorized = false;
1175 if ( LOG.isDebugEnabled() ) {
1176 LOG.debug("Evaluating isUserInRouteLog [docId=" + documentId + ", principalId=" + principalId + ", lookFuture=" + lookFuture + "]");
1177 }
1178 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
1179 if (routeHeader == null) {
1180 throw new IllegalArgumentException("Document for documentId: " + documentId + " does not exist");
1181 }
1182 Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(principalId);
1183 if (principal == null) {
1184 throw new IllegalArgumentException("Principal for principalId: " + principalId + " does not exist");
1185 }
1186 List<ActionTakenValue> actionsTaken = KEWServiceLocator.getActionTakenService().findByDocumentIdWorkflowId(documentId, principal.getPrincipalId());
1187
1188 if(routeHeader.getInitiatorWorkflowId().equals(principal.getPrincipalId())){
1189 return true;
1190 }
1191
1192 if (!actionsTaken.isEmpty()) {
1193 LOG.debug("found action taken by user");
1194 authorized = true;
1195 }
1196
1197 List<ActionRequestValue> actionRequests = KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
1198 if (actionRequestListHasPrincipal(principal, actionRequests)) {
1199 authorized = true;
1200 }
1201
1202 if (!lookFuture || authorized) {
1203 return authorized;
1204 }
1205
1206
1207 SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
1208 SimulationCriteria criteria = SimulationCriteria.createSimulationCritUsingDocumentId(documentId);
1209 criteria.setDestinationNodeName(null);
1210 criteria.getDestinationRecipients().add(new KimPrincipalRecipient(principal));
1211 criteria.setFlattenNodes(flattenNodes);
1212
1213 try {
1214 SimulationResults results = simulationEngine.runSimulation(criteria);
1215 if (actionRequestListHasPrincipal(principal, results.getSimulatedActionRequests())) {
1216 authorized = true;
1217 }
1218 } catch (Exception e) {
1219 throw new RiceRuntimeException(e);
1220 }
1221
1222 return authorized;
1223 }
1224
1225 private boolean actionRequestListHasPrincipal(Principal principal, List<ActionRequestValue> actionRequests) {
1226 for (ActionRequestValue actionRequest : actionRequests) {
1227 if (actionRequest.isRecipientRoutedRequest(new KimPrincipalRecipient(principal))) {
1228 return true;
1229 }
1230 }
1231 return false;
1232 }
1233
1234 public List<String> getPrincipalIdsInRouteLog(String documentId, boolean lookFuture) {
1235 if (StringUtils.isEmpty(documentId)) {
1236 throw new IllegalArgumentException("documentId passed in is null or blank");
1237 }
1238 Set<String> principalIds = new HashSet<String>();
1239 try {
1240 if ( LOG.isDebugEnabled() ) {
1241 LOG.debug("Evaluating isUserInRouteLog [docId=" + documentId + ", lookFuture=" + lookFuture + "]");
1242 }
1243 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
1244 List<ActionTakenValue> actionsTakens =
1245 (List<ActionTakenValue>)KEWServiceLocator.getActionTakenService().findByDocumentId(documentId);
1246
1247 principalIds.add(routeHeader.getInitiatorWorkflowId());
1248 for(ActionTakenValue actionTaken: actionsTakens){
1249 principalIds.add(actionTaken.getPrincipalId());
1250 }
1251 List<ActionRequestValue> actionRequests =
1252 KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
1253 for(ActionRequestValue actionRequest: actionRequests){
1254 principalIds.addAll(getPrincipalIdsForActionRequest(actionRequest));
1255 }
1256 if (!lookFuture) {
1257 return new ArrayList<String>(principalIds);
1258 }
1259 SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
1260 SimulationCriteria criteria = SimulationCriteria.createSimulationCritUsingDocumentId(documentId);
1261 criteria.setDestinationNodeName(null);
1262 SimulationResults results = simulationEngine.runSimulation(criteria);
1263 actionRequests = (List<ActionRequestValue>)results.getSimulatedActionRequests();
1264 for(ActionRequestValue actionRequest: actionRequests){
1265 principalIds.addAll(getPrincipalIdsForActionRequest(actionRequest));
1266 }
1267 } catch (Exception ex) {
1268 LOG.warn("Problems getting principalIds in Route Log for documentId: "+documentId+". Exception:"+ex.getMessage(),ex);
1269 }
1270 return new ArrayList<String>(principalIds);
1271 }
1272
1273 private DocumentRouteHeaderValue loadDocument(String documentId) {
1274 return KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
1275 }
1276
1277
1278
1279
1280
1281
1282
1283 private List<String> getPrincipalIdsForActionRequest(ActionRequestValue actionRequest) {
1284 List<String> results = Collections.emptyList();
1285 if (actionRequest.getPrincipalId() != null) {
1286 results = Collections.singletonList(actionRequest.getPrincipalId());
1287 } else if (actionRequest.getGroupId() != null) {
1288 List<String> principalIdsForGroup =
1289 KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequest.getGroupId());
1290 if (principalIdsForGroup != null) {
1291 results = principalIdsForGroup;
1292 }
1293 }
1294 return results;
1295 }
1296
1297 private void incomingParamCheck(Object object, String name) {
1298 if (object == null) {
1299 throw new RiceIllegalArgumentException(name + " was null");
1300 } else if (object instanceof String
1301 && StringUtils.isBlank((String) object)) {
1302 throw new RiceIllegalArgumentException(name + " was blank");
1303 }
1304 }
1305
1306 public void setDocumentTypeService(DocumentTypeService documentTypeService) {
1307 this.documentTypeService = documentTypeService;
1308 }
1309
1310
1311
1312
1313
1314 private void translateException(WorkflowException e) {
1315 if (e instanceof org.kuali.rice.kew.api.exception.InvalidActionTakenException) {
1316 throw new InvalidActionTakenException(e.getMessage(), e);
1317 }
1318 throw new WorkflowRuntimeException(e.getMessage(), e);
1319 }
1320
1321 protected DocumentActionResult executeActionInternal(DocumentActionParameters parameters,
1322 DocumentActionCallback callback) {
1323 if (parameters == null) {
1324 throw new RiceIllegalArgumentException("Document action parameters was null.");
1325 }
1326 if (LOG.isDebugEnabled()) {
1327 LOG.debug(callback.getLogMessage(parameters.getDocumentId(), parameters.getPrincipalId(),
1328 parameters.getAnnotation()));
1329 }
1330 DocumentRouteHeaderValue documentBo = init(parameters);
1331 try {
1332 documentBo = callback.doInDocumentBo(documentBo, parameters.getPrincipalId(), parameters.getAnnotation());
1333 } catch (WorkflowException e) {
1334
1335 translateException(e);
1336 }
1337 return constructDocumentActionResult(documentBo, parameters.getPrincipalId());
1338 }
1339
1340 protected static interface DocumentActionCallback {
1341
1342 DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
1343 String annotation) throws WorkflowException;
1344
1345 String getLogMessage(String documentId, String principalId, String annotation);
1346
1347 }
1348
1349 protected static abstract class StandardDocumentActionCallback implements DocumentActionCallback {
1350
1351 public final String getLogMessage(String documentId, String principalId, String annotation) {
1352 return getActionName() + " [principalId=" + principalId + ", documentId=" + documentId + ", annotation="
1353 + annotation + "]";
1354 }
1355
1356 protected abstract String getActionName();
1357
1358 }
1359
1360 }