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