View Javadoc
1   /**
2    * Copyright 2005-2014 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.impl.document;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.List;
21  
22  import org.apache.commons.collections.CollectionUtils;
23  import org.apache.commons.lang.StringUtils;
24  import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
25  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
26  import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
27  import org.kuali.rice.kew.actionrequest.service.impl.NotificationSuppression;
28  import org.kuali.rice.kew.api.document.DocumentRefreshQueue;
29  import org.kuali.rice.kew.api.WorkflowRuntimeException;
30  import org.kuali.rice.kew.engine.OrchestrationConfig;
31  import org.kuali.rice.kew.engine.OrchestrationConfig.EngineCapability;
32  import org.kuali.rice.kew.engine.RouteHelper;
33  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
34  import org.kuali.rice.kew.engine.node.service.RouteNodeService;
35  import org.kuali.rice.kew.service.KEWServiceLocator;
36  import org.kuali.rice.kew.util.PerformanceLogger;
37  
38  
39  /**
40   * A service which effectively "refreshes" and requeues a document.  It first deletes any
41   * pending action requests on the documents and then requeues the document for standard routing.
42   * Addionally, it adds duplicate notification suppression state to RouteNodeInstanceS for 
43   * which ActionRequestS will be regenerated. 
44   * 
45   * <p>Intended to be called async and wired that way in server/client spring beans.</p>
46   * 
47   * @author Kuali Rice Team (rice.collab@kuali.org)
48   */
49  public class DocumentRefreshQueueImpl implements DocumentRefreshQueue {
50  	
51  	private RouteHelper helper = new RouteHelper();
52      
53  	/**
54  	 * Requeues a document, and sets notification suppression data
55  	 * 
56  	 * @see org.kuali.rice.kew.api.document.DocumentRefreshQueue#refreshDocument(java.lang.String)
57  	 */
58  	@Override
59  	public void refreshDocument(String documentId) {
60  		if (StringUtils.isBlank(documentId)) {
61              throw new RiceIllegalArgumentException("documentId is null or blank");
62          }
63  
64          PerformanceLogger performanceLogger = new PerformanceLogger();
65          KEWServiceLocator.getRouteHeaderService().lockRouteHeader(documentId);
66          Collection<RouteNodeInstance> activeNodes = getRouteNodeService().getActiveNodeInstances(documentId);
67          List<ActionRequestValue> requestsToDelete = new ArrayList<ActionRequestValue>();
68          
69  		NotificationSuppression notificationSuppression = new NotificationSuppression();
70  		
71          for (RouteNodeInstance nodeInstance : activeNodes) {
72              // only "requeue" if we're dealing with a request activation node
73              if (helper.isRequestActivationNode(nodeInstance.getRouteNode())) {
74              	List<ActionRequestValue> deletesForThisNode = 
75              		getActionRequestService().findPendingRootRequestsByDocIdAtRouteNode(documentId, nodeInstance.getRouteNodeInstanceId());
76  
77              	for (ActionRequestValue deleteForThisNode : deletesForThisNode) {
78                      // check either the request or its first present child request to see if it is system generated
79                      boolean containsRoleOrRuleRequests = deleteForThisNode.isRouteModuleRequest();
80                      if (!containsRoleOrRuleRequests) {
81                          if (CollectionUtils.isNotEmpty(deleteForThisNode.getChildrenRequests())) {
82                              containsRoleOrRuleRequests = deleteForThisNode.getChildrenRequests().get(0).isRouteModuleRequest();
83                          }
84                      }
85  
86                      if (containsRoleOrRuleRequests) {
87                          // remove all route or rule system generated requests
88                          requestsToDelete.add(deleteForThisNode);
89  
90                          // suppress duplicate notifications
91              			notificationSuppression.addNotificationSuppression(nodeInstance, deleteForThisNode);
92              		}
93              	}
94  
95                  // this will trigger a regeneration of requests
96                  nodeInstance.setInitial(true);
97                  getRouteNodeService().save(nodeInstance);
98              }
99          }
100         for (ActionRequestValue requestToDelete : requestsToDelete) {
101             getActionRequestService().deleteActionRequestGraphNoOutbox(requestToDelete);
102         }
103         try {
104             OrchestrationConfig config = new OrchestrationConfig(EngineCapability.STANDARD);
105         	KEWServiceLocator.getWorkflowEngineFactory().newEngine(config).process(documentId, null);
106         } catch (Exception e) {
107         	throw new WorkflowRuntimeException(e);
108         }
109         performanceLogger.log("Time to run DocumentRequeuer for document " + documentId);	
110 	}
111 
112     private ActionRequestService getActionRequestService() {
113         return KEWServiceLocator.getActionRequestService();
114     }
115     
116     private RouteNodeService getRouteNodeService() {
117         return KEWServiceLocator.getRouteNodeService();
118     }
119 }