001 /**
002 * Copyright 2005-2013 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.kew.impl.document;
017
018 import java.util.ArrayList;
019 import java.util.Collection;
020 import java.util.List;
021
022 import org.apache.commons.lang.StringUtils;
023 import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
024 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
025 import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
026 import org.kuali.rice.kew.actionrequest.service.impl.NotificationSuppression;
027 import org.kuali.rice.kew.api.document.DocumentRefreshQueue;
028 import org.kuali.rice.kew.api.WorkflowRuntimeException;
029 import org.kuali.rice.kew.engine.OrchestrationConfig;
030 import org.kuali.rice.kew.engine.OrchestrationConfig.EngineCapability;
031 import org.kuali.rice.kew.engine.RouteHelper;
032 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
033 import org.kuali.rice.kew.engine.node.service.RouteNodeService;
034 import org.kuali.rice.kew.service.KEWServiceLocator;
035 import org.kuali.rice.kew.util.PerformanceLogger;
036
037
038 /**
039 * A service which effectively "refreshes" and requeues a document. It first deletes any
040 * pending action requests on the documents and then requeues the document for standard routing.
041 * Addionally, it adds duplicate notification suppression state to RouteNodeInstanceS for
042 * which ActionRequestS will be regenerated.
043 *
044 * <p>Intended to be called async and wired that way in server/client spring beans.</p>
045 *
046 * @author Kuali Rice Team (rice.collab@kuali.org)
047 */
048 public class DocumentRefreshQueueImpl implements DocumentRefreshQueue {
049
050 private RouteHelper helper = new RouteHelper();
051
052 /**
053 * Requeues a document, and sets notification suppression data
054 *
055 * @see org.kuali.rice.kew.api.document.DocumentRefreshQueue#refreshDocument(java.lang.String)
056 */
057 @Override
058 public void refreshDocument(String documentId) {
059 if (StringUtils.isBlank(documentId)) {
060 throw new RiceIllegalArgumentException("documentId is null or blank");
061 }
062
063 PerformanceLogger performanceLogger = new PerformanceLogger();
064 KEWServiceLocator.getRouteHeaderService().lockRouteHeader(documentId, true);
065 Collection<RouteNodeInstance> activeNodes = getRouteNodeService().getActiveNodeInstances(documentId);
066 List<ActionRequestValue> requestsToDelete = new ArrayList<ActionRequestValue>();
067
068 NotificationSuppression notificationSuppression = new NotificationSuppression();
069
070 for (RouteNodeInstance nodeInstance : activeNodes) {
071 // only "requeue" if we're dealing with a request activation node
072 if (helper.isRequestActivationNode(nodeInstance.getRouteNode())) {
073 List<ActionRequestValue> deletesForThisNode =
074 getActionRequestService().findPendingRootRequestsByDocIdAtRouteNode(documentId, nodeInstance.getRouteNodeInstanceId());
075
076 for (ActionRequestValue deleteForThisNode : deletesForThisNode) {
077 // only delete the request if it was generated by a route module (or the rules system)
078 if (deleteForThisNode.isRouteModuleRequest()) {
079 requestsToDelete.add(deleteForThisNode);
080
081 // suppress duplicate notifications
082 notificationSuppression.addNotificationSuppression(nodeInstance, deleteForThisNode);
083 }
084 }
085 // this will trigger a regeneration of requests
086 nodeInstance.setInitial(true);
087 getRouteNodeService().save(nodeInstance);
088 }
089 }
090 for (ActionRequestValue requestToDelete : requestsToDelete) {
091 getActionRequestService().deleteActionRequestGraph(requestToDelete);
092 }
093 try {
094 OrchestrationConfig config = new OrchestrationConfig(EngineCapability.STANDARD);
095 KEWServiceLocator.getWorkflowEngineFactory().newEngine(config).process(documentId, null);
096 } catch (Exception e) {
097 throw new WorkflowRuntimeException(e);
098 }
099 performanceLogger.log("Time to run DocumentRequeuer for document " + documentId);
100 }
101
102 private ActionRequestService getActionRequestService() {
103 return KEWServiceLocator.getActionRequestService();
104 }
105
106 private RouteNodeService getRouteNodeService() {
107 return KEWServiceLocator.getRouteNodeService();
108 }
109 }