View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    *
4    *
5    * Licensed under the Educational Community License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.opensource.org/licenses/ecl2.php
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.kuali.rice.kew.role.service.impl;
18  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Set;
25  
26  import javax.xml.namespace.QName;
27  
28  import org.kuali.rice.core.reflect.ObjectDefinition;
29  import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
30  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
31  import org.kuali.rice.kew.doctype.bo.DocumentType;
32  import org.kuali.rice.kew.engine.RouteContext;
33  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
34  import org.kuali.rice.kew.exception.WorkflowException;
35  import org.kuali.rice.kew.exception.WorkflowRuntimeException;
36  import org.kuali.rice.kew.messaging.MessageServiceNames;
37  import org.kuali.rice.kew.role.service.RoleService;
38  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
39  import org.kuali.rice.kew.rule.FlexRM;
40  import org.kuali.rice.kew.rule.RoleAttribute;
41  import org.kuali.rice.kew.rule.RolePoker;
42  import org.kuali.rice.kew.rule.bo.RuleAttribute;
43  import org.kuali.rice.kew.rule.bo.RuleTemplate;
44  import org.kuali.rice.kew.rule.bo.RuleTemplateAttribute;
45  import org.kuali.rice.kew.service.KEWServiceLocator;
46  import org.kuali.rice.kew.util.Utilities;
47  import org.kuali.rice.ksb.messaging.service.KSBXMLService;
48  import org.kuali.rice.ksb.service.KSBServiceLocator;
49  
50  
51  /**
52   *
53   * @author Kuali Rice Team (rice.collab@kuali.org)
54   */
55  public class RoleServiceImpl implements RoleService {
56  
57  	private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RoleServiceImpl.class);
58  
59      public void reResolveRole(DocumentType documentType, String roleName) throws WorkflowException {
60      	String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName;
61          if (documentType == null ||
62                  Utilities.isEmpty(roleName)) {
63              throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveRole: "+infoString);
64          }
65          LOG.debug("Re-resolving role asynchronously for "+infoString);
66      	Set routeHeaderIds = new HashSet();
67      	findAffectedDocuments(documentType, roleName, null, routeHeaderIds);
68      	LOG.debug(routeHeaderIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerProcessor");
69      	for (Iterator iterator = routeHeaderIds.iterator(); iterator.hasNext();) {
70      		Long documentId = (Long) iterator.next();
71      		QName rolePokerName = new QName(documentType.getServiceNamespace(), MessageServiceNames.ROLE_POKER);
72      		RolePoker rolePoker = (RolePoker)KSBServiceLocator.getMessageHelper().getServiceAsynchronously(rolePokerName);
73      		rolePoker.reResolveRole(documentId, roleName);
74  		}
75      }
76  
77      public void reResolveQualifiedRole(DocumentType documentType, String roleName, String qualifiedRoleNameLabel) throws WorkflowException {
78      	String infoString = "documentType="+(documentType == null ? null : documentType.getName())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel;
79          if (documentType == null ||
80                  Utilities.isEmpty(roleName) ||
81                  Utilities.isEmpty(qualifiedRoleNameLabel)) {
82              throw new IllegalArgumentException("Cannot pass null or empty arguments to reResolveQualifiedRole: "+infoString);
83          }
84          LOG.debug("Re-resolving qualified role asynchronously for "+infoString);
85      	Set routeHeaderIds = new HashSet();
86      	findAffectedDocuments(documentType, roleName, qualifiedRoleNameLabel, routeHeaderIds);
87      	LOG.debug(routeHeaderIds.size()+" documents were affected by this re-resolution, requeueing with the RolePokerProcessor");
88      	for (Iterator iterator = routeHeaderIds.iterator(); iterator.hasNext();) {
89      		Long documentId = (Long) iterator.next();
90  
91      		QName rolePokerName = new QName(documentType.getServiceNamespace(), MessageServiceNames.ROLE_POKER);
92      		RolePoker rolePoker = (RolePoker)KSBServiceLocator.getMessageHelper().getServiceAsynchronously(rolePokerName);
93      		rolePoker.reResolveRole(documentId, roleName, qualifiedRoleNameLabel);
94  		}
95      }
96  
97      /**
98       *
99       * route level and then filters in the approriate ones.
100      */
101     public void reResolveQualifiedRole(DocumentRouteHeaderValue routeHeader, String roleName, String qualifiedRoleNameLabel) throws WorkflowException {
102         String infoString = "routeHeader="+(routeHeader == null ? null : routeHeader.getRouteHeaderId())+", role="+roleName+", qualifiedRole="+qualifiedRoleNameLabel;
103         if (routeHeader == null ||
104                 Utilities.isEmpty(roleName) ||
105                 Utilities.isEmpty(qualifiedRoleNameLabel)) {
106             throw new IllegalArgumentException("Cannot pass null arguments to reResolveQualifiedRole: "+infoString);
107         }
108         LOG.debug("Re-resolving qualified role synchronously for "+infoString);
109         List nodeInstances = findNodeInstances(routeHeader, roleName);
110         int requestsGenerated = 0;
111         if (!nodeInstances.isEmpty()) {
112             deletePendingRoleRequests(routeHeader.getRouteHeaderId(), roleName, qualifiedRoleNameLabel);
113             for (Iterator nodeIt = nodeInstances.iterator(); nodeIt.hasNext();) {
114                 RouteNodeInstance nodeInstance = (RouteNodeInstance)nodeIt.next();
115                 RuleTemplate ruleTemplate = nodeInstance.getRouteNode().getRuleTemplate();
116                 FlexRM flexRM = new FlexRM();
117         		RouteContext context = RouteContext.getCurrentRouteContext();
118         		context.setDocument(routeHeader);
119         		context.setNodeInstance(nodeInstance);
120         		try {
121         			List actionRequests = flexRM.getActionRequests(routeHeader, nodeInstance, ruleTemplate.getName());
122         			for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
123         				ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
124         				if (roleName.equals(actionRequest.getRoleName()) && qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel())) {
125         					actionRequest = KEWServiceLocator.getActionRequestService().initializeActionRequestGraph(actionRequest, routeHeader, nodeInstance);
126         					KEWServiceLocator.getActionRequestService().saveActionRequest(actionRequest);
127         					requestsGenerated++;
128         				}
129         			}
130         		} catch (Exception e) {
131         			RouteContext.clearCurrentRouteContext();
132         		}
133 
134             }
135         }
136         LOG.debug("Generated "+requestsGenerated+" action requests after re-resolve: "+infoString);
137         requeueDocument(routeHeader);
138     }
139 
140     public void reResolveRole(DocumentRouteHeaderValue routeHeader, String roleName) throws WorkflowException {
141     	String infoString = "routeHeader="+(routeHeader == null ? null : routeHeader.getRouteHeaderId())+", role="+roleName;
142         if (routeHeader == null ||
143                 Utilities.isEmpty(roleName)) {
144             throw new IllegalArgumentException("Cannot pass null arguments to reResolveRole: "+infoString);
145         }
146         LOG.debug("Re-resolving role synchronously for "+infoString);
147         List nodeInstances = findNodeInstances(routeHeader, roleName);
148         int requestsGenerated = 0;
149         if (!nodeInstances.isEmpty()) {
150             deletePendingRoleRequests(routeHeader.getRouteHeaderId(), roleName, null);
151             for (Iterator nodeIt = nodeInstances.iterator(); nodeIt.hasNext();) {
152                 RouteNodeInstance nodeInstance = (RouteNodeInstance)nodeIt.next();
153                 RuleTemplate ruleTemplate = nodeInstance.getRouteNode().getRuleTemplate();
154                 FlexRM flexRM = new FlexRM();
155         		RouteContext context = RouteContext.getCurrentRouteContext();
156         		context.setDocument(routeHeader);
157         		context.setNodeInstance(nodeInstance);
158         		try {
159         			List actionRequests = flexRM.getActionRequests(routeHeader, nodeInstance, ruleTemplate.getName());
160         			for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
161         				ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
162         				if (roleName.equals(actionRequest.getRoleName())) {
163         					actionRequest = KEWServiceLocator.getActionRequestService().initializeActionRequestGraph(actionRequest, routeHeader, nodeInstance);
164         					KEWServiceLocator.getActionRequestService().saveActionRequest(actionRequest);
165         					requestsGenerated++;
166         				}
167         			}
168         		} finally {
169         			RouteContext.clearCurrentRouteContext();
170         		}
171             }
172         }
173         LOG.debug("Generated "+requestsGenerated+" action requests after re-resolve: "+infoString);
174         requeueDocument(routeHeader);
175     }
176 
177     // search the document type and all its children
178     private void findAffectedDocuments(DocumentType documentType, String roleName, String qualifiedRoleNameLabel, Set routeHeaderIds) {
179     	List pendingRequests = KEWServiceLocator.getActionRequestService().findPendingRootRequestsByDocumentType(documentType.getDocumentTypeId());
180     	for (Iterator iterator = pendingRequests.iterator(); iterator.hasNext();) {
181 			ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
182 			if (roleName.equals(actionRequest.getRoleName()) &&
183 					(qualifiedRoleNameLabel == null || qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel()))) {
184 				routeHeaderIds.add(actionRequest.getRouteHeaderId());
185 			}
186 		}
187     	for (Iterator iterator = documentType.getChildrenDocTypes().iterator(); iterator.hasNext();) {
188 			DocumentType childDocumentType = (DocumentType) iterator.next();
189 			findAffectedDocuments(childDocumentType, roleName, qualifiedRoleNameLabel, routeHeaderIds);
190 		}
191     }
192 
193     private void deletePendingRoleRequests(Long routeHeaderId, String roleName, String qualifiedRoleNameLabel) {
194         List pendingRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(routeHeaderId);
195         pendingRequests = KEWServiceLocator.getActionRequestService().getRootRequests(pendingRequests);
196         List requestsToDelete = new ArrayList();
197         for (Iterator iterator = pendingRequests.iterator(); iterator.hasNext();) {
198             ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
199             if (roleName.equals(actionRequest.getRoleName()) &&
200             		(qualifiedRoleNameLabel == null || qualifiedRoleNameLabel.equals(actionRequest.getQualifiedRoleNameLabel()))) {
201                 requestsToDelete.add(actionRequest);
202             }
203         }
204         LOG.debug("Deleting "+requestsToDelete.size()+" action requests for roleName="+roleName+", qualifiedRoleNameLabel="+qualifiedRoleNameLabel);
205         for (Iterator iterator = requestsToDelete.iterator(); iterator.hasNext();) {
206             KEWServiceLocator.getActionRequestService().deleteActionRequestGraph((ActionRequestValue)iterator.next());
207         }
208     }
209 
210     private List findNodeInstances(DocumentRouteHeaderValue routeHeader, String roleName) throws WorkflowException {
211         List nodeInstances = new ArrayList();
212         Collection activeNodeInstances = KEWServiceLocator.getRouteNodeService().getActiveNodeInstances(routeHeader.getRouteHeaderId());
213         if (Utilities.isEmpty(activeNodeInstances)) {
214             throw new WorkflowException("Document does not currently have any active nodes so re-resolving is not legal.");
215         }
216         for (Iterator iterator = activeNodeInstances.iterator(); iterator.hasNext();) {
217             RouteNodeInstance activeNodeInstance = (RouteNodeInstance) iterator.next();
218             RuleTemplate template = activeNodeInstance.getRouteNode().getRuleTemplate();
219             if (templateHasRole(template, roleName)) {
220                 nodeInstances.add(activeNodeInstance);
221             }
222         }
223         if (nodeInstances.isEmpty()) {
224             throw new WorkflowException("Could not locate given role to re-resolve: " + roleName);
225         }
226         return nodeInstances;
227     }
228 
229     private boolean templateHasRole(RuleTemplate template, String roleName) throws WorkflowException {
230         List templateAttributes = template.getRuleTemplateAttributes();
231         for (Iterator iterator = templateAttributes.iterator(); iterator.hasNext();) {
232             RuleTemplateAttribute templateAttribute = (RuleTemplateAttribute) iterator.next();
233             RuleAttribute ruleAttribute = templateAttribute.getRuleAttribute();
234             Object workflowAttribute = GlobalResourceLoader.getResourceLoader().getObject(new ObjectDefinition(ruleAttribute.getClassName()));//SpringServiceLocator.getExtensionService().getWorkflowAttribute(ruleAttribute.getClassName());
235             if (workflowAttribute instanceof RoleAttribute) {
236                 List roleNames = ((RoleAttribute)workflowAttribute).getRoleNames();
237                 for (Iterator roleIt = roleNames.iterator(); roleIt.hasNext();) {
238                     org.kuali.rice.kew.rule.Role role = (org.kuali.rice.kew.rule.Role) roleIt.next();
239                     if (role.getLabel().equals(roleName)) {
240                         return true;
241                     }
242                 }
243             }
244         }
245         return false;
246     }
247 
248     protected void requeueDocument(DocumentRouteHeaderValue document) {
249     	QName documentServiceName = new QName(document.getDocumentType().getServiceNamespace(), MessageServiceNames.DOCUMENT_ROUTING_SERVICE);
250     	KSBXMLService documentRoutingService = (KSBXMLService)MessageServiceNames.getServiceAsynchronously(documentServiceName, document);
251     	try {
252 			documentRoutingService.invoke(String.valueOf(document.getRouteHeaderId()));
253 		} catch (Exception e) {
254 			throw new WorkflowRuntimeException(e);
255 		}
256     }
257 
258 }