View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.role.service.impl;
17  
18  import org.apache.commons.collections.CollectionUtils;
19  import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
20  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
21  import org.kuali.rice.kew.api.KewApiServiceLocator;
22  import org.kuali.rice.kew.api.action.RolePokerQueue;
23  import org.kuali.rice.kew.api.document.DocumentProcessingQueue;
24  import org.kuali.rice.kew.api.rule.RoleName;
25  import org.kuali.rice.kew.doctype.bo.DocumentType;
26  import org.kuali.rice.kew.engine.RouteContext;
27  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
28  import org.kuali.rice.kew.role.service.RoleService;
29  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
30  import org.kuali.rice.kew.rule.FlexRM;
31  import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
32  import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
33  import org.kuali.rice.kew.service.KEWServiceLocator;
34  
35  import java.util.ArrayList;
36  import java.util.Collection;
37  import java.util.HashSet;
38  import java.util.List;
39  import java.util.Set;
40  
41  
42  /**
43   *
44   * @author Kuali Rice Team (rice.collab@kuali.org)
45   */
46  public class RoleServiceImpl implements RoleService {
47  
48  	private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RoleServiceImpl.class);
49  
50      public void reResolveRole(DocumentType documentType, String roleName) {
51      	String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName;
52          if (documentType == null ||
53                  org.apache.commons.lang.StringUtils.isEmpty(roleName)) {
54              throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString);
55          }
56          LOG.debug("Re-resolving role asynchronously for "+infoString);
57      	Set<String> documentIds = new HashSet<String>();
58      	findAffectedDocuments(documentType, roleName, null, documentIds);
59      	LOG.debug(documentIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerQueue");
60          for (String documentId : documentIds) {
61              String applicationId = KEWServiceLocator.getRouteHeaderService().getApplicationIdByDocumentId(documentId);
62              RolePokerQueue rolePokerQueue = KewApiServiceLocator.getRolePokerQueue(documentId, applicationId);
63      		rolePokerQueue.reResolveRole(documentId, roleName);
64  		}
65      }
66  
67      public void reResolveQualifiedRole(DocumentType documentType, String roleName, String qualifiedRoleNameLabel) {
68      	String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel;
69          if (documentType == null ||
70                  org.apache.commons.lang.StringUtils.isEmpty(roleName) ||
71                  org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
72              throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString);
73          }
74          LOG.debug("Re-resolving qualified role asynchronously for "+infoString);
75      	Set<String> documentIds = new HashSet<String>();
76      	findAffectedDocuments(documentType, roleName, qualifiedRoleNameLabel, documentIds);
77      	LOG.debug(documentIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerQueue");
78          for (String documentId : documentIds) {
79              String applicationId = KEWServiceLocator.getRouteHeaderService().getApplicationIdByDocumentId(documentId);
80              RolePokerQueue rolePokerQueue = KewApiServiceLocator.getRolePokerQueue(documentId, applicationId);
81      		rolePokerQueue.reResolveQualifiedRole(documentId, roleName, qualifiedRoleNameLabel);
82  		}
83      }
84  
85      /**
86       *
87       * route level and then filters in the approriate ones.
88       */
89      public void reResolveQualifiedRole(DocumentRouteHeaderValue routeHeader, String roleName, String qualifiedRoleNameLabel) {
90          String infoString = "routeHeader="+(routeHeader == null ? null : routeHeader.getDocumentId())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel;
91          if (routeHeader == null ||
92                  org.apache.commons.lang.StringUtils.isEmpty(roleName) ||
93                  org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
94              throw new IllegalArgumentException("Cannot pass null arguments to reResolveQualifiedRole: "+infoString);
95          }
96          LOG.debug("Re-resolving qualified role synchronously for "+infoString);
97          List<RouteNodeInstance> nodeInstances = findNodeInstances(routeHeader, roleName);
98          int requestsGenerated = 0;
99          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 }