View Javadoc

1   /**
2    * Copyright 2005-2012 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.action.RolePokerQueue;
22  import org.kuali.rice.kew.api.document.DocumentProcessingQueue;
23  import org.kuali.rice.kew.api.extension.ExtensionUtils;
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.messaging.MessageServiceNames;
29  import org.kuali.rice.kew.role.service.RoleService;
30  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
31  import org.kuali.rice.kew.rule.FlexRM;
32  import org.kuali.rice.kew.rule.RoleAttribute;
33  import org.kuali.rice.kew.rule.bo.RuleAttribute;
34  import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
35  import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
36  import org.kuali.rice.kew.service.KEWServiceLocator;
37  
38  import java.util.ArrayList;
39  import java.util.Collection;
40  import java.util.HashSet;
41  import java.util.Iterator;
42  import java.util.List;
43  import java.util.Set;
44  
45  
46  /**
47   *
48   * @author Kuali Rice Team (rice.collab@kuali.org)
49   */
50  public class RoleServiceImpl implements RoleService {
51  
52  	private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RoleServiceImpl.class);
53  
54      public void reResolveRole(DocumentType documentType, String roleName) {
55      	String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName;
56          if (documentType == null ||
57                  org.apache.commons.lang.StringUtils.isEmpty(roleName)) {
58              throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString);
59          }
60          LOG.debug("Re-resolving role asynchronously for "+infoString);
61      	Set documentIds = new HashSet();
62      	findAffectedDocuments(documentType, roleName, null, documentIds);
63      	LOG.debug(documentIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerQueue");
64      	for (Iterator iterator = documentIds.iterator(); iterator.hasNext();) {
65      		String documentId = (String) iterator.next();
66      		RolePokerQueue rolePokerQueue = MessageServiceNames.getRolePokerQueue(documentId);
67      		rolePokerQueue.reResolveRole(documentId, roleName);
68  		}
69      }
70  
71      public void reResolveQualifiedRole(DocumentType documentType, String roleName, String qualifiedRoleNameLabel) {
72      	String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel;
73          if (documentType == null ||
74                  org.apache.commons.lang.StringUtils.isEmpty(roleName) ||
75                  org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
76              throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString);
77          }
78          LOG.debug("Re-resolving qualified role asynchronously for "+infoString);
79      	Set documentIds = new HashSet();
80      	findAffectedDocuments(documentType, roleName, qualifiedRoleNameLabel, documentIds);
81      	LOG.debug(documentIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerQueue");
82      	for (Iterator iterator = documentIds.iterator(); iterator.hasNext();) {
83      		String documentId = (String) iterator.next();
84      		RolePokerQueue rolePokerQueue = MessageServiceNames.getRolePokerQueue(documentId);
85      		rolePokerQueue.reResolveQualifiedRole(documentId, roleName, qualifiedRoleNameLabel);
86  		}
87      }
88  
89      /**
90       *
91       * route level and then filters in the approriate ones.
92       */
93      public void reResolveQualifiedRole(DocumentRouteHeaderValue routeHeader, String roleName, String qualifiedRoleNameLabel) {
94          String infoString = "routeHeader="+(routeHeader == null ? null : routeHeader.getDocumentId())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel;
95          if (routeHeader == null ||
96                  org.apache.commons.lang.StringUtils.isEmpty(roleName) ||
97                  org.apache.commons.lang.StringUtils.isEmpty(qualifiedRoleNameLabel)) {
98              throw new IllegalArgumentException("Cannot pass null arguments to reResolveQualifiedRole: "+infoString);
99          }
100         LOG.debug("Re-resolving qualified role synchronously for "+infoString);
101         List nodeInstances = findNodeInstances(routeHeader, roleName);
102         int requestsGenerated = 0;
103         if (!nodeInstances.isEmpty()) {
104             deletePendingRoleRequests(routeHeader.getDocumentId(), roleName, qualifiedRoleNameLabel);
105             for (Iterator nodeIt = nodeInstances.iterator(); nodeIt.hasNext();) {
106                 RouteNodeInstance nodeInstance = (RouteNodeInstance)nodeIt.next();
107                 RuleTemplateBo ruleTemplate = nodeInstance.getRouteNode().getRuleTemplate();
108                 FlexRM flexRM = new FlexRM();
109         		RouteContext context = RouteContext.getCurrentRouteContext();
110         		context.setDocument(routeHeader);
111         		context.setNodeInstance(nodeInstance);
112         		try {
113         			List actionRequests = flexRM.getActionRequests(routeHeader, nodeInstance, ruleTemplate.getName());
114         			for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
115         				ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
116         				if (roleName.equals(actionRequest.getRoleName()) && qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel())) {
117         					actionRequest = KEWServiceLocator.getActionRequestService().initializeActionRequestGraph(actionRequest, routeHeader, nodeInstance);
118         					KEWServiceLocator.getActionRequestService().saveActionRequest(actionRequest);
119         					requestsGenerated++;
120         				}
121         			}
122         		} catch (Exception e) {
123         			RouteContext.clearCurrentRouteContext();
124         		}
125 
126             }
127         }
128         LOG.debug("Generated "+requestsGenerated+" action requests after re-resolve: "+infoString);
129         requeueDocument(routeHeader);
130     }
131 
132     public void reResolveRole(DocumentRouteHeaderValue routeHeader, String roleName) {
133     	String infoString = "routeHeader="+(routeHeader == null ? null : routeHeader.getDocumentId())+", role="+roleName;
134         if (routeHeader == null ||
135                 org.apache.commons.lang.StringUtils.isEmpty(roleName)) {
136             throw new RiceIllegalArgumentException("Cannot pass null arguments to reResolveQualifiedRole: "+infoString);
137         }
138         LOG.debug("Re-resolving role synchronously for "+infoString);
139         List nodeInstances = findNodeInstances(routeHeader, roleName);
140         int requestsGenerated = 0;
141         if (!nodeInstances.isEmpty()) {
142             deletePendingRoleRequests(routeHeader.getDocumentId(), roleName, null);
143             for (Iterator nodeIt = nodeInstances.iterator(); nodeIt.hasNext();) {
144                 RouteNodeInstance nodeInstance = (RouteNodeInstance)nodeIt.next();
145                 RuleTemplateBo ruleTemplate = nodeInstance.getRouteNode().getRuleTemplate();
146                 FlexRM flexRM = new FlexRM();
147         		RouteContext context = RouteContext.getCurrentRouteContext();
148         		context.setDocument(routeHeader);
149         		context.setNodeInstance(nodeInstance);
150         		try {
151         			List actionRequests = flexRM.getActionRequests(routeHeader, nodeInstance, ruleTemplate.getName());
152         			for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
153         				ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
154         				if (roleName.equals(actionRequest.getRoleName())) {
155         					actionRequest = KEWServiceLocator.getActionRequestService().initializeActionRequestGraph(actionRequest, routeHeader, nodeInstance);
156         					KEWServiceLocator.getActionRequestService().saveActionRequest(actionRequest);
157         					requestsGenerated++;
158         				}
159         			}
160         		} finally {
161         			RouteContext.clearCurrentRouteContext();
162         		}
163             }
164         }
165         LOG.debug("Generated "+requestsGenerated+" action requests after re-resolve: "+infoString);
166         requeueDocument(routeHeader);
167     }
168 
169     // search the document type and all its children
170     private void findAffectedDocuments(DocumentType documentType, String roleName, String qualifiedRoleNameLabel, Set documentIds) {
171     	List pendingRequests = KEWServiceLocator.getActionRequestService().findPendingRootRequestsByDocumentType(documentType.getDocumentTypeId());
172     	for (Iterator iterator = pendingRequests.iterator(); iterator.hasNext();) {
173 			ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
174 			if (roleName.equals(actionRequest.getRoleName()) &&
175 					(qualifiedRoleNameLabel == null || qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel()))) {
176 				documentIds.add(actionRequest.getDocumentId());
177 			}
178 		}
179     	for (Iterator iterator = documentType.getChildrenDocTypes().iterator(); iterator.hasNext();) {
180 			DocumentType childDocumentType = (DocumentType) iterator.next();
181 			findAffectedDocuments(childDocumentType, roleName, qualifiedRoleNameLabel, documentIds);
182 		}
183     }
184 
185     private void deletePendingRoleRequests(String documentId, String roleName, String qualifiedRoleNameLabel) {
186         List pendingRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(documentId);
187         pendingRequests = KEWServiceLocator.getActionRequestService().getRootRequests(pendingRequests);
188         List requestsToDelete = new ArrayList();
189         for (Iterator iterator = pendingRequests.iterator(); iterator.hasNext();) {
190             ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
191             if (roleName.equals(actionRequest.getRoleName()) &&
192             		(qualifiedRoleNameLabel == null || qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel()))) {
193                 requestsToDelete.add(actionRequest);
194             }
195         }
196         LOG.debug("Deleting "+requestsToDelete.size()+" action requests for roleName="+roleName+", qualifiedRoleNameLabel="+qualifiedRoleNameLabel);
197         for (Iterator iterator = requestsToDelete.iterator(); iterator.hasNext();) {
198             KEWServiceLocator.getActionRequestService().deleteActionRequestGraph((ActionRequestValue)iterator.next());
199         }
200     }
201 
202     private List findNodeInstances(DocumentRouteHeaderValue routeHeader, String roleName) {
203         List nodeInstances = new ArrayList();
204         Collection activeNodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(routeHeader.getDocumentId());
205         if (CollectionUtils.isEmpty(activeNodeInstances)) {
206             throw new IllegalStateException("Document does not currently have any active nodes so re-resolving is not legal.");
207         }
208         for (Iterator iterator = activeNodeInstances.iterator(); iterator.hasNext();) {
209             RouteNodeInstance activeNodeInstance = (RouteNodeInstance) iterator.next();
210             RuleTemplateBo template = activeNodeInstance.getRouteNode().getRuleTemplate();
211             if (templateHasRole(template, roleName)) {
212                 nodeInstances.add(activeNodeInstance);
213             }
214         }
215         if (nodeInstances.isEmpty()) {
216             throw new IllegalStateException("Could not locate given role to re-resolve: " + roleName);
217         }
218         return nodeInstances;
219     }
220 
221     private boolean templateHasRole(RuleTemplateBo template, String roleName) {
222         List<RuleTemplateAttributeBo> templateAttributes = template.getRuleTemplateAttributes();
223         for (RuleTemplateAttributeBo templateAttribute : templateAttributes) {
224             RuleAttribute ruleAttribute = templateAttribute.getRuleAttribute();
225             Object workflowAttribute = ExtensionUtils.loadExtension(ruleAttribute);
226 
227             if (workflowAttribute instanceof RoleAttribute) {
228                 List<RoleName> roleNames = ((RoleAttribute)workflowAttribute).getRoleNames();
229                 for (RoleName role : roleNames) {
230                     if (role.getLabel().equals(roleName)) {
231                         return true;
232                     }
233                 }
234             }
235         }
236         return false;
237     }
238 
239     protected void requeueDocument(DocumentRouteHeaderValue document) {
240         DocumentProcessingQueue documentProcessingQueue = MessageServiceNames.getDocumentProcessingQueue(document);
241         documentProcessingQueue.process(document.getDocumentId());
242     }
243 
244 }