001/** 002 * Copyright 2005-2017 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kew.actionrequest.service.impl; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.log4j.Logger; 020import org.kuali.rice.core.api.config.CoreConfigHelper; 021import org.kuali.rice.core.api.config.property.ConfigContext; 022import org.kuali.rice.core.api.criteria.CountFlag; 023import org.kuali.rice.core.api.criteria.Predicate; 024import org.kuali.rice.core.api.criteria.QueryByCriteria; 025import org.kuali.rice.core.api.exception.RiceRuntimeException; 026import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator; 027import org.kuali.rice.kew.actionitem.ActionItem; 028import org.kuali.rice.kew.actionlist.service.ActionListService; 029import org.kuali.rice.kew.actionrequest.ActionRequestValue; 030import org.kuali.rice.kew.actionrequest.Recipient; 031import org.kuali.rice.kew.actionrequest.dao.ActionRequestDAO; 032import org.kuali.rice.kew.actionrequest.service.ActionRequestService; 033import org.kuali.rice.kew.actiontaken.ActionTakenValue; 034import org.kuali.rice.kew.actiontaken.service.ActionTakenService; 035import org.kuali.rice.kew.api.KewApiConstants; 036import org.kuali.rice.kew.api.KewApiServiceLocator; 037import org.kuali.rice.kew.api.action.ActionRequestPolicy; 038import org.kuali.rice.kew.api.action.ActionRequestStatus; 039import org.kuali.rice.kew.api.action.RecipientType; 040import org.kuali.rice.kew.api.document.DocumentRefreshQueue; 041import org.kuali.rice.kew.doctype.bo.DocumentType; 042import org.kuali.rice.kew.engine.ActivationContext; 043import org.kuali.rice.kew.engine.node.RouteNodeInstance; 044import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 045import org.kuali.rice.kew.routeheader.service.RouteHeaderService; 046import org.kuali.rice.kew.routemodule.RouteModule; 047import org.kuali.rice.kew.service.KEWServiceLocator; 048import org.kuali.rice.kew.util.FutureRequestDocumentStateManager; 049import org.kuali.rice.kew.util.PerformanceLogger; 050import org.kuali.rice.kew.util.ResponsibleParty; 051import org.kuali.rice.kim.api.group.Group; 052import org.kuali.rice.kim.api.identity.principal.Principal; 053import org.kuali.rice.kim.api.services.KimApiServiceLocator; 054import org.kuali.rice.krad.data.DataObjectService; 055import org.kuali.rice.krad.data.PersistenceOption; 056import org.kuali.rice.krad.util.KRADConstants; 057 058import java.sql.Timestamp; 059import java.util.ArrayList; 060import java.util.Collection; 061import java.util.Collections; 062import java.util.HashMap; 063import java.util.HashSet; 064import java.util.List; 065import java.util.Map; 066import java.util.Set; 067 068import static org.kuali.rice.core.api.criteria.PredicateFactory.*; 069 070/** 071 * Default implementation of the {@link ActionRequestService}. 072 * 073 * @author Kuali Rice Team (rice.collab@kuali.org) 074 */ 075public class ActionRequestServiceImpl implements ActionRequestService { 076 077 private static final Logger LOG = Logger.getLogger(ActionRequestServiceImpl.class); 078 079 private static final String STATUS = "status"; 080 private static final String DOCUMENT_ID = "documentId"; 081 private static final String CURRENT_INDICATOR = "currentIndicator"; 082 private static final String PARENT_ACTION_REQUEST = "parentActionRequest"; 083 private static final String ACTION_REQUESTED = "actionRequested"; 084 private static final String ROUTE_NODE_INSTANCE_ID = "nodeInstance.routeNodeInstanceId"; 085 private static final String GROUP_ID = "groupId"; 086 private static final String ACTION_TAKEN_ID = "actionTaken.actionTakenId"; 087 private static final String RECIPIENT_TYPE_CD = "recipientTypeCd"; 088 private static final String PRINCIPAL_ID = "principalId"; 089 090 private DataObjectService dataObjectService; 091 private ActionRequestDAO actionRequestDAO; 092 093 @Override 094 public ActionRequestValue findByActionRequestId(String actionRequestId) { 095 return getDataObjectService().find(ActionRequestValue.class, actionRequestId); 096 } 097 098 @Override 099 public Map<String, String> getActionsRequested(DocumentRouteHeaderValue routeHeader, String principalId, boolean completeAndApproveTheSame) { 100 return getActionsRequested(principalId, routeHeader.getActionRequests(), completeAndApproveTheSame); 101 } 102 103 /** 104 * Returns a Map of actions that are requested for the given principalId in the given list of action requests. 105 */ 106 protected Map<String, String> getActionsRequested(String principalId, List<ActionRequestValue> actionRequests, boolean completeAndApproveTheSame) { 107 Map<String, String> actionsRequested = new HashMap<String, String>(); 108 actionsRequested.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, "false"); 109 actionsRequested.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, "false"); 110 actionsRequested.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, "false"); 111 actionsRequested.put(KewApiConstants.ACTION_REQUEST_COMPLETE_REQ, "false"); 112 String topActionRequested = KewApiConstants.ACTION_REQUEST_FYI_REQ; 113 for (ActionRequestValue actionRequest : actionRequests) { 114 // we are getting the full list of requests here, so no need to look at role requests, if we did this then 115 // we could get a "false positive" for "all approve" roles where only part of the request graph is marked 116 // as "done" 117 if (!RecipientType.ROLE.getCode().equals(actionRequest.getRecipientTypeCd()) && 118 actionRequest.isRecipientRoutedRequest(principalId) && actionRequest.isActive()) { 119 int actionRequestComparison = ActionRequestValue.compareActionCode(actionRequest.getActionRequested(), topActionRequested, completeAndApproveTheSame); 120 if (actionRequest.isFYIRequest() && actionRequestComparison >= 0) { 121 actionsRequested.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, "true"); 122 } else if (actionRequest.isAcknowledgeRequest() && actionRequestComparison >= 0) { 123 actionsRequested.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, "true"); 124 actionsRequested.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, "false"); 125 topActionRequested = actionRequest.getActionRequested(); 126 } else if (actionRequest.isApproveRequest() && actionRequestComparison >= 0) { 127 actionsRequested.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, "true"); 128 actionsRequested.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, "false"); 129 actionsRequested.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, "false"); 130 topActionRequested = actionRequest.getActionRequested(); 131 } else if (actionRequest.isCompleteRequst() && actionRequestComparison >= 0) { 132 actionsRequested.put(KewApiConstants.ACTION_REQUEST_COMPLETE_REQ, "true"); 133 actionsRequested.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, "false"); 134 actionsRequested.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, "false"); 135 actionsRequested.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, "false"); 136 if (completeAndApproveTheSame) { 137 actionsRequested.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, "true"); 138 } 139 topActionRequested = actionRequest.getActionRequested(); 140 } 141 } 142 } 143 return actionsRequested; 144 } 145 146 @Override 147 public ActionRequestValue initializeActionRequestGraph(ActionRequestValue actionRequest, 148 DocumentRouteHeaderValue document, RouteNodeInstance nodeInstance) { 149 if (actionRequest.getParentActionRequest() != null) { 150 LOG.warn("-->A non parent action request from doc " + document.getDocumentId()); 151 actionRequest = KEWServiceLocator.getActionRequestService().getRoot(actionRequest); 152 } 153 propagatePropertiesToRequestGraph(actionRequest, document, nodeInstance); 154 return actionRequest; 155 } 156 157 private void propagatePropertiesToRequestGraph(ActionRequestValue actionRequest, DocumentRouteHeaderValue document, 158 RouteNodeInstance nodeInstance) { 159 setPropertiesToRequest(actionRequest, document, nodeInstance); 160 for (ActionRequestValue actionRequestValue : actionRequest.getChildrenRequests()) 161 { 162 propagatePropertiesToRequestGraph(actionRequestValue, document, nodeInstance); 163 } 164 } 165 166 private void setPropertiesToRequest(ActionRequestValue actionRequest, DocumentRouteHeaderValue document, 167 RouteNodeInstance nodeInstance) { 168 actionRequest.setDocumentId(document.getDocumentId()); 169 actionRequest.setDocVersion(document.getDocVersion()); 170 actionRequest.setRouteLevel(document.getDocRouteLevel()); 171 actionRequest.setNodeInstance(nodeInstance); 172 actionRequest.setStatus(ActionRequestStatus.INITIALIZED.getCode()); 173 } 174 175 176 177 @Override 178 public List<ActionRequestValue> activateRequests(List<ActionRequestValue> actionRequests) { 179 return activateRequests(actionRequests, new ActivationContext(!ActivationContext.CONTEXT_IS_SIMULATION)); 180 } 181 182 @Override 183 public List<ActionRequestValue> activateRequests(List<ActionRequestValue> actionRequests, boolean simulate) { 184 return activateRequests(actionRequests, new ActivationContext(simulate)); 185 } 186 187 @Override 188 public List<ActionRequestValue> activateRequests(List<ActionRequestValue> actionRequests, ActivationContext activationContext) { 189 if (actionRequests == null) { 190 return new ArrayList<ActionRequestValue>(); 191 } 192 PerformanceLogger performanceLogger = null; 193 if ( LOG.isInfoEnabled() ) { 194 performanceLogger = new PerformanceLogger(); 195 } 196 activationContext.setGeneratedActionItems(new ArrayList<ActionItem>()); 197 // first step, we are going to save the action requests, since we are using JPA on the backend doing a save will 198 // either persist or merge this action request and all of it's children into the current persistence context so 199 // that subsequent saves won't be required and we won't have to return and reset action requests from every 200 // internal method because we will *know* it has already been merged into the persistence contest 201 if (!activationContext.isSimulation()) { 202 actionRequests = saveActionRequests(actionRequests); 203 } 204 205 activateRequestsInternal(actionRequests, activationContext); 206 if (!activationContext.isSimulation()) { 207 KEWServiceLocator.getNotificationService().notify(ActionItem.to(activationContext.getGeneratedActionItems())); 208 } 209 if ( LOG.isInfoEnabled() ) { 210 performanceLogger.log("Time to " + (activationContext.isSimulation() ? "simulate activation of " : "activate ") 211 + actionRequests.size() + " action requests."); 212 } 213 if ( LOG.isDebugEnabled() ) { 214 LOG.debug("Generated " + activationContext.getGeneratedActionItems().size() + " action items."); 215 } 216 return actionRequests; 217 } 218 219 @Override 220 public ActionRequestValue activateRequest(ActionRequestValue actionRequest) { 221 return activateRequests(Collections.singletonList(actionRequest), new ActivationContext(!ActivationContext.CONTEXT_IS_SIMULATION)).get(0); 222 } 223 224 @Override 225 public ActionRequestValue activateRequest(ActionRequestValue actionRequest, boolean simulate) { 226 return activateRequests(Collections.singletonList(actionRequest), new ActivationContext(simulate)).get(0); 227 } 228 229 @Override 230 public ActionRequestValue activateRequest(ActionRequestValue actionRequest, ActivationContext activationContext) { 231 return activateRequests(Collections.singletonList(actionRequest), activationContext).get(0); 232 } 233 234 @Override 235 public ActionRequestValue activateRequestNoNotification(ActionRequestValue actionRequest, ActivationContext activationContext) { 236 activationContext.setGeneratedActionItems(new ArrayList<ActionItem>()); 237 actionRequest = saveActionRequest(actionRequest, activationContext.isSimulation()); 238 activateRequestInternal(actionRequest, activationContext); 239 return actionRequest; 240 } 241 242 /** 243 * Internal helper method for activating a Collection of action requests and their children. Maintains an accumulator 244 * for generated action items. 245 * 246 * <p>IMPORTANT! This method assumes that the action requests given have already been "merged" into the 247 * JPA persistence context.</p> 248 */ 249 private void activateRequestsInternal(List<ActionRequestValue> actionRequests, ActivationContext activationContext) { 250 if (actionRequests != null) { 251 for (ActionRequestValue actionRequest : actionRequests) { 252 activateRequestInternal(actionRequest, activationContext); 253 } 254 } 255 } 256 257 /** 258 * Internal helper method for activating a single action requests and it's children. Maintains an accumulator for 259 * generated action items. 260 * 261 * <p>IMPORTANT! This method assumes that the action request given has already been "merged" into the 262 * JPA persistence context.</p> 263 */ 264 private void activateRequestInternal(ActionRequestValue actionRequest, ActivationContext activationContext) { 265 PerformanceLogger performanceLogger = null; 266 if ( LOG.isInfoEnabled() ) { 267 performanceLogger = new PerformanceLogger(); 268 } 269 if (actionRequest == null || actionRequest.isActive() || actionRequest.isDeactivated()) { 270 return; 271 } 272 processResponsibilityId(actionRequest); 273 if (deactivateOnActionAlreadyTaken(actionRequest, activationContext)) { 274 return; 275 } 276 if (deactivateOnInactiveGroup(actionRequest, activationContext)) { 277 return; 278 } 279 if (deactivateOnEmptyGroup(actionRequest, activationContext)) { 280 return; 281 } 282 actionRequest.setStatus(ActionRequestStatus.ACTIVATED.getCode()); 283 if (!activationContext.isSimulation()) { 284 activationContext.getGeneratedActionItems().addAll(generateActionItems(actionRequest, activationContext)); 285 } 286 activateRequestsInternal(actionRequest.getChildrenRequests(), activationContext); 287 activateRequestInternal(actionRequest.getParentActionRequest(), activationContext); 288 if ( LOG.isInfoEnabled() ) { 289 if (activationContext.isSimulation()) { 290 performanceLogger.log("Time to simulate activation of request."); 291 } else { 292 performanceLogger.log("Time to activate action request with id " + actionRequest.getActionRequestId()); 293 } 294 } 295 } 296 297 /** 298 * Generates ActionItems for the given ActionRequest and returns the List of generated Action Items. 299 * 300 * @return the List of generated ActionItems 301 */ 302 private List<ActionItem> generateActionItems(ActionRequestValue actionRequest, ActivationContext activationContext) { 303 if ( LOG.isDebugEnabled() ) { 304 LOG.debug("generating the action items for request " + actionRequest.getActionRequestId()); 305 } 306 List<ActionItem> actionItems = new ArrayList<ActionItem>(); 307 if (!actionRequest.isPrimaryDelegator()) { 308 if (actionRequest.isGroupRequest()) { 309 List<String> principalIds = KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequest.getGroupId()); 310 actionItems.addAll(createActionItemsForPrincipals(actionRequest, principalIds)); 311 } else if (actionRequest.isUserRequest()) { 312 ActionItem actionItem = getActionListService().createActionItemForActionRequest(actionRequest); 313 actionItems.add(actionItem); 314 } 315 } 316 List<ActionItem> actionItemsToReturn = new ArrayList<ActionItem>(actionItems.size()); 317 if (!activationContext.isSimulation()) { 318 for (ActionItem actionItem: actionItems) { 319 if ( LOG.isDebugEnabled() ) { 320 LOG.debug("Saving action item: " + actionItems); 321 } 322 actionItem = getActionListService().saveActionItem(actionItem); 323 actionItemsToReturn.add(actionItem); 324 } 325 } else { 326 actionRequest.getSimulatedActionItems().addAll(actionItems); 327 actionItemsToReturn.addAll(actionItems); 328 } 329 return actionItemsToReturn; 330 } 331 332 private List<ActionItem> createActionItemsForPrincipals(ActionRequestValue actionRequest, List<String> principalIds) { 333 List<ActionItem> actionItems = new ArrayList<ActionItem>(); 334 for (String principalId: principalIds) { 335 336 ActionItem actionItem = getActionListService().createActionItemForActionRequest(actionRequest); 337 actionItem.setPrincipalId(principalId); 338 actionItem.setRoleName(actionRequest.getQualifiedRoleName()); 339 340 //KULRICE-3307 Prevent workflow from attempting to activate requests for null principals 341 String ignoreUnknownPrincipalIdsValue = ConfigContext.getCurrentContextConfig().getProperty(KewApiConstants.WORKFLOW_ACTION_IGNORE_UNKOWN_PRINCIPAL_IDS); 342 boolean ignoreUnknownPrincipalIds = Boolean.parseBoolean(ignoreUnknownPrincipalIdsValue); 343 344 if(principalId==null && ignoreUnknownPrincipalIds) 345 { 346 LOG.warn("Ignoring action item with actionRequestID of " + actionRequest.getActionRequestId() + " due to null principalId."); 347 } 348 else 349 { 350 if(principalId==null) 351 { 352 IllegalArgumentException e = new IllegalArgumentException("Exception thrown when trying to add action item with null principalId"); 353 LOG.error(e); 354 throw e; 355 } 356 else 357 { 358 actionItems.add(actionItem); 359 } 360 } 361 } 362 return actionItems; 363 } 364 365 private void processResponsibilityId(ActionRequestValue actionRequest) { 366 if (actionRequest.getResolveResponsibility()) { 367 String responsibilityId = actionRequest.getResponsibilityId(); 368 try { 369 RouteModule routeModule = KEWServiceLocator.getRouteModuleService().findRouteModule(actionRequest); 370 if (responsibilityId != null && actionRequest.isRouteModuleRequest()) { 371 if ( LOG.isDebugEnabled() ) { 372 LOG.debug("Resolving responsibility id for action request id=" + actionRequest.getActionRequestId() 373 + " and responsibility id=" + actionRequest.getResponsibilityId()); 374 } 375 ResponsibleParty responsibleParty = routeModule.resolveResponsibilityId(actionRequest.getResponsibilityId()); 376 if (responsibleParty == null) { 377 return; 378 } 379 if (responsibleParty.getPrincipalId() != null) { 380 Principal user = KimApiServiceLocator.getIdentityService() 381 .getPrincipal(responsibleParty.getPrincipalId()); 382 actionRequest.setPrincipalId(user.getPrincipalId()); 383 } else if (responsibleParty.getGroupId() != null) { 384 actionRequest.setGroupId(responsibleParty.getGroupId()); 385 } else if (responsibleParty.getRoleName() != null) { 386 actionRequest.setRoleName(responsibleParty.getRoleName()); 387 } 388 } 389 } catch (Exception e) { 390 LOG.error("Exception thrown when trying to resolve responsibility id " + responsibilityId, e); 391 throw new RuntimeException(e); 392 } 393 } 394 } 395 396 protected boolean deactivateOnActionAlreadyTaken(ActionRequestValue actionRequestToActivate, 397 ActivationContext activationContext) { 398 399 FutureRequestDocumentStateManager futureRequestStateMngr = null; 400 401 if (actionRequestToActivate.isGroupRequest()) { 402 futureRequestStateMngr = new FutureRequestDocumentStateManager(actionRequestToActivate.getRouteHeader(), actionRequestToActivate.getGroup()); 403 } else if (actionRequestToActivate.isUserRequest()) { 404 futureRequestStateMngr = new FutureRequestDocumentStateManager(actionRequestToActivate.getRouteHeader(), actionRequestToActivate.getPrincipalId()); 405 } else { 406 return false; 407 } 408 409 if (futureRequestStateMngr.isReceiveFutureRequests()) { 410 return false; 411 } 412 if (!actionRequestToActivate.getForceAction() || futureRequestStateMngr.isDoNotReceiveFutureRequests()) { 413 ActionTakenValue previousActionTaken = null; 414 if (!activationContext.isSimulation()) { 415 previousActionTaken = getActionTakenService().getPreviousAction(actionRequestToActivate); 416 } else { 417 previousActionTaken = getActionTakenService().getPreviousAction(actionRequestToActivate, 418 activationContext.getSimulatedActionsTaken()); 419 } 420 if (previousActionTaken != null) { 421 if ( LOG.isDebugEnabled() ) { 422 LOG.debug("found a satisfying action taken so setting this request done. Action Request Id " 423 + actionRequestToActivate.getActionRequestId()); 424 } 425 // set up the delegation for an action taken if this is a delegate request and the delegate has 426 // already taken action. 427 if (!previousActionTaken.isForDelegator() && actionRequestToActivate.getParentActionRequest() != null) { 428 previousActionTaken.setDelegator(actionRequestToActivate.getParentActionRequest().getRecipient()); 429 if (!activationContext.isSimulation()) { 430 previousActionTaken = getActionTakenService().saveActionTaken(previousActionTaken); 431 } 432 } 433 deactivateRequest(previousActionTaken, actionRequestToActivate, null, activationContext); 434 return true; 435 } 436 } 437 if ( LOG.isDebugEnabled() ) { 438 LOG.debug("Forcing action for action request " + actionRequestToActivate.getActionRequestId()); 439 } 440 return false; 441 } 442 443 /** 444 * Checks if the action request which is being activated has a group with no members. If this is the case then it will immediately 445 * initiate de-activation on the request since a group with no members will result in no action items being generated so should be 446 * effectively skipped. 447 */ 448 protected boolean deactivateOnEmptyGroup(ActionRequestValue actionRequestToActivate, ActivationContext activationContext) { 449 if (actionRequestToActivate.isGroupRequest()) { 450 if (KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequestToActivate.getGroup().getId()).isEmpty()) { 451 deactivateRequest(null, actionRequestToActivate, null, activationContext); 452 return true; 453 } 454 } 455 return false; 456 } 457 458 /** 459 * Checks if the action request which is being activated is being assigned to an inactive group. If this is the case and if the FailOnInactiveGroup 460 * policy is set to false then it will immediately initiate de-activation on the request 461 */ 462 protected boolean deactivateOnInactiveGroup(ActionRequestValue actionRequestToActivate, ActivationContext activationContext) { 463 if (actionRequestToActivate.isGroupRequest()) { 464 if (!actionRequestToActivate.getGroup().isActive() && !actionRequestToActivate.getRouteHeader().getDocumentType().getFailOnInactiveGroup().getPolicyValue()) { 465 deactivateRequest(null, actionRequestToActivate, null, activationContext); 466 return true; 467 } 468 } 469 return false; 470 } 471 472 @Override 473 public ActionRequestValue deactivateRequest(ActionTakenValue actionTaken, ActionRequestValue actionRequest) { 474 return deactivateRequest(actionTaken, actionRequest, null, new ActivationContext(!ActivationContext.CONTEXT_IS_SIMULATION)); 475 } 476 477 @Override 478 public ActionRequestValue deactivateRequest(ActionTakenValue actionTaken, ActionRequestValue actionRequest, 479 ActivationContext activationContext) { 480 return deactivateRequest(actionTaken, actionRequest, null, activationContext); 481 } 482 483 @Override 484 public List<ActionRequestValue> deactivateRequests(ActionTakenValue actionTaken, List<ActionRequestValue> actionRequests) { 485 return deactivateRequests(actionTaken, actionRequests, null, 486 new ActivationContext(!ActivationContext.CONTEXT_IS_SIMULATION)); 487 } 488 489 @Override 490 public List<ActionRequestValue> deactivateRequests(ActionTakenValue actionTaken, List<ActionRequestValue> actionRequests, boolean simulate) { 491 return deactivateRequests(actionTaken, actionRequests, null, new ActivationContext(simulate)); 492 } 493 494 @Override 495 public List<ActionRequestValue> deactivateRequests(ActionTakenValue actionTaken, List<ActionRequestValue> actionRequests, ActivationContext activationContext) { 496 return deactivateRequests(actionTaken, actionRequests, null, activationContext); 497 } 498 499 private List<ActionRequestValue> deactivateRequests(ActionTakenValue actionTaken, List<ActionRequestValue> actionRequests, 500 ActionRequestValue deactivationRequester, ActivationContext activationContext) { 501 List<ActionRequestValue> deactivatedRequests = new ArrayList<ActionRequestValue>(); 502 if (actionRequests != null) { 503 for (ActionRequestValue actionRequest : actionRequests) { 504 deactivatedRequests.add(deactivateRequest(actionTaken, actionRequest, deactivationRequester, activationContext)); 505 } 506 } 507 return deactivatedRequests; 508 } 509 510 private ActionRequestValue deactivateRequest(ActionTakenValue actionTaken, ActionRequestValue actionRequest, 511 ActionRequestValue deactivationRequester, ActivationContext activationContext) { 512 if (actionRequest == null || actionRequest.isDeactivated() 513 || haltForAllApprove(actionRequest, deactivationRequester)) { 514 return actionRequest; 515 } 516 actionRequest.setStatus(ActionRequestStatus.DONE.getCode()); 517 actionRequest.setActionTaken(actionTaken); 518 519 if (!activationContext.isSimulation()) { 520 if (actionTaken != null) { 521 // only add it if it's not null and we aren't in a simulation context, if we are in simulation mode, we 522 // don't want to modify any action requests, lest they get saved by a JPA flush later! 523 actionTaken.getActionRequests().add(actionRequest); 524 } 525 actionRequest = getDataObjectService().save(actionRequest); 526 deleteActionItems(actionRequest, true); 527 } 528 actionRequest.setChildrenRequests(deactivateRequests(actionTaken, actionRequest.getChildrenRequests(), actionRequest, activationContext)); 529 actionRequest.setParentActionRequest(deactivateRequest(actionTaken, actionRequest.getParentActionRequest(), actionRequest, activationContext)); 530 return actionRequest; 531 } 532 533 /** 534 * Returns true if we are dealing with an 'All Approve' request, the requester of the deactivation is a child of the 535 * 'All Approve' request, and all of the children have not been deactivated. If all of the children are already 536 * deactivated or a non-child request initiated deactivation, then this method returns false. false otherwise. 537 */ 538 private boolean haltForAllApprove(ActionRequestValue actionRequest, ActionRequestValue deactivationRequester) { 539 if (ActionRequestPolicy.ALL.getCode().equals(actionRequest.getApprovePolicy()) 540 && actionRequest.hasChild(deactivationRequester)) { 541 for (ActionRequestValue childRequest : actionRequest.getChildrenRequests()) { 542 if (!childRequest.isDeactivated()) { 543 return true; 544 } 545 } 546 } 547 return false; 548 } 549 550 @Override 551 public List<ActionRequestValue> getRootRequests(Collection<ActionRequestValue> actionRequests) { 552 Set<ActionRequestValue> unsavedRequests = new HashSet<ActionRequestValue>(); 553 Map<String, ActionRequestValue> requestMap = new HashMap<String, ActionRequestValue>(); 554 for (ActionRequestValue actionRequest1 : actionRequests) { 555 ActionRequestValue actionRequest = actionRequest1; 556 ActionRequestValue rootRequest = getRoot(actionRequest); 557 if (rootRequest.getActionRequestId() != null) { 558 requestMap.put(rootRequest.getActionRequestId(), rootRequest); 559 } else { 560 unsavedRequests.add(rootRequest); 561 } 562 } 563 List<ActionRequestValue> requests = new ArrayList<ActionRequestValue>(); 564 requests.addAll(requestMap.values()); 565 requests.addAll(unsavedRequests); 566 return requests; 567 } 568 569 @Override 570 public ActionRequestValue getRoot(ActionRequestValue actionRequest) { 571 if (actionRequest == null) { 572 return null; 573 } 574 if (actionRequest.getParentActionRequest() != null) { 575 return getRoot(actionRequest.getParentActionRequest()); 576 } 577 return actionRequest; 578 } 579 580 /** 581 * Returns all pending requests for a given routing identity 582 * @param documentId the id of the document header being routed 583 * @return a List of all pending ActionRequestValues for the document 584 */ 585 @Override 586 public List<ActionRequestValue> findAllPendingRequests(String documentId) { 587 return findByStatusAndDocId(ActionRequestStatus.ACTIVATED.getCode(), documentId); 588 } 589 590 @Override 591 public List<ActionRequestValue> findAllValidRequests(String principalId, String documentId, String requestCode) { 592 List<ActionRequestValue> pendingArs = 593 findByStatusAndDocumentId(ActionRequestStatus.ACTIVATED.getCode(), documentId); 594 return findAllValidRequests(principalId, pendingArs, requestCode); 595 } 596 597 protected List<ActionRequestValue> findByStatusAndDocumentId(String statusCode, String documentId) { 598 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 599 equal(STATUS, statusCode), 600 equal(DOCUMENT_ID, documentId), 601 equal(CURRENT_INDICATOR, Boolean.TRUE) 602 ); 603 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 604 } 605 606 @Override 607 public List<ActionRequestValue> findAllValidRequests(String principalId, List<ActionRequestValue> actionRequests, String requestCode) { 608 List<String> arGroups = KimApiServiceLocator.getGroupService().getGroupIdsByPrincipalId(principalId); 609 return filterActionRequestsByCode(actionRequests, principalId, arGroups, requestCode); 610 } 611 612 /** 613 * Filters action requests based on if they occur after the given requestCode, and if they relate to 614 * the given principal 615 * @param actionRequests the List of ActionRequestValues to filter 616 * @param principalId the id of the principal to find active requests for 617 * @param principalGroupIds List of group ids that the principal belongs to 618 * @param requestCode the request code for all ActionRequestValues to be after 619 * @return the filtered List of ActionRequestValues 620 */ 621 @Override 622 public List<ActionRequestValue> filterActionRequestsByCode(List<ActionRequestValue> actionRequests, String principalId, List<String> principalGroupIds, String requestCode) { 623 List<ActionRequestValue> filteredActionRequests = new ArrayList<ActionRequestValue>(); 624 625 for (ActionRequestValue ar : actionRequests) { 626 if (ActionRequestValue.compareActionCode(ar.getActionRequested(), requestCode, true) > 0) { 627 continue; 628 } 629 if (ar.isUserRequest() && principalId.equals(ar.getPrincipalId())) { 630 filteredActionRequests.add(ar); 631 } else if (ar.isGroupRequest() && principalGroupIds != null && !principalGroupIds.isEmpty()) { 632 for (String groupId : principalGroupIds) { 633 if (groupId.equals(ar.getGroupId())) { 634 filteredActionRequests.add(ar); 635 } 636 } 637 } 638 } 639 640 return filteredActionRequests; 641 } 642 643 @Override 644 public void updateActionRequestsForResponsibilityChange(Set<String> responsibilityIds) { 645 PerformanceLogger performanceLogger = null; 646 if ( LOG.isInfoEnabled() ) { 647 performanceLogger = new PerformanceLogger(); 648 } 649 Collection<String> documentsAffected = getRouteHeaderService().findPendingByResponsibilityIds(responsibilityIds); 650 String cacheWaitValue = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.RULE_DETAIL_TYPE, KewApiConstants.RULE_CACHE_REQUEUE_DELAY); 651 Long cacheWait = KewApiConstants.DEFAULT_CACHE_REQUEUE_WAIT_TIME; 652 if (!org.apache.commons.lang.StringUtils.isEmpty(cacheWaitValue)) { 653 try { 654 cacheWait = Long.valueOf(cacheWaitValue); 655 } catch (NumberFormatException e) { 656 LOG.warn("Cache wait time is not a valid number: " + cacheWaitValue); 657 } 658 } 659 if ( LOG.isInfoEnabled() ) { 660 LOG.info("Scheduling requeue of " + documentsAffected.size() + " documents, affected by " + responsibilityIds.size() 661 + " responsibility changes. Installing a processing wait time of " + cacheWait 662 + " milliseconds to avoid stale rule cache."); 663 } 664 for (String documentId : documentsAffected) { 665 666 String applicationId = null; 667 DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByDocumentId(documentId); 668 669 if (documentType != null) { 670 applicationId = documentType.getApplicationId(); 671 } 672 673 if (applicationId == null) 674 { 675 applicationId = CoreConfigHelper.getApplicationId(); 676 } 677 if(documentType.getRegenerateActionRequestsOnChange().getPolicyValue()) { 678 DocumentRefreshQueue documentRequeuer = KewApiServiceLocator.getDocumentRequeuerService(applicationId, 679 documentId, cacheWait); 680 documentRequeuer.refreshDocument(documentId); 681 } 682 } 683 if ( LOG.isInfoEnabled() ) { 684 performanceLogger.log("Time to updateActionRequestsForResponsibilityChange"); 685 } 686 } 687 688 @Override 689 public void deleteActionRequestGraphNoOutbox(ActionRequestValue actionRequest) { 690 deleteActionRequestGraph(actionRequest, false); 691 } 692 693 /** 694 * Deletes an action request and all of its action items following the graph down through the action request's 695 * children. This method should be invoked on a top-level action request. 696 */ 697 @Override 698 public void deleteActionRequestGraph(ActionRequestValue actionRequest) { 699 deleteActionRequestGraph(actionRequest, true); 700 } 701 702 protected void deleteActionRequestGraph(ActionRequestValue actionRequest, boolean populateOutbox) { 703 if (actionRequest.getParentActionRequest() != null) { 704 throw new IllegalArgumentException("Must delete action request graph from the root, encountered a request with a parent: " + actionRequest); 705 } 706 deleteActionItemsFromGraph(actionRequest, populateOutbox); 707 String actionTakenId = actionRequest.getActionTakenId(); 708 // delete from the root, it should cascade down to the children 709 getDataObjectService().delete(actionRequest); 710 // go ahead and flush to ensure that the deletion happens before we return control to the calling code 711 getDataObjectService().flush(ActionRequestValue.class); 712 713 // If there are no other actions taken associated with this action request, delete the action taken as well. 714 if (actionTakenId != null) { 715 ActionTakenValue actionTaken = getActionTakenService().findByActionTakenId(actionTakenId); 716 if (actionTaken != null) { 717 Collection<ActionRequestValue> actionRequestValues = actionTaken.getActionRequests(); 718 if (actionRequestValues.size() == 0) { 719 getActionTakenService().delete(actionTaken); 720 } 721 } 722 } 723 } 724 725 /** 726 * Deletes the action items for the action request 727 * @param actionRequest the action request whose action items to delete 728 */ 729 private void deleteActionItems(ActionRequestValue actionRequest, boolean populateOutbox) { 730 List<ActionItem> actionItems = actionRequest.getActionItems(); 731 if ( LOG.isDebugEnabled() ) { 732 LOG.debug("deleting " + actionItems.size() + " action items for action request: " + actionRequest); 733 } 734 for (ActionItem actionItem: actionItems) { 735 if ( LOG.isDebugEnabled() ) { 736 LOG.debug("deleting action item: " + actionItem); 737 } 738 if (populateOutbox) { 739 getActionListService().deleteActionItem(actionItem); 740 } else { 741 getActionListService().deleteActionItemNoOutbox(actionItem); 742 } 743 } 744 } 745 746 /** 747 * Deletes the action items for the *root* action request. 748 * 749 * @param actionRequest the action request whose action items to delete 750 */ 751 private void deleteActionItemsFromGraph(ActionRequestValue actionRequest, boolean populateOutbox) { 752 if (actionRequest.getParentActionRequest() != null) { 753 throw new IllegalArgumentException("Must delete action item from root of action request graph!"); 754 } 755 List<ActionItem> actionItemsToDelete = new ArrayList<ActionItem>(); 756 accumulateActionItemsFromGraph(actionRequest, actionItemsToDelete); 757 if ( LOG.isDebugEnabled() ) { 758 LOG.debug("deleting " + actionItemsToDelete.size() + " action items for action request graph: " + actionRequest); 759 } 760 for (ActionItem actionItem : actionItemsToDelete) { 761 if ( LOG.isDebugEnabled() ) { 762 LOG.debug("deleting action item: " + actionItem); 763 } 764 if (populateOutbox) { 765 getActionListService().deleteActionItem(actionItem); 766 } else { 767 getActionListService().deleteActionItemNoOutbox(actionItem); 768 } 769 } 770 } 771 772 private void accumulateActionItemsFromGraph(ActionRequestValue actionRequest, List<ActionItem> actionItems) { 773 actionItems.addAll(actionRequest.getActionItems()); 774 for (ActionRequestValue childRequest : actionRequest.getChildrenRequests()) { 775 accumulateActionItemsFromGraph(childRequest, actionItems); 776 } 777 } 778 779 780 @Override 781 public List<ActionRequestValue> findByDocumentIdIgnoreCurrentInd(String documentId) { 782 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates(equal(DOCUMENT_ID, documentId)); 783 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 784 } 785 786 @Override 787 public List<ActionRequestValue> findAllActionRequestsByDocumentId(String documentId) { 788 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 789 equal(DOCUMENT_ID, documentId), 790 equal(CURRENT_INDICATOR, Boolean.TRUE) 791 ); 792 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 793 } 794 795 @Override 796 public List<ActionRequestValue> findAllRootActionRequestsByDocumentId(String documentId) { 797 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 798 equal(DOCUMENT_ID, documentId), 799 equal(CURRENT_INDICATOR, Boolean.TRUE), 800 isNull(PARENT_ACTION_REQUEST) 801 ); 802 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 803 } 804 805 @Override 806 public List<ActionRequestValue> findPendingByActionRequestedAndDocId(String actionRequestedCd, String documentId) { 807 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 808 equal(DOCUMENT_ID, documentId), 809 equal(CURRENT_INDICATOR, Boolean.TRUE), 810 equal(ACTION_REQUESTED, actionRequestedCd), 811 getPendingCriteria() 812 ); 813 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 814 } 815 816 817 818 @Override 819 public List<String> getPrincipalIdsWithPendingActionRequestByActionRequestedAndDocId(String actionRequestedCd, String documentId) { 820 List<String> principalIds = new ArrayList<String>(); 821 List<ActionRequestValue> actionRequests = findPendingByActionRequestedAndDocId(actionRequestedCd, documentId); 822 for(ActionRequestValue actionRequest: actionRequests){ 823 if(actionRequest.isUserRequest()){ 824 principalIds.add(actionRequest.getPrincipalId()); 825 } else if(actionRequest.isGroupRequest()){ 826 principalIds.addAll( 827 KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequest.getGroupId())); 828 } 829 } 830 return principalIds; 831 } 832 833 @Override 834 public List<ActionRequestValue> findPendingRootRequestsByDocId(String documentId) { 835 return getRootRequests(findPendingByDoc(documentId)); 836 } 837 838 @Override 839 public List<ActionRequestValue> findPendingRootRequestsByDocIdAtRouteNode(String documentId, String nodeInstanceId) { 840 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 841 equal(DOCUMENT_ID, documentId), 842 equal(CURRENT_INDICATOR, Boolean.TRUE), 843 isNull(PARENT_ACTION_REQUEST), 844 getPendingCriteria(), 845 equal(ROUTE_NODE_INSTANCE_ID, nodeInstanceId) 846 ); 847 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 848 } 849 850 @Override 851 public List<ActionRequestValue> findRootRequestsByDocIdAtRouteNode(String documentId, String nodeInstanceId) { 852 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 853 equal(DOCUMENT_ID, documentId), 854 equal(CURRENT_INDICATOR, Boolean.TRUE), 855 isNull(PARENT_ACTION_REQUEST), 856 equal(ROUTE_NODE_INSTANCE_ID, nodeInstanceId) 857 ); 858 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 859 } 860 861 @Override 862 public List<ActionRequestValue> findPendingRootRequestsByDocumentType(String documentTypeId) { 863 return getActionRequestDAO().findPendingRootRequestsByDocumentType(documentTypeId); 864 } 865 866 @Override 867 public ActionRequestValue saveActionRequest(ActionRequestValue actionRequest) { 868 return saveActionRequest(actionRequest, false); 869 } 870 871 protected ActionRequestValue saveActionRequest(ActionRequestValue actionRequest, boolean simulation) { 872 if (actionRequest.isGroupRequest()) { 873 Group group = actionRequest.getGroup(); 874 if (group == null) { 875 throw new RiceRuntimeException("Attempted to save an action request with a non-existent group."); 876 } 877 if (!group.isActive() && actionRequest.getRouteHeader().getDocumentType().getFailOnInactiveGroup().getPolicyValue()) { 878 throw new RiceRuntimeException("Attempted to save an action request with an inactive group."); 879 } 880 } 881 if (actionRequest.getActionRequestId() == null) { 882 loadDefaultValues(actionRequest); 883 } 884 if ( actionRequest.getAnnotation() != null && actionRequest.getAnnotation().length() > 2000 ) { 885 actionRequest.setAnnotation( StringUtils.abbreviate(actionRequest.getAnnotation(), 2000) ); 886 } 887 if (simulation) { 888 return actionRequest; 889 } else { 890 return getDataObjectService().save(actionRequest); 891 } 892 } 893 894 private void loadDefaultValues(ActionRequestValue actionRequest) { 895 checkNull(actionRequest.getActionRequested(), "action requested"); 896 checkNull(actionRequest.getResponsibilityId(), "responsibility ID"); 897 checkNull(actionRequest.getRouteLevel(), "route level"); 898 checkNull(actionRequest.getDocVersion(), "doc version"); 899 if (actionRequest.getForceAction() == null) { 900 actionRequest.setForceAction(Boolean.FALSE); 901 } 902 if (actionRequest.getStatus() == null) { 903 actionRequest.setStatus(ActionRequestStatus.INITIALIZED.getCode()); 904 } 905 if (actionRequest.getPriority() == null) { 906 actionRequest.setPriority(KewApiConstants.ACTION_REQUEST_DEFAULT_PRIORITY); 907 } 908 if (actionRequest.getCurrentIndicator() == null) { 909 actionRequest.setCurrentIndicator(true); 910 } 911 actionRequest.setCreateDate(new Timestamp(System.currentTimeMillis())); 912 } 913 914 private void checkNull(Object value, String valueName) throws RuntimeException { 915 if (value == null) { 916 throw new IllegalArgumentException("Null value for " + valueName); 917 } 918 } 919 920 private List<ActionRequestValue> saveActionRequests(Collection<ActionRequestValue> actionRequests) { 921 // TODO validate only root requests are being saved here? 922 List<ActionRequestValue> savedRequests = new ArrayList<ActionRequestValue>(actionRequests.size()); 923 for (ActionRequestValue actionRequest : actionRequests) { 924 savedRequests.add(saveActionRequest(actionRequest)); 925 } 926 return savedRequests; 927 } 928 929 @Override 930 public List<ActionRequestValue> findPendingByDoc(String documentId) { 931 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 932 equal(DOCUMENT_ID, documentId), 933 equal(CURRENT_INDICATOR, Boolean.TRUE), 934 getPendingCriteria() 935 ); 936 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 937 } 938 939 @Override 940 public List<ActionRequestValue> findPendingByDocRequestCdNodeName(String documentId, String requestCode, String nodeName) { 941 List<ActionRequestValue> requests = new ArrayList<ActionRequestValue>(); 942 for (ActionRequestValue actionRequest : findPendingByDoc(documentId)) { 943 if (ActionRequestValue.compareActionCode(actionRequest.getActionRequested(), requestCode, true) > 0) { 944 continue; 945 } 946 if (actionRequest.getNodeInstance() != null && actionRequest.getNodeInstance().getName().equals(nodeName)) { 947 requests.add(actionRequest); 948 } 949 } 950 return requests; 951 } 952 953 @Override 954 public List<ActionRequestValue> findActivatedByGroup(String groupId) { 955 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 956 equal(STATUS, ActionRequestStatus.ACTIVATED.getCode()), 957 equal(GROUP_ID, groupId), 958 equal(CURRENT_INDICATOR, Boolean.TRUE), 959 getPendingCriteria() 960 ); 961 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 962 } 963 964 @Override 965 public List<ActionRequestValue> findByStatusAndDocId(String statusCode, String documentId) { 966 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 967 equal(STATUS, statusCode), 968 equal(DOCUMENT_ID, documentId), 969 equal(CURRENT_INDICATOR, Boolean.TRUE) 970 ); 971 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 972 } 973 974 @Override 975 public Recipient findDelegator(List<ActionRequestValue> actionRequests) { 976 Recipient delegator = null; 977 String requestCode = KewApiConstants.ACTION_REQUEST_FYI_REQ; 978 for (Object actionRequest1 : actionRequests) 979 { 980 ActionRequestValue actionRequest = (ActionRequestValue) actionRequest1; 981 ActionRequestValue delegatorRequest = findDelegatorRequest(actionRequest); 982 if (delegatorRequest != null) 983 { 984 if (ActionRequestValue.compareActionCode(delegatorRequest.getActionRequested(), requestCode, true) >= 0) 985 { 986 delegator = delegatorRequest.getRecipient(); 987 requestCode = delegatorRequest.getActionRequested(); 988 } 989 } 990 } 991 return delegator; 992 } 993 994 @Override 995 public ActionRequestValue findDelegatorRequest(ActionRequestValue actionRequest) { 996 ActionRequestValue parentRequest = actionRequest.getParentActionRequest(); 997 if (parentRequest != null && !(parentRequest.isUserRequest() || parentRequest.isGroupRequest())) { 998 parentRequest = findDelegatorRequest(parentRequest); 999 } 1000 return parentRequest; 1001 } 1002 1003 @Override 1004 public List<ActionRequestValue> getDelegateRequests(ActionRequestValue actionRequest) { 1005 List<ActionRequestValue> delegateRequests = new ArrayList<ActionRequestValue>(); 1006 List<ActionRequestValue> requests = getTopLevelRequests(actionRequest); 1007 for (Object request : requests) 1008 { 1009 ActionRequestValue parentActionRequest = (ActionRequestValue) request; 1010 delegateRequests.addAll(parentActionRequest.getChildrenRequests()); 1011 } 1012 return delegateRequests; 1013 } 1014 1015 @Override 1016 public List<ActionRequestValue> getTopLevelRequests(ActionRequestValue actionRequest) { 1017 List<ActionRequestValue> topLevelRequests = new ArrayList<ActionRequestValue>(); 1018 if (actionRequest.isRoleRequest()) { 1019 topLevelRequests.addAll(actionRequest.getChildrenRequests()); 1020 } else { 1021 topLevelRequests.add(actionRequest); 1022 } 1023 return topLevelRequests; 1024 } 1025 1026 @Override 1027 public boolean doesPrincipalHaveRequest(String principalId, String documentId) { 1028 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 1029 equal(PRINCIPAL_ID, principalId), 1030 equal(DOCUMENT_ID, documentId), 1031 equal(RECIPIENT_TYPE_CD, RecipientType.PRINCIPAL.getCode()), 1032 equal(CURRENT_INDICATOR, Boolean.TRUE) 1033 ); 1034 1035 criteria.setCountFlag(CountFlag.ONLY); 1036 Integer count = getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getTotalRowCount(); 1037 if (count != null && count > 0) { 1038 return true; 1039 } 1040 // TODO since we only store the workgroup id for workgroup requests, if the user is in a workgroup that has a request 1041 // than we need get all the requests with workgroup ids and see if our user is in that group 1042 List<String> groupIds = getActionRequestDAO().getRequestGroupIds(documentId); 1043 for (String groupId : groupIds) { 1044 if (KimApiServiceLocator.getGroupService().isMemberOfGroup(principalId, groupId)) { 1045 return true; 1046 } 1047 } 1048 return false; 1049 } 1050 1051 @Override 1052 public ActionRequestValue getActionRequestForRole(String actionTakenId) { 1053 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 1054 equal(ACTION_TAKEN_ID, actionTakenId), 1055 equal(CURRENT_INDICATOR, Boolean.TRUE), 1056 equal(RECIPIENT_TYPE_CD, RecipientType.ROLE.getCode()), 1057 isNull(PARENT_ACTION_REQUEST) 1058 ); 1059 List<ActionRequestValue> actionTakenRoleRequests = 1060 getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 1061 if (actionTakenRoleRequests.isEmpty()) { 1062 return null; 1063 } 1064 return actionTakenRoleRequests.get(0); 1065 } 1066 1067 /** 1068 * Returns criteria for selecting "pending" action requests. A request is pending if it's status is activated 1069 * or initialized. 1070 * 1071 * @return criteria for selecting pending action requests 1072 */ 1073 protected Predicate getPendingCriteria() { 1074 return or( 1075 equal(STATUS, ActionRequestStatus.ACTIVATED.getCode()), 1076 equal(STATUS, ActionRequestStatus.INITIALIZED.getCode()) 1077 ); 1078 } 1079 1080 private ActionListService getActionListService() { 1081 return KEWServiceLocator.getActionListService(); 1082 } 1083 1084 private ActionTakenService getActionTakenService() { 1085 return KEWServiceLocator.getActionTakenService(); 1086 } 1087 1088 private RouteHeaderService getRouteHeaderService() { 1089 return KEWServiceLocator.getService(KEWServiceLocator.DOC_ROUTE_HEADER_SRV); 1090 } 1091 1092 public DataObjectService getDataObjectService() { 1093 return dataObjectService; 1094 } 1095 1096 public void setDataObjectService(DataObjectService dataObjectService) { 1097 this.dataObjectService = dataObjectService; 1098 } 1099 1100 public ActionRequestDAO getActionRequestDAO() { 1101 return actionRequestDAO; 1102 } 1103 1104 public void setActionRequestDAO(ActionRequestDAO actionRequestDAO) { 1105 this.actionRequestDAO = actionRequestDAO; 1106 } 1107 1108}