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