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.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.KewApiConstants;
33 import org.kuali.rice.kew.api.KewApiServiceLocator;
34 import org.kuali.rice.kew.api.WorkflowRuntimeException;
35 import org.kuali.rice.kew.api.action.ActionRequest;
36 import org.kuali.rice.kew.api.action.ActionRequestType;
37 import org.kuali.rice.kew.api.action.ActionType;
38 import org.kuali.rice.kew.api.action.AdHocRevoke;
39 import org.kuali.rice.kew.api.action.AdHocToGroup;
40 import org.kuali.rice.kew.api.action.AdHocToGroup_v2_1_2;
41 import org.kuali.rice.kew.api.action.AdHocToPrincipal;
42 import org.kuali.rice.kew.api.action.AdHocToPrincipal_v2_1_2;
43 import org.kuali.rice.kew.api.action.DocumentActionParameters;
44 import org.kuali.rice.kew.api.action.DocumentActionResult;
45 import org.kuali.rice.kew.api.action.InvalidActionTakenException;
46 import org.kuali.rice.kew.api.action.MovePoint;
47 import org.kuali.rice.kew.api.action.RequestedActions;
48 import org.kuali.rice.kew.api.action.ReturnPoint;
49 import org.kuali.rice.kew.api.action.RoutingReportCriteria;
50 import org.kuali.rice.kew.api.action.ValidActions;
51 import org.kuali.rice.kew.api.action.WorkflowDocumentActionsService;
52 import org.kuali.rice.kew.api.doctype.DocumentTypeService;
53 import org.kuali.rice.kew.api.doctype.IllegalDocumentTypeException;
54 import org.kuali.rice.kew.api.document.Document;
55 import org.kuali.rice.kew.api.document.DocumentContentUpdate;
56 import org.kuali.rice.kew.api.document.DocumentDetail;
57 import org.kuali.rice.kew.api.document.DocumentUpdate;
58 import org.kuali.rice.kew.api.document.PropertyDefinition;
59 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeIndexingQueue;
60 import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
61 import org.kuali.rice.kew.api.exception.WorkflowException;
62 import org.kuali.rice.kew.definition.AttributeDefinition;
63 import org.kuali.rice.kew.doctype.bo.DocumentType;
64 import org.kuali.rice.kew.dto.DTOConverter;
65 import org.kuali.rice.kew.engine.ActivationContext;
66 import org.kuali.rice.kew.engine.node.RouteNode;
67 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
68 import org.kuali.rice.kew.engine.simulation.SimulationCriteria;
69 import org.kuali.rice.kew.engine.simulation.SimulationResults;
70 import org.kuali.rice.kew.engine.simulation.SimulationWorkflowEngine;
71 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
72 import org.kuali.rice.kew.rule.WorkflowAttributeXmlValidator;
73 import org.kuali.rice.kew.rule.WorkflowRuleAttribute;
74 import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute;
75 import org.kuali.rice.kew.service.KEWServiceLocator;
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 DocumentRouteHeaderValue documentBo = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
766 if (documentBo.getDocumentType().hasSearchableAttributes()) {
767 DocumentAttributeIndexingQueue queue = KewApiServiceLocator.getDocumentAttributeIndexingQueue(documentBo.getDocumentType().getApplicationId());
768 queue.indexDocument(documentId);
769 }
770 }
771
772 @Override
773 public DocumentActionResult superUserBlanketApprove(DocumentActionParameters parameters,
774 final boolean executePostProcessor) {
775 incomingParamCheck(parameters, "parameters");
776 return executeActionInternal(parameters,
777 new DocumentActionCallback() {
778 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
779 String principalId, String annotation) throws WorkflowException {
780 return KEWServiceLocator.getWorkflowDocumentService().superUserApprove(principalId, documentBo,
781 annotation, executePostProcessor);
782 }
783
784 public String getLogMessage(String documentId, String principalId, String annotation) {
785 return "SU Blanket Approve [principalId=" + principalId + ", documentId=" + documentId
786 + ", annotation=" + annotation + "]";
787 }
788 });
789 }
790
791 @Override
792 public DocumentActionResult superUserNodeApprove(DocumentActionParameters parameters,
793 final boolean executePostProcessor, final String nodeName) {
794 incomingParamCheck(parameters, "parameters");
795 incomingParamCheck(nodeName, "nodeName");
796 return executeActionInternal(parameters,
797 new DocumentActionCallback() {
798 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
799 String principalId, String annotation) throws WorkflowException {
800 return KEWServiceLocator.getWorkflowDocumentService().superUserNodeApproveAction(principalId,
801 documentBo, nodeName, annotation, executePostProcessor);
802 }
803
804 public String getLogMessage(String documentId, String principalId, String annotation) {
805 return "SU Node Approve Action [principalId=" + principalId + ", documentId=" + documentId
806 + ", nodeName=" + nodeName + ", annotation=" + annotation + "]";
807 }
808 });
809
810 }
811
812 @Override
813 public DocumentActionResult superUserTakeRequestedAction(DocumentActionParameters parameters,
814 final boolean executePostProcessor, final String actionRequestId) {
815 incomingParamCheck(parameters, "parameters");
816 incomingParamCheck(actionRequestId, "actionRequestId");
817 return executeActionInternal(parameters,
818 new DocumentActionCallback() {
819 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
820 String principalId, String annotation) throws WorkflowException {
821 return KEWServiceLocator.getWorkflowDocumentService().superUserActionRequestApproveAction(
822 principalId, documentBo, actionRequestId, annotation,
823 executePostProcessor);
824 }
825
826 public String getLogMessage(String documentId, String principalId, String annotation) {
827 return "SU Take Requested Action [principalId=" + principalId + ", docume tId=" + documentId
828 + ", actionRequestId=" + actionRequestId + ", annotation=" + annotation + "]";
829 }
830 });
831 }
832
833 @Override
834 public DocumentActionResult superUserDisapprove(DocumentActionParameters parameters,
835 final boolean executePostProcessor) {
836 incomingParamCheck(parameters, "parameters");
837 return executeActionInternal(parameters,
838 new DocumentActionCallback() {
839 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
840 String principalId, String annotation) throws WorkflowException {
841 return KEWServiceLocator.getWorkflowDocumentService().superUserDisapproveAction(principalId,
842 documentBo, annotation, executePostProcessor);
843 }
844
845 public String getLogMessage(String documentId, String principalId, String annotation) {
846 return "SU Disapprove [principalId=" + principalId + ", documentId=" + documentId
847 + ", annotation=" + annotation + "]";
848 }
849 });
850 }
851
852 @Override
853 public DocumentActionResult superUserCancel(DocumentActionParameters parameters, final boolean executePostProcessor) {
854 incomingParamCheck(parameters, "parameters");
855 return executeActionInternal(parameters,
856 new DocumentActionCallback() {
857 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
858 String principalId, String annotation) throws WorkflowException {
859 return KEWServiceLocator.getWorkflowDocumentService().superUserCancelAction(principalId,
860 documentBo, annotation, executePostProcessor);
861 }
862
863 public String getLogMessage(String documentId, String principalId, String annotation) {
864 return "SU Cancel [principalId=" + principalId + ", documentId=" + documentId + ", annotation="
865 + annotation + "]";
866 }
867 });
868 }
869
870 @Override
871 public DocumentActionResult superUserReturnToPreviousNode(DocumentActionParameters parameters,
872 final boolean executePostProcessor, final ReturnPoint returnPoint) {
873 incomingParamCheck(parameters, "parameters");
874 incomingParamCheck(returnPoint, "returnPoint");
875 return executeActionInternal(parameters,
876 new DocumentActionCallback() {
877 public DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo,
878 String principalId, String annotation) throws WorkflowException {
879 return KEWServiceLocator.getWorkflowDocumentService().superUserReturnDocumentToPreviousNode(
880 principalId, documentBo, returnPoint.getNodeName(), annotation, executePostProcessor);
881 }
882
883 public String getLogMessage(String documentId, String principalId, String annotation) {
884 return "SU Return to Previous Node [principalId=" + principalId + ", documentId=" + documentId
885 + ", annotation=" + annotation + ", returnPoint=" + returnPoint + "]";
886 }
887 });
888
889 }
890
891 @Override
892 public DocumentActionResult placeInExceptionRouting(DocumentActionParameters parameters) {
893 incomingParamCheck(parameters, "parameters");
894 return executeActionInternal(parameters, PLACE_IN_EXCEPTION_CALLBACK);
895 }
896
897 @Override
898 public boolean documentWillHaveAtLeastOneActionRequest(RoutingReportCriteria reportCriteria, List<String> actionRequestedCodes, boolean ignoreCurrentActionRequests) {
899 incomingParamCheck(reportCriteria, "reportCriteria");
900 incomingParamCheck(actionRequestedCodes, "actionRequestedCodes");
901 try {
902 SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
903 SimulationCriteria criteria = SimulationCriteria.from(reportCriteria);
904
905 criteria.setActivateRequests(Boolean.TRUE);
906 SimulationResults results = simulationEngine.runSimulation(criteria);
907 List<ActionRequestValue> actionRequestsToProcess = results.getSimulatedActionRequests();
908 if (!ignoreCurrentActionRequests) {
909 actionRequestsToProcess.addAll(results.getDocument().getActionRequests());
910 }
911 for (ActionRequestValue actionRequest : actionRequestsToProcess) {
912 if (actionRequest.isDone()) {
913
914 continue;
915 }
916
917 if (CollectionUtils.isEmpty(actionRequestedCodes) ) {
918
919 return true;
920 }
921
922 for (String requestedActionRequestCode : actionRequestedCodes) {
923 if (requestedActionRequestCode.equals(actionRequest.getActionRequested())) {
924 boolean satisfiesDestinationUserCriteria = (criteria.getDestinationRecipients().isEmpty()) || (isRecipientRoutedRequest(actionRequest,criteria.getDestinationRecipients()));
925 if (satisfiesDestinationUserCriteria) {
926 if (StringUtils.isBlank(criteria.getDestinationNodeName())) {
927 return true;
928 } else if (StringUtils.equals(criteria.getDestinationNodeName(),actionRequest.getNodeInstance().getName())) {
929 return true;
930 }
931 }
932 }
933 }
934 }
935 return false;
936 } catch (Exception ex) {
937 String error = "Problems evaluating documentWillHaveAtLeastOneActionRequest: " + ex.getMessage();
938 LOG.error(error,ex);
939 if (ex instanceof RuntimeException) {
940 throw (RuntimeException)ex;
941 }
942 throw new RuntimeException(error, ex);
943 }
944 }
945
946 private boolean isRecipientRoutedRequest(ActionRequestValue actionRequest, List<Recipient> recipients) throws WorkflowException {
947 for (Recipient recipient : recipients) {
948 if (actionRequest.isRecipientRoutedRequest(recipient)) {
949 return true;
950 }
951 }
952 return false;
953 }
954
955 @Override
956 public void reResolveRoleByDocTypeName(String documentTypeName, String roleName, String qualifiedRoleNameLabel) {
957 incomingParamCheck(documentTypeName, "documentTypeName");
958 incomingParamCheck(roleName, "roleName");
959 incomingParamCheck(qualifiedRoleNameLabel, "qualifiedRoleNameLabel");
960 if ( LOG.isDebugEnabled() ) {
961 LOG.debug("Re-resolving Role [docTypeName=" + documentTypeName + ", roleName=" + roleName + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel + "]");
962 }
963 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
964 if (org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
965 KEWServiceLocator.getRoleService().reResolveRole(documentType, roleName);
966 } else {
967 KEWServiceLocator.getRoleService().reResolveQualifiedRole(documentType, roleName, qualifiedRoleNameLabel);
968 }
969 }
970
971 public void reResolveRoleByDocumentId(String documentId, String roleName, String qualifiedRoleNameLabel) {
972 incomingParamCheck(documentId, "documentId");
973 incomingParamCheck(roleName, "roleName");
974 incomingParamCheck(qualifiedRoleNameLabel, "qualifiedRoleNameLabel");
975 if ( LOG.isDebugEnabled() ) {
976 LOG.debug("Re-resolving Role [documentId=" + documentId + ", roleName=" + roleName + ", qualifiedRoleNameLabel=" + qualifiedRoleNameLabel + "]");
977 }
978 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
979 if (org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
980 KEWServiceLocator.getRoleService().reResolveRole(routeHeader, roleName);
981 } else {
982 KEWServiceLocator.getRoleService().reResolveQualifiedRole(routeHeader, roleName, qualifiedRoleNameLabel);
983 }
984 }
985
986 @Override
987 public List<RemotableAttributeError> validateWorkflowAttributeDefinition(
988 WorkflowAttributeDefinition definition) {
989 if (definition == null) {
990 throw new RiceIllegalArgumentException("definition was null");
991 }
992 if ( LOG.isDebugEnabled() ) {
993 LOG.debug("Validating WorkflowAttributeDefinition [attributeName="+definition.getAttributeName()+"]");
994 }
995 AttributeDefinition attributeDefinition = DTOConverter.convertWorkflowAttributeDefinition(definition);
996 WorkflowRuleAttribute attribute = null;
997 if (attributeDefinition != null) {
998 attribute = (WorkflowRuleAttribute) GlobalResourceLoader.getObject(attributeDefinition.getObjectDefinition());
999 }
1000 if (attribute instanceof GenericXMLRuleAttribute) {
1001 Map<String, String> attributePropMap = new HashMap<String, String>();
1002 GenericXMLRuleAttribute xmlAttribute = (GenericXMLRuleAttribute)attribute;
1003 xmlAttribute.setExtensionDefinition(attributeDefinition.getExtensionDefinition());
1004 for (PropertyDefinition propertyDefinition : definition.getPropertyDefinitions()) {
1005 attributePropMap.put(propertyDefinition.getName(), propertyDefinition.getValue());
1006 }
1007 xmlAttribute.setParamMap(attributePropMap);
1008 }
1009 List<RemotableAttributeError> errors = new ArrayList<RemotableAttributeError>();
1010
1011 if (attribute instanceof WorkflowAttributeXmlValidator) {
1012 List<? extends RemotableAttributeErrorContract> validationErrors = ((WorkflowAttributeXmlValidator)attribute).validateClientRoutingData();
1013 if (validationErrors != null) {
1014 for (RemotableAttributeErrorContract validationError : validationErrors) {
1015 errors.add(RemotableAttributeError.Builder.create(validationError).build());
1016 }
1017 }
1018 }
1019 return errors;
1020 }
1021
1022 @Override
1023 public boolean isFinalApprover(String documentId, String principalId) {
1024 incomingParamCheck(documentId, "documentId");
1025 incomingParamCheck(principalId, "principalId");
1026 if ( LOG.isDebugEnabled() ) {
1027 LOG.debug("Evaluating isFinalApprover [docId=" + documentId + ", principalId=" + principalId + "]");
1028 }
1029 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
1030 List<ActionRequestValue> requests = KEWServiceLocator.getActionRequestService().findPendingByDoc(documentId);
1031 List<RouteNode> finalApproverNodes = KEWServiceLocator.getRouteNodeService().findFinalApprovalRouteNodes(routeHeader.getDocumentType().getDocumentTypeId());
1032 if (finalApproverNodes.isEmpty()) {
1033 if ( LOG.isDebugEnabled() ) {
1034 LOG.debug("Could not locate final approval nodes for document " + documentId);
1035 }
1036 return false;
1037 }
1038 Set<String> finalApproverNodeNames = new HashSet<String>();
1039 for (RouteNode node : finalApproverNodes) {
1040 finalApproverNodeNames.add(node.getRouteNodeName());
1041 }
1042
1043 int approveRequest = 0;
1044 for (ActionRequestValue request : requests) {
1045 RouteNodeInstance nodeInstance = request.getNodeInstance();
1046 if (nodeInstance == null) {
1047 if ( LOG.isDebugEnabled() ) {
1048 LOG.debug("Found an action request on the document with a null node instance, indicating EXCEPTION routing.");
1049 }
1050 return false;
1051 }
1052 if (finalApproverNodeNames.contains(nodeInstance.getRouteNode().getRouteNodeName())) {
1053 if (request.isApproveOrCompleteRequest()) {
1054 approveRequest++;
1055 if ( LOG.isDebugEnabled() ) {
1056 LOG.debug("Found request is approver " + request.getActionRequestId());
1057 }
1058 if (! request.isRecipientRoutedRequest(principalId)) {
1059 if ( LOG.isDebugEnabled() ) {
1060 LOG.debug("Action Request not for user " + principalId);
1061 }
1062 return false;
1063 }
1064 }
1065 }
1066 }
1067
1068 if (approveRequest == 0) {
1069 return false;
1070 }
1071 if ( LOG.isDebugEnabled() ) {
1072 LOG.debug("Principal "+principalId+" is final approver for document " + documentId);
1073 }
1074 return true;
1075 }
1076
1077 @Override
1078 public boolean routeNodeHasApproverActionRequest(String documentTypeName, String docContent, String nodeName) {
1079 incomingParamCheck(documentTypeName, "documentTypeName");
1080 incomingParamCheck(docContent, "docContent");
1081 incomingParamCheck(nodeName, "nodeName");
1082 if ( LOG.isDebugEnabled() ) {
1083 LOG.debug("Evaluating routeNodeHasApproverActionRequest [docTypeName=" + documentTypeName + ", nodeName=" + nodeName + "]");
1084 }
1085 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
1086 RouteNode routeNode = KEWServiceLocator.getRouteNodeService().findRouteNodeByName(documentType.getDocumentTypeId(), nodeName);
1087 return routeNodeHasApproverActionRequest(documentType, docContent, routeNode, new Integer(KewApiConstants.INVALID_ROUTE_LEVEL));
1088 }
1089
1090
1091
1092
1093
1094 private boolean routeNodeHasApproverActionRequest(DocumentType documentType, String docContent, RouteNode node, Integer routeLevel) {
1095 incomingParamCheck(documentType, "documentType");
1096 incomingParamCheck(docContent, "docContent");
1097 incomingParamCheck(node, "node");
1098 incomingParamCheck(routeLevel, "routeLevel");
1099
1100
1101
1102
1103
1104
1105
1106 RoutingReportCriteria.Builder builder = RoutingReportCriteria.Builder.createByDocumentTypeName(documentType.getName());
1107 builder.setNodeNames(Collections.singletonList(node.getName()));
1108 builder.setXmlContent(docContent);
1109 DocumentDetail docDetail = executeSimulation(builder.build());
1110 if (docDetail != null) {
1111 for (ActionRequest actionRequest : docDetail.getActionRequests()) {
1112 if (actionRequest.isApprovalRequest()) {
1113 return true;
1114 }
1115 }
1116 }
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136 return false;
1137 }
1138
1139 @Override
1140 public boolean isLastApproverAtNode(String documentId, String principalId, String nodeName) {
1141 incomingParamCheck(documentId, "documentId");
1142 incomingParamCheck(principalId, "principalId");
1143 incomingParamCheck(nodeName, "nodeName");
1144 if ( LOG.isDebugEnabled() ) {
1145 LOG.debug("Evaluating isLastApproverAtNode [docId=" + documentId + ", principalId=" + principalId + ", nodeName=" + nodeName + "]");
1146 }
1147 loadDocument(documentId);
1148
1149
1150
1151 Boolean activateFirst = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(
1152 KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.FEATURE_DETAIL_TYPE, KewApiConstants.IS_LAST_APPROVER_ACTIVATE_FIRST_IND);
1153 if (activateFirst == null) {
1154 activateFirst = Boolean.FALSE;
1155 }
1156
1157 List<ActionRequestValue> requests = KEWServiceLocator.getActionRequestService().findPendingByDocRequestCdNodeName(documentId, KewApiConstants.ACTION_REQUEST_APPROVE_REQ, nodeName);
1158 if (requests == null || requests.isEmpty()) {
1159 return false;
1160 }
1161
1162
1163 List<ActionRequestValue> copiedRequests = new ArrayList<ActionRequestValue>();
1164 for (ActionRequestValue request : requests) {
1165 ActionRequestValue actionRequest = (ActionRequestValue) ObjectUtils.deepCopy(
1166 (ActionRequestValue) request);
1167
1168 for (ActionItem actionItem : actionRequest.getActionItems()) {
1169 actionRequest.getSimulatedActionItems().add((ActionItem) ObjectUtils.deepCopy(actionItem));
1170 }
1171 copiedRequests.add(actionRequest);
1172 }
1173
1174 ActivationContext activationContext = new ActivationContext(ActivationContext.CONTEXT_IS_SIMULATION);
1175 for (ActionRequestValue request : copiedRequests) {
1176 if (activateFirst.booleanValue() && !request.isActive()) {
1177 KEWServiceLocator.getActionRequestService().activateRequest(request, activationContext);
1178 }
1179 if (request.isUserRequest() && request.getPrincipalId().equals(principalId)) {
1180 KEWServiceLocator.getActionRequestService().deactivateRequest(null, request, activationContext);
1181 } else if (request.isGroupRequest() && KimApiServiceLocator.getGroupService().isMemberOfGroup(principalId, request.getGroup().getId())) {
1182 KEWServiceLocator.getActionRequestService().deactivateRequest(null, request, activationContext);
1183 }
1184 }
1185 boolean allDeactivated = true;
1186 for (ActionRequestValue actionRequest: copiedRequests) {
1187 allDeactivated = allDeactivated && actionRequest.isDeactivated();
1188 }
1189 return allDeactivated;
1190 }
1191
1192 @Override
1193 public boolean isUserInRouteLog(String documentId, String principalId, boolean lookFuture) {
1194 incomingParamCheck(documentId, "documentId");
1195 incomingParamCheck(principalId, "principalId");
1196 return isUserInRouteLogWithOptionalFlattening(documentId, principalId, lookFuture, false);
1197 }
1198
1199 @Override
1200 public boolean isUserInRouteLogWithOptionalFlattening(String documentId, String principalId, boolean lookFuture, boolean flattenNodes) {
1201 incomingParamCheck(documentId, "documentId");
1202 incomingParamCheck(principalId, "principalId");
1203 boolean authorized = false;
1204 if ( LOG.isDebugEnabled() ) {
1205 LOG.debug("Evaluating isUserInRouteLog [docId=" + documentId + ", principalId=" + principalId + ", lookFuture=" + lookFuture + "]");
1206 }
1207 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
1208 if (routeHeader == null) {
1209 throw new IllegalArgumentException("Document for documentId: " + documentId + " does not exist");
1210 }
1211 Principal principal = KEWServiceLocator.getIdentityHelperService().getPrincipal(principalId);
1212 if (principal == null) {
1213 throw new IllegalArgumentException("Principal for principalId: " + principalId + " does not exist");
1214 }
1215 List<ActionTakenValue> actionsTaken = KEWServiceLocator.getActionTakenService().findByDocumentIdWorkflowId(documentId, principal.getPrincipalId());
1216
1217 if(routeHeader.getInitiatorWorkflowId().equals(principal.getPrincipalId())){
1218 return true;
1219 }
1220
1221 if (!actionsTaken.isEmpty()) {
1222 LOG.debug("found action taken by user");
1223 authorized = true;
1224 }
1225
1226 List<ActionRequestValue> actionRequests = KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
1227 if (actionRequestListHasPrincipal(principal, actionRequests)) {
1228 authorized = true;
1229 }
1230
1231 if (!lookFuture || authorized) {
1232 return authorized;
1233 }
1234
1235
1236 SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
1237 SimulationCriteria criteria = SimulationCriteria.createSimulationCritUsingDocumentId(documentId);
1238 criteria.setDestinationNodeName(null);
1239 criteria.getDestinationRecipients().add(new KimPrincipalRecipient(principal));
1240 criteria.setFlattenNodes(flattenNodes);
1241
1242 try {
1243 SimulationResults results = simulationEngine.runSimulation(criteria);
1244 if (actionRequestListHasPrincipal(principal, results.getSimulatedActionRequests())) {
1245 authorized = true;
1246 }
1247 } catch (Exception e) {
1248 throw new RiceRuntimeException(e);
1249 }
1250
1251 return authorized;
1252 }
1253
1254 private boolean actionRequestListHasPrincipal(Principal principal, List<ActionRequestValue> actionRequests) {
1255 for (ActionRequestValue actionRequest : actionRequests) {
1256 if (actionRequest.isRecipientRoutedRequest(new KimPrincipalRecipient(principal))) {
1257 return true;
1258 }
1259 }
1260 return false;
1261 }
1262
1263 public List<String> getPrincipalIdsInRouteLog(String documentId, boolean lookFuture) {
1264 if (StringUtils.isEmpty(documentId)) {
1265 throw new IllegalArgumentException("documentId passed in is null or blank");
1266 }
1267 Set<String> principalIds = new HashSet<String>();
1268 try {
1269 if ( LOG.isDebugEnabled() ) {
1270 LOG.debug("Evaluating isUserInRouteLog [docId=" + documentId + ", lookFuture=" + lookFuture + "]");
1271 }
1272 DocumentRouteHeaderValue routeHeader = loadDocument(documentId);
1273 List<ActionTakenValue> actionsTakens =
1274 (List<ActionTakenValue>)KEWServiceLocator.getActionTakenService().findByDocumentId(documentId);
1275
1276 principalIds.add(routeHeader.getInitiatorWorkflowId());
1277 for(ActionTakenValue actionTaken: actionsTakens){
1278 principalIds.add(actionTaken.getPrincipalId());
1279 }
1280 List<ActionRequestValue> actionRequests =
1281 KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(documentId);
1282 for(ActionRequestValue actionRequest: actionRequests){
1283 principalIds.addAll(getPrincipalIdsForActionRequest(actionRequest));
1284 }
1285 if (!lookFuture) {
1286 return new ArrayList<String>(principalIds);
1287 }
1288 SimulationWorkflowEngine simulationEngine = KEWServiceLocator.getSimulationEngine();
1289 SimulationCriteria criteria = SimulationCriteria.createSimulationCritUsingDocumentId(documentId);
1290 criteria.setDestinationNodeName(null);
1291 SimulationResults results = simulationEngine.runSimulation(criteria);
1292 actionRequests = (List<ActionRequestValue>)results.getSimulatedActionRequests();
1293 for(ActionRequestValue actionRequest: actionRequests){
1294 principalIds.addAll(getPrincipalIdsForActionRequest(actionRequest));
1295 }
1296 } catch (Exception ex) {
1297 LOG.warn("Problems getting principalIds in Route Log for documentId: "+documentId+". Exception:"+ex.getMessage(),ex);
1298 }
1299 return new ArrayList<String>(principalIds);
1300 }
1301
1302 private DocumentRouteHeaderValue loadDocument(String documentId) {
1303 return KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
1304 }
1305
1306
1307
1308
1309
1310
1311
1312 private List<String> getPrincipalIdsForActionRequest(ActionRequestValue actionRequest) {
1313 List<String> results = Collections.emptyList();
1314 if (actionRequest.getPrincipalId() != null) {
1315 results = Collections.singletonList(actionRequest.getPrincipalId());
1316 } else if (actionRequest.getGroupId() != null) {
1317 List<String> principalIdsForGroup =
1318 KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequest.getGroupId());
1319 if (principalIdsForGroup != null) {
1320 results = principalIdsForGroup;
1321 }
1322 }
1323 return results;
1324 }
1325
1326 private void incomingParamCheck(Object object, String name) {
1327 if (object == null) {
1328 throw new RiceIllegalArgumentException(name + " was null");
1329 } else if (object instanceof String
1330 && StringUtils.isBlank((String) object)) {
1331 throw new RiceIllegalArgumentException(name + " was blank");
1332 }
1333 }
1334
1335 public void setDocumentTypeService(DocumentTypeService documentTypeService) {
1336 this.documentTypeService = documentTypeService;
1337 }
1338
1339
1340
1341
1342
1343 private void translateException(WorkflowException e) {
1344 if (e instanceof org.kuali.rice.kew.api.exception.InvalidActionTakenException) {
1345 throw new InvalidActionTakenException(e.getMessage(), e);
1346 }
1347 throw new WorkflowRuntimeException(e.getMessage(), e);
1348 }
1349
1350 protected DocumentActionResult executeActionInternal(DocumentActionParameters parameters,
1351 DocumentActionCallback callback) {
1352 if (parameters == null) {
1353 throw new RiceIllegalArgumentException("Document action parameters was null.");
1354 }
1355 if (LOG.isDebugEnabled()) {
1356 LOG.debug(callback.getLogMessage(parameters.getDocumentId(), parameters.getPrincipalId(),
1357 parameters.getAnnotation()));
1358 }
1359 DocumentRouteHeaderValue documentBo = init(parameters);
1360 try {
1361 documentBo = callback.doInDocumentBo(documentBo, parameters.getPrincipalId(), parameters.getAnnotation());
1362 } catch (WorkflowException e) {
1363
1364 translateException(e);
1365 }
1366 return constructDocumentActionResult(documentBo, parameters.getPrincipalId());
1367 }
1368
1369 protected static interface DocumentActionCallback {
1370
1371 DocumentRouteHeaderValue doInDocumentBo(DocumentRouteHeaderValue documentBo, String principalId,
1372 String annotation) throws WorkflowException;
1373
1374 String getLogMessage(String documentId, String principalId, String annotation);
1375
1376 }
1377
1378 protected static abstract class StandardDocumentActionCallback implements DocumentActionCallback {
1379
1380 public final String getLogMessage(String documentId, String principalId, String annotation) {
1381 return getActionName() + " [principalId=" + principalId + ", documentId=" + documentId + ", annotation="
1382 + annotation + "]";
1383 }
1384
1385 protected abstract String getActionName();
1386
1387 }
1388
1389 }