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