001/** 002 * Copyright 2005-2016 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 if (actionRequest.getActionTakenId() != null) { 708 ActionTakenValue actionTaken = getActionTakenService().findByActionTakenId(actionRequest.getActionTakenId()); 709 if (actionTaken != null) { 710 getActionTakenService().delete(actionTaken); 711 } 712 } 713 // delete from the root, it should cascade down to the children 714 getDataObjectService().delete(actionRequest); 715 // go ahead and flush to ensure that the deletion happens before we return control to the calling code 716 getDataObjectService().flush(ActionRequestValue.class); 717 } 718 719 /** 720 * Deletes the action items for the action request 721 * @param actionRequest the action request whose action items to delete 722 */ 723 private void deleteActionItems(ActionRequestValue actionRequest, boolean populateOutbox) { 724 List<ActionItem> actionItems = actionRequest.getActionItems(); 725 if ( LOG.isDebugEnabled() ) { 726 LOG.debug("deleting " + actionItems.size() + " action items for action request: " + actionRequest); 727 } 728 for (ActionItem actionItem: actionItems) { 729 if ( LOG.isDebugEnabled() ) { 730 LOG.debug("deleting action item: " + actionItem); 731 } 732 if (populateOutbox) { 733 getActionListService().deleteActionItem(actionItem); 734 } else { 735 getActionListService().deleteActionItemNoOutbox(actionItem); 736 } 737 } 738 } 739 740 /** 741 * Deletes the action items for the *root* action request. 742 * 743 * @param actionRequest the action request whose action items to delete 744 */ 745 private void deleteActionItemsFromGraph(ActionRequestValue actionRequest, boolean populateOutbox) { 746 if (actionRequest.getParentActionRequest() != null) { 747 throw new IllegalArgumentException("Must delete action item from root of action request graph!"); 748 } 749 List<ActionItem> actionItemsToDelete = new ArrayList<ActionItem>(); 750 accumulateActionItemsFromGraph(actionRequest, actionItemsToDelete); 751 if ( LOG.isDebugEnabled() ) { 752 LOG.debug("deleting " + actionItemsToDelete.size() + " action items for action request graph: " + actionRequest); 753 } 754 for (ActionItem actionItem : actionItemsToDelete) { 755 if ( LOG.isDebugEnabled() ) { 756 LOG.debug("deleting action item: " + actionItem); 757 } 758 if (populateOutbox) { 759 getActionListService().deleteActionItem(actionItem); 760 } else { 761 getActionListService().deleteActionItemNoOutbox(actionItem); 762 } 763 } 764 } 765 766 private void accumulateActionItemsFromGraph(ActionRequestValue actionRequest, List<ActionItem> actionItems) { 767 actionItems.addAll(actionRequest.getActionItems()); 768 for (ActionRequestValue childRequest : actionRequest.getChildrenRequests()) { 769 accumulateActionItemsFromGraph(childRequest, actionItems); 770 } 771 } 772 773 774 @Override 775 public List<ActionRequestValue> findByDocumentIdIgnoreCurrentInd(String documentId) { 776 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates(equal(DOCUMENT_ID, documentId)); 777 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 778 } 779 780 @Override 781 public List<ActionRequestValue> findAllActionRequestsByDocumentId(String documentId) { 782 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 783 equal(DOCUMENT_ID, documentId), 784 equal(CURRENT_INDICATOR, Boolean.TRUE) 785 ); 786 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 787 } 788 789 @Override 790 public List<ActionRequestValue> findAllRootActionRequestsByDocumentId(String documentId) { 791 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 792 equal(DOCUMENT_ID, documentId), 793 equal(CURRENT_INDICATOR, Boolean.TRUE), 794 isNull(PARENT_ACTION_REQUEST) 795 ); 796 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 797 } 798 799 @Override 800 public List<ActionRequestValue> findPendingByActionRequestedAndDocId(String actionRequestedCd, String documentId) { 801 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 802 equal(DOCUMENT_ID, documentId), 803 equal(CURRENT_INDICATOR, Boolean.TRUE), 804 equal(ACTION_REQUESTED, actionRequestedCd), 805 getPendingCriteria() 806 ); 807 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 808 } 809 810 811 812 @Override 813 public List<String> getPrincipalIdsWithPendingActionRequestByActionRequestedAndDocId(String actionRequestedCd, String documentId) { 814 List<String> principalIds = new ArrayList<String>(); 815 List<ActionRequestValue> actionRequests = findPendingByActionRequestedAndDocId(actionRequestedCd, documentId); 816 for(ActionRequestValue actionRequest: actionRequests){ 817 if(actionRequest.isUserRequest()){ 818 principalIds.add(actionRequest.getPrincipalId()); 819 } else if(actionRequest.isGroupRequest()){ 820 principalIds.addAll( 821 KimApiServiceLocator.getGroupService().getMemberPrincipalIds(actionRequest.getGroupId())); 822 } 823 } 824 return principalIds; 825 } 826 827 @Override 828 public List<ActionRequestValue> findPendingRootRequestsByDocId(String documentId) { 829 return getRootRequests(findPendingByDoc(documentId)); 830 } 831 832 @Override 833 public List<ActionRequestValue> findPendingRootRequestsByDocIdAtRouteNode(String documentId, String nodeInstanceId) { 834 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 835 equal(DOCUMENT_ID, documentId), 836 equal(CURRENT_INDICATOR, Boolean.TRUE), 837 isNull(PARENT_ACTION_REQUEST), 838 getPendingCriteria(), 839 equal(ROUTE_NODE_INSTANCE_ID, nodeInstanceId) 840 ); 841 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 842 } 843 844 @Override 845 public List<ActionRequestValue> findRootRequestsByDocIdAtRouteNode(String documentId, String nodeInstanceId) { 846 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 847 equal(DOCUMENT_ID, documentId), 848 equal(CURRENT_INDICATOR, Boolean.TRUE), 849 isNull(PARENT_ACTION_REQUEST), 850 equal(ROUTE_NODE_INSTANCE_ID, nodeInstanceId) 851 ); 852 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 853 } 854 855 @Override 856 public List<ActionRequestValue> findPendingRootRequestsByDocumentType(String documentTypeId) { 857 return getActionRequestDAO().findPendingRootRequestsByDocumentType(documentTypeId); 858 } 859 860 @Override 861 public ActionRequestValue saveActionRequest(ActionRequestValue actionRequest) { 862 return saveActionRequest(actionRequest, false); 863 } 864 865 protected ActionRequestValue saveActionRequest(ActionRequestValue actionRequest, boolean simulation) { 866 if (actionRequest.isGroupRequest()) { 867 Group group = actionRequest.getGroup(); 868 if (group == null) { 869 throw new RiceRuntimeException("Attempted to save an action request with a non-existent group."); 870 } 871 if (!group.isActive() && actionRequest.getRouteHeader().getDocumentType().getFailOnInactiveGroup().getPolicyValue()) { 872 throw new RiceRuntimeException("Attempted to save an action request with an inactive group."); 873 } 874 } 875 if (actionRequest.getActionRequestId() == null) { 876 loadDefaultValues(actionRequest); 877 } 878 if ( actionRequest.getAnnotation() != null && actionRequest.getAnnotation().length() > 2000 ) { 879 actionRequest.setAnnotation( StringUtils.abbreviate(actionRequest.getAnnotation(), 2000) ); 880 } 881 if (simulation) { 882 return actionRequest; 883 } else { 884 return getDataObjectService().save(actionRequest); 885 } 886 } 887 888 private void loadDefaultValues(ActionRequestValue actionRequest) { 889 checkNull(actionRequest.getActionRequested(), "action requested"); 890 checkNull(actionRequest.getResponsibilityId(), "responsibility ID"); 891 checkNull(actionRequest.getRouteLevel(), "route level"); 892 checkNull(actionRequest.getDocVersion(), "doc version"); 893 if (actionRequest.getForceAction() == null) { 894 actionRequest.setForceAction(Boolean.FALSE); 895 } 896 if (actionRequest.getStatus() == null) { 897 actionRequest.setStatus(ActionRequestStatus.INITIALIZED.getCode()); 898 } 899 if (actionRequest.getPriority() == null) { 900 actionRequest.setPriority(KewApiConstants.ACTION_REQUEST_DEFAULT_PRIORITY); 901 } 902 if (actionRequest.getCurrentIndicator() == null) { 903 actionRequest.setCurrentIndicator(true); 904 } 905 actionRequest.setCreateDate(new Timestamp(System.currentTimeMillis())); 906 } 907 908 private void checkNull(Object value, String valueName) throws RuntimeException { 909 if (value == null) { 910 throw new IllegalArgumentException("Null value for " + valueName); 911 } 912 } 913 914 private List<ActionRequestValue> saveActionRequests(Collection<ActionRequestValue> actionRequests) { 915 // TODO validate only root requests are being saved here? 916 List<ActionRequestValue> savedRequests = new ArrayList<ActionRequestValue>(actionRequests.size()); 917 for (ActionRequestValue actionRequest : actionRequests) { 918 savedRequests.add(saveActionRequest(actionRequest)); 919 } 920 return savedRequests; 921 } 922 923 @Override 924 public List<ActionRequestValue> findPendingByDoc(String documentId) { 925 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 926 equal(DOCUMENT_ID, documentId), 927 equal(CURRENT_INDICATOR, Boolean.TRUE), 928 getPendingCriteria() 929 ); 930 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 931 } 932 933 @Override 934 public List<ActionRequestValue> findPendingByDocRequestCdNodeName(String documentId, String requestCode, String nodeName) { 935 List<ActionRequestValue> requests = new ArrayList<ActionRequestValue>(); 936 for (ActionRequestValue actionRequest : findPendingByDoc(documentId)) { 937 if (ActionRequestValue.compareActionCode(actionRequest.getActionRequested(), requestCode, true) > 0) { 938 continue; 939 } 940 if (actionRequest.getNodeInstance() != null && actionRequest.getNodeInstance().getName().equals(nodeName)) { 941 requests.add(actionRequest); 942 } 943 } 944 return requests; 945 } 946 947 @Override 948 public List<ActionRequestValue> findActivatedByGroup(String groupId) { 949 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 950 equal(STATUS, ActionRequestStatus.ACTIVATED.getCode()), 951 equal(GROUP_ID, groupId), 952 equal(CURRENT_INDICATOR, Boolean.TRUE), 953 getPendingCriteria() 954 ); 955 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 956 } 957 958 @Override 959 public List<ActionRequestValue> findByStatusAndDocId(String statusCode, String documentId) { 960 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 961 equal(STATUS, statusCode), 962 equal(DOCUMENT_ID, documentId), 963 equal(CURRENT_INDICATOR, Boolean.TRUE) 964 ); 965 return getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 966 } 967 968 @Override 969 public Recipient findDelegator(List<ActionRequestValue> actionRequests) { 970 Recipient delegator = null; 971 String requestCode = KewApiConstants.ACTION_REQUEST_FYI_REQ; 972 for (Object actionRequest1 : actionRequests) 973 { 974 ActionRequestValue actionRequest = (ActionRequestValue) actionRequest1; 975 ActionRequestValue delegatorRequest = findDelegatorRequest(actionRequest); 976 if (delegatorRequest != null) 977 { 978 if (ActionRequestValue.compareActionCode(delegatorRequest.getActionRequested(), requestCode, true) >= 0) 979 { 980 delegator = delegatorRequest.getRecipient(); 981 requestCode = delegatorRequest.getActionRequested(); 982 } 983 } 984 } 985 return delegator; 986 } 987 988 @Override 989 public ActionRequestValue findDelegatorRequest(ActionRequestValue actionRequest) { 990 ActionRequestValue parentRequest = actionRequest.getParentActionRequest(); 991 if (parentRequest != null && !(parentRequest.isUserRequest() || parentRequest.isGroupRequest())) { 992 parentRequest = findDelegatorRequest(parentRequest); 993 } 994 return parentRequest; 995 } 996 997 @Override 998 public List<ActionRequestValue> getDelegateRequests(ActionRequestValue actionRequest) { 999 List<ActionRequestValue> delegateRequests = new ArrayList<ActionRequestValue>(); 1000 List<ActionRequestValue> requests = getTopLevelRequests(actionRequest); 1001 for (Object request : requests) 1002 { 1003 ActionRequestValue parentActionRequest = (ActionRequestValue) request; 1004 delegateRequests.addAll(parentActionRequest.getChildrenRequests()); 1005 } 1006 return delegateRequests; 1007 } 1008 1009 @Override 1010 public List<ActionRequestValue> getTopLevelRequests(ActionRequestValue actionRequest) { 1011 List<ActionRequestValue> topLevelRequests = new ArrayList<ActionRequestValue>(); 1012 if (actionRequest.isRoleRequest()) { 1013 topLevelRequests.addAll(actionRequest.getChildrenRequests()); 1014 } else { 1015 topLevelRequests.add(actionRequest); 1016 } 1017 return topLevelRequests; 1018 } 1019 1020 @Override 1021 public boolean doesPrincipalHaveRequest(String principalId, String documentId) { 1022 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 1023 equal(PRINCIPAL_ID, principalId), 1024 equal(DOCUMENT_ID, documentId), 1025 equal(RECIPIENT_TYPE_CD, RecipientType.PRINCIPAL.getCode()), 1026 equal(CURRENT_INDICATOR, Boolean.TRUE) 1027 ); 1028 1029 criteria.setCountFlag(CountFlag.ONLY); 1030 Integer count = getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getTotalRowCount(); 1031 if (count != null && count > 0) { 1032 return true; 1033 } 1034 // TODO since we only store the workgroup id for workgroup requests, if the user is in a workgroup that has a request 1035 // than we need get all the requests with workgroup ids and see if our user is in that group 1036 List<String> groupIds = getActionRequestDAO().getRequestGroupIds(documentId); 1037 for (String groupId : groupIds) { 1038 if (KimApiServiceLocator.getGroupService().isMemberOfGroup(principalId, groupId)) { 1039 return true; 1040 } 1041 } 1042 return false; 1043 } 1044 1045 @Override 1046 public ActionRequestValue getActionRequestForRole(String actionTakenId) { 1047 QueryByCriteria.Builder criteria = QueryByCriteria.Builder.create().setPredicates( 1048 equal(ACTION_TAKEN_ID, actionTakenId), 1049 equal(CURRENT_INDICATOR, Boolean.TRUE), 1050 equal(RECIPIENT_TYPE_CD, RecipientType.ROLE.getCode()), 1051 isNull(PARENT_ACTION_REQUEST) 1052 ); 1053 List<ActionRequestValue> actionTakenRoleRequests = 1054 getDataObjectService().findMatching(ActionRequestValue.class, criteria.build()).getResults(); 1055 if (actionTakenRoleRequests.isEmpty()) { 1056 return null; 1057 } 1058 return actionTakenRoleRequests.get(0); 1059 } 1060 1061 /** 1062 * Returns criteria for selecting "pending" action requests. A request is pending if it's status is activated 1063 * or initialized. 1064 * 1065 * @return criteria for selecting pending action requests 1066 */ 1067 protected Predicate getPendingCriteria() { 1068 return or( 1069 equal(STATUS, ActionRequestStatus.ACTIVATED.getCode()), 1070 equal(STATUS, ActionRequestStatus.INITIALIZED.getCode()) 1071 ); 1072 } 1073 1074 private ActionListService getActionListService() { 1075 return KEWServiceLocator.getActionListService(); 1076 } 1077 1078 private ActionTakenService getActionTakenService() { 1079 return KEWServiceLocator.getActionTakenService(); 1080 } 1081 1082 private RouteHeaderService getRouteHeaderService() { 1083 return KEWServiceLocator.getService(KEWServiceLocator.DOC_ROUTE_HEADER_SRV); 1084 } 1085 1086 public DataObjectService getDataObjectService() { 1087 return dataObjectService; 1088 } 1089 1090 public void setDataObjectService(DataObjectService dataObjectService) { 1091 this.dataObjectService = dataObjectService; 1092 } 1093 1094 public ActionRequestDAO getActionRequestDAO() { 1095 return actionRequestDAO; 1096 } 1097 1098 public void setActionRequestDAO(ActionRequestDAO actionRequestDAO) { 1099 this.actionRequestDAO = actionRequestDAO; 1100 } 1101 1102}