001/**
002 * Copyright 2005-2016 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 */
016package org.kuali.rice.kew.impl.document;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.List;
021
022import org.apache.commons.lang.StringUtils;
023import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
024import org.kuali.rice.kew.actionrequest.ActionRequestValue;
025import org.kuali.rice.kew.actionrequest.service.ActionRequestService;
026import org.kuali.rice.kew.actionrequest.service.impl.NotificationSuppression;
027import org.kuali.rice.kew.api.document.DocumentRefreshQueue;
028import org.kuali.rice.kew.api.WorkflowRuntimeException;
029import org.kuali.rice.kew.engine.OrchestrationConfig;
030import org.kuali.rice.kew.engine.OrchestrationConfig.EngineCapability;
031import org.kuali.rice.kew.engine.RouteHelper;
032import org.kuali.rice.kew.engine.node.RouteNodeInstance;
033import org.kuali.rice.kew.engine.node.service.RouteNodeService;
034import org.kuali.rice.kew.service.KEWServiceLocator;
035import 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 */
048public 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}