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.role.service.impl; 017 018import org.apache.commons.collections.CollectionUtils; 019import org.kuali.rice.core.api.exception.RiceIllegalArgumentException; 020import org.kuali.rice.kew.actionrequest.ActionRequestValue; 021import org.kuali.rice.kew.api.KewApiServiceLocator; 022import org.kuali.rice.kew.api.action.RolePokerQueue; 023import org.kuali.rice.kew.api.document.DocumentProcessingQueue; 024import org.kuali.rice.kew.api.rule.RoleName; 025import org.kuali.rice.kew.doctype.bo.DocumentType; 026import org.kuali.rice.kew.engine.RouteContext; 027import org.kuali.rice.kew.engine.node.RouteNodeInstance; 028import org.kuali.rice.kew.role.service.RoleService; 029import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 030import org.kuali.rice.kew.rule.FlexRM; 031import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo; 032import org.kuali.rice.kew.rule.bo.RuleTemplateBo; 033import org.kuali.rice.kew.service.KEWServiceLocator; 034 035import java.util.ArrayList; 036import java.util.Collection; 037import java.util.HashSet; 038import java.util.Iterator; 039import java.util.List; 040import java.util.Set; 041 042 043/** 044 * 045 * @author Kuali Rice Team (rice.collab@kuali.org) 046 */ 047public class RoleServiceImpl implements RoleService { 048 049 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RoleServiceImpl.class); 050 051 public void reResolveRole(DocumentType documentType, String roleName) { 052 String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName; 053 if (documentType == null || 054 org.apache.commons.lang.StringUtils.isEmpty(roleName)) { 055 throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString); 056 } 057 LOG.debug("Re-resolving role asynchronously for "+infoString); 058 Set documentIds = new HashSet(); 059 findAffectedDocuments(documentType, roleName, null, documentIds); 060 LOG.debug(documentIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerQueue"); 061 for (Iterator iterator = documentIds.iterator(); iterator.hasNext();) { 062 String documentId = (String) iterator.next(); 063 String applicationId = KEWServiceLocator.getRouteHeaderService().getApplicationIdByDocumentId(documentId); 064 RolePokerQueue rolePokerQueue = KewApiServiceLocator.getRolePokerQueue(documentId, applicationId); 065 rolePokerQueue.reResolveRole(documentId, roleName); 066 } 067 } 068 069 public void reResolveQualifiedRole(DocumentType documentType, String roleName, String qualifiedRoleNameLabel) { 070 String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel; 071 if (documentType == null || 072 org.apache.commons.lang.StringUtils.isEmpty(roleName) || 073 org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) { 074 throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString); 075 } 076 LOG.debug("Re-resolving qualified role asynchronously for "+infoString); 077 Set documentIds = new HashSet(); 078 findAffectedDocuments(documentType, roleName, qualifiedRoleNameLabel, documentIds); 079 LOG.debug(documentIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerQueue"); 080 for (Iterator iterator = documentIds.iterator(); iterator.hasNext();) { 081 String documentId = (String) iterator.next(); 082 String applicationId = KEWServiceLocator.getRouteHeaderService().getApplicationIdByDocumentId(documentId); 083 RolePokerQueue rolePokerQueue = KewApiServiceLocator.getRolePokerQueue(documentId, applicationId); 084 rolePokerQueue.reResolveQualifiedRole(documentId, roleName, qualifiedRoleNameLabel); 085 } 086 } 087 088 /** 089 * 090 * route level and then filters in the approriate ones. 091 */ 092 public void reResolveQualifiedRole(DocumentRouteHeaderValue routeHeader, String roleName, String qualifiedRoleNameLabel) { 093 String infoString = "routeHeader="+(routeHeader == null ? null : routeHeader.getDocumentId())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel; 094 if (routeHeader == null || 095 org.apache.commons.lang.StringUtils.isEmpty(roleName) || 096 org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) { 097 throw new IllegalArgumentException("Cannot pass null arguments to reResolveQualifiedRole: "+infoString); 098 } 099 LOG.debug("Re-resolving qualified role synchronously for "+infoString); 100 List nodeInstances = findNodeInstances(routeHeader, roleName); 101 int requestsGenerated = 0; 102 if (!nodeInstances.isEmpty()) { 103 deletePendingRoleRequests(routeHeader.getDocumentId(), roleName, qualifiedRoleNameLabel); 104 for (Iterator nodeIt = nodeInstances.iterator(); nodeIt.hasNext();) { 105 RouteNodeInstance nodeInstance = (RouteNodeInstance)nodeIt.next(); 106 RuleTemplateBo ruleTemplate = nodeInstance.getRouteNode().getRuleTemplate(); 107 FlexRM flexRM = new FlexRM(); 108 RouteContext context = RouteContext.getCurrentRouteContext(); 109 context.setDocument(routeHeader); 110 context.setNodeInstance(nodeInstance); 111 try { 112 List actionRequests = flexRM.getActionRequests(routeHeader, nodeInstance, ruleTemplate.getName()); 113 for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) { 114 ActionRequestValue actionRequest = (ActionRequestValue) iterator.next(); 115 if (roleName.equals(actionRequest.getRoleName()) && qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel())) { 116 actionRequest = KEWServiceLocator.getActionRequestService().initializeActionRequestGraph(actionRequest, routeHeader, nodeInstance); 117 KEWServiceLocator.getActionRequestService().saveActionRequest(actionRequest); 118 requestsGenerated++; 119 } 120 } 121 } catch (Exception e) { 122 RouteContext.clearCurrentRouteContext(); 123 } 124 125 } 126 } 127 LOG.debug("Generated "+requestsGenerated+" action requests after re-resolve: "+infoString); 128 requeueDocument(routeHeader); 129 } 130 131 public void reResolveRole(DocumentRouteHeaderValue routeHeader, String roleName) { 132 String infoString = "routeHeader="+(routeHeader == null ? null : routeHeader.getDocumentId())+", role="+roleName; 133 if (routeHeader == null || 134 org.apache.commons.lang.StringUtils.isEmpty(roleName)) { 135 throw new RiceIllegalArgumentException("Cannot pass null arguments to reResolveQualifiedRole: "+infoString); 136 } 137 LOG.debug("Re-resolving role synchronously for "+infoString); 138 List nodeInstances = findNodeInstances(routeHeader, roleName); 139 int requestsGenerated = 0; 140 if (!nodeInstances.isEmpty()) { 141 deletePendingRoleRequests(routeHeader.getDocumentId(), roleName, null); 142 for (Iterator nodeIt = nodeInstances.iterator(); nodeIt.hasNext();) { 143 RouteNodeInstance nodeInstance = (RouteNodeInstance)nodeIt.next(); 144 RuleTemplateBo ruleTemplate = nodeInstance.getRouteNode().getRuleTemplate(); 145 FlexRM flexRM = new FlexRM(); 146 RouteContext context = RouteContext.getCurrentRouteContext(); 147 context.setDocument(routeHeader); 148 context.setNodeInstance(nodeInstance); 149 try { 150 List actionRequests = flexRM.getActionRequests(routeHeader, nodeInstance, ruleTemplate.getName()); 151 for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) { 152 ActionRequestValue actionRequest = (ActionRequestValue) iterator.next(); 153 if (roleName.equals(actionRequest.getRoleName())) { 154 actionRequest = KEWServiceLocator.getActionRequestService().initializeActionRequestGraph(actionRequest, routeHeader, nodeInstance); 155 KEWServiceLocator.getActionRequestService().saveActionRequest(actionRequest); 156 requestsGenerated++; 157 } 158 } 159 } finally { 160 RouteContext.clearCurrentRouteContext(); 161 } 162 } 163 } 164 LOG.debug("Generated "+requestsGenerated+" action requests after re-resolve: "+infoString); 165 requeueDocument(routeHeader); 166 } 167 168 // search the document type and all its children 169 private void findAffectedDocuments(DocumentType documentType, String roleName, String qualifiedRoleNameLabel, Set documentIds) { 170 List pendingRequests = KEWServiceLocator.getActionRequestService().findPendingRootRequestsByDocumentType(documentType.getDocumentTypeId()); 171 for (Iterator iterator = pendingRequests.iterator(); iterator.hasNext();) { 172 ActionRequestValue actionRequest = (ActionRequestValue) iterator.next(); 173 if (roleName.equals(actionRequest.getRoleName()) && 174 (qualifiedRoleNameLabel == null || qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel()))) { 175 documentIds.add(actionRequest.getDocumentId()); 176 } 177 } 178 for (Iterator iterator = documentType.getChildrenDocTypes().iterator(); iterator.hasNext();) { 179 DocumentType childDocumentType = (DocumentType) iterator.next(); 180 findAffectedDocuments(childDocumentType, roleName, qualifiedRoleNameLabel, documentIds); 181 } 182 } 183 184 private void deletePendingRoleRequests(String documentId, String roleName, String qualifiedRoleNameLabel) { 185 List pendingRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(documentId); 186 pendingRequests = KEWServiceLocator.getActionRequestService().getRootRequests(pendingRequests); 187 List requestsToDelete = new ArrayList(); 188 for (Iterator iterator = pendingRequests.iterator(); iterator.hasNext();) { 189 ActionRequestValue actionRequest = (ActionRequestValue) iterator.next(); 190 if (roleName.equals(actionRequest.getRoleName()) && 191 (qualifiedRoleNameLabel == null || qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel()))) { 192 requestsToDelete.add(actionRequest); 193 } 194 } 195 LOG.debug("Deleting "+requestsToDelete.size()+" action requests for roleName="+roleName+", qualifiedRoleNameLabel="+qualifiedRoleNameLabel); 196 for (Iterator iterator = requestsToDelete.iterator(); iterator.hasNext();) { 197 KEWServiceLocator.getActionRequestService().deleteActionRequestGraph((ActionRequestValue)iterator.next()); 198 } 199 } 200 201 private List findNodeInstances(DocumentRouteHeaderValue routeHeader, String roleName) { 202 List nodeInstances = new ArrayList(); 203 Collection activeNodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(routeHeader.getDocumentId()); 204 if (CollectionUtils.isEmpty(activeNodeInstances)) { 205 throw new IllegalStateException("Document does not currently have any active nodes so re-resolving is not legal."); 206 } 207 for (Iterator iterator = activeNodeInstances.iterator(); iterator.hasNext();) { 208 RouteNodeInstance activeNodeInstance = (RouteNodeInstance) iterator.next(); 209 RuleTemplateBo template = activeNodeInstance.getRouteNode().getRuleTemplate(); 210 if (templateHasRole(template, roleName)) { 211 nodeInstances.add(activeNodeInstance); 212 } 213 } 214 if (nodeInstances.isEmpty()) { 215 throw new IllegalStateException("Could not locate given role to re-resolve: " + roleName); 216 } 217 return nodeInstances; 218 } 219 220 private boolean templateHasRole(RuleTemplateBo template, String roleName) { 221 List<RuleTemplateAttributeBo> templateAttributes = template.getRuleTemplateAttributes(); 222 for (RuleTemplateAttributeBo templateAttribute : templateAttributes) { 223 List<RoleName> roleNames = KEWServiceLocator.getWorkflowRuleAttributeMediator().getRoleNames(templateAttribute); 224 for (RoleName role : roleNames) { 225 if (role.getLabel().equals(roleName)) { 226 return true; 227 } 228 } 229 } 230 return false; 231 } 232 233 protected void requeueDocument(DocumentRouteHeaderValue document) { 234 String applicationId = document.getDocumentType().getApplicationId(); 235 DocumentProcessingQueue documentProcessingQueue = KewApiServiceLocator.getDocumentProcessingQueue(document.getDocumentId(), applicationId); 236 documentProcessingQueue.process(document.getDocumentId()); 237 } 238 239}