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 */
016 package org.kuali.rice.kew.role.service.impl;
017
018 import org.apache.commons.collections.CollectionUtils;
019 import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
020 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
021 import org.kuali.rice.kew.api.KewApiServiceLocator;
022 import org.kuali.rice.kew.api.action.RolePokerQueue;
023 import org.kuali.rice.kew.api.document.DocumentProcessingQueue;
024 import org.kuali.rice.kew.api.rule.RoleName;
025 import org.kuali.rice.kew.doctype.bo.DocumentType;
026 import org.kuali.rice.kew.engine.RouteContext;
027 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
028 import org.kuali.rice.kew.role.service.RoleService;
029 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
030 import org.kuali.rice.kew.rule.FlexRM;
031 import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
032 import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
033 import org.kuali.rice.kew.service.KEWServiceLocator;
034
035 import java.util.ArrayList;
036 import java.util.Collection;
037 import java.util.HashSet;
038 import java.util.List;
039 import java.util.Set;
040
041
042 /**
043 *
044 * @author Kuali Rice Team (rice.collab@kuali.org)
045 */
046 public 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 }