View Javadoc

1   /**
2    * Copyright 2005-2013 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.Iterator;
39  import java.util.List;
40  import java.util.Set;
41  
42  
43  /**
44   *
45   * @author Kuali Rice Team (rice.collab@kuali.org)
46   */
47  public class RoleServiceImpl implements RoleService {
48  
49  	private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RoleServiceImpl.class);
50  
51      public void reResolveRole(DocumentType documentType, String roleName) {
52      	String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName;
53          if (documentType == null ||
54                  org.apache.commons.lang.StringUtils.isEmpty(roleName)) {
55              throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString);
56          }
57          LOG.debug("Re-resolving role asynchronously for "+infoString);
58      	Set documentIds = new HashSet();
59      	findAffectedDocuments(documentType, roleName, null, documentIds);
60      	LOG.debug(documentIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerQueue");
61      	for (Iterator iterator = documentIds.iterator(); iterator.hasNext();) {
62      		String documentId = (String) iterator.next();
63              String applicationId = KEWServiceLocator.getRouteHeaderService().getApplicationIdByDocumentId(documentId);
64              RolePokerQueue rolePokerQueue = KewApiServiceLocator.getRolePokerQueue(documentId, applicationId);
65      		rolePokerQueue.reResolveRole(documentId, roleName);
66  		}
67      }
68  
69      public void reResolveQualifiedRole(DocumentType documentType, String roleName, String qualifiedRoleNameLabel) {
70      	String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel;
71          if (documentType == null ||
72                  org.apache.commons.lang.StringUtils.isEmpty(roleName) ||
73                  org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
74              throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString);
75          }
76          LOG.debug("Re-resolving qualified role asynchronously for "+infoString);
77      	Set documentIds = new HashSet();
78      	findAffectedDocuments(documentType, roleName, qualifiedRoleNameLabel, documentIds);
79      	LOG.debug(documentIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerQueue");
80      	for (Iterator iterator = documentIds.iterator(); iterator.hasNext();) {
81      		String documentId = (String) iterator.next();
82              String applicationId = KEWServiceLocator.getRouteHeaderService().getApplicationIdByDocumentId(documentId);
83              RolePokerQueue rolePokerQueue = KewApiServiceLocator.getRolePokerQueue(documentId, applicationId);
84      		rolePokerQueue.reResolveQualifiedRole(documentId, roleName, qualifiedRoleNameLabel);
85  		}
86      }
87  
88      /**
89       *
90       * route level and then filters in the approriate ones.
91       */
92      public void reResolveQualifiedRole(DocumentRouteHeaderValue routeHeader, String roleName, String qualifiedRoleNameLabel) {
93          String infoString = "routeHeader="+(routeHeader == null ? null : routeHeader.getDocumentId())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel;
94          if (routeHeader == null ||
95                  org.apache.commons.lang.StringUtils.isEmpty(roleName) ||
96                  org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
97              throw new IllegalArgumentException("Cannot pass null arguments to reResolveQualifiedRole: "+infoString);
98          }
99          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 }