001/**
002 * Copyright 2005-2017 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.stuck;
017
018import org.kuali.rice.core.api.config.property.RuntimeConfig;
019import org.slf4j.Logger;
020import org.slf4j.LoggerFactory;
021import org.springframework.beans.factory.annotation.Required;
022
023import java.sql.Timestamp;
024import java.util.ArrayList;
025import java.util.Collections;
026import java.util.List;
027import java.util.stream.Collectors;
028
029import static com.google.common.base.Preconditions.checkNotNull;
030
031/**
032 * @author Eric Westfall
033 */
034public class StuckDocumentServiceImpl implements StuckDocumentService {
035
036    private StuckDocumentDao stuckDocumentDao;
037    private StuckDocumentNotifier notifier;
038    private RuntimeConfig failureNotificationEnabled;
039
040    @Override
041    public List<String> findAllStuckDocumentIds() {
042        return getStuckDocumentDao().findAllStuckDocumentIds();
043    }
044
045    @Override
046    public List<StuckDocument> findAllStuckDocuments() {
047        return getStuckDocumentDao().findAllStuckDocuments();
048    }
049
050    @Override
051    public StuckDocumentIncident findIncident(String stuckDocumentIncidentId) {
052        checkNotNull(stuckDocumentIncidentId);
053        return getStuckDocumentDao().findIncident(stuckDocumentIncidentId);
054    }
055
056    @Override
057    public List<StuckDocumentIncident> findIncidents(List<String> stuckDocumentIncidentIds) {
058        checkNotNull(stuckDocumentIncidentIds);
059        List<StuckDocumentIncident> incidents = new ArrayList<>(stuckDocumentIncidentIds.size());
060        for (String stuckDocumentIncidentId : stuckDocumentIncidentIds) {
061            StuckDocumentIncident incident = findIncident(stuckDocumentIncidentId);
062            if (incident != null) {
063                incidents.add(incident);
064            }
065        }
066        return incidents;
067    }
068
069    @Override
070    public List<StuckDocumentIncident> findAllIncidents(int maxIncidents) {
071        return getStuckDocumentDao().findAllIncidents(maxIncidents);
072    }
073
074    @Override
075    public List<StuckDocumentIncident> findIncidentsByStatus(int maxIncidents, StuckDocumentIncident.Status status) {
076        return getStuckDocumentDao().findIncidentsByStatus(maxIncidents, status);
077    }
078
079    @Override
080    public List<StuckDocumentIncident> recordNewStuckDocumentIncidents() {
081        List<String> newStuckDocuments = getStuckDocumentDao().identifyNewStuckDocuments();
082        return newStuckDocuments.stream().map(documentId -> getStuckDocumentDao().saveIncident(StuckDocumentIncident.startNewIncident(documentId))).collect(Collectors.toList());
083    }
084
085    @Override
086    public StuckDocumentFixAttempt recordNewIncidentFixAttempt(StuckDocumentIncident stuckDocumentIncident) {
087        checkNotNull(stuckDocumentIncident);
088        StuckDocumentFixAttempt auditEntry = new StuckDocumentFixAttempt();
089        auditEntry.setStuckDocumentIncidentId(stuckDocumentIncident.getStuckDocumentIncidentId());
090        auditEntry.setTimestamp(new Timestamp(System.currentTimeMillis()));
091        return getStuckDocumentDao().saveFixAttempt(auditEntry);
092    }
093
094    @Override
095    public List<StuckDocumentFixAttempt> findAllFixAttempts(String stuckDocumentIncidentId) {
096        return getStuckDocumentDao().findAllFixAttempts(stuckDocumentIncidentId);
097    }
098
099    @Override
100    public List<StuckDocumentIncident> resolveIncidentsIfPossible(List<String> stuckDocumentIncidentIds) {
101        checkNotNull(stuckDocumentIncidentIds);
102        List<StuckDocumentIncident> stuckIncidents = getStuckDocumentDao().identifyStillStuckDocuments(stuckDocumentIncidentIds);
103        List<String> stuckIncidentIds = stuckIncidents.stream().map(StuckDocumentIncident::getStuckDocumentIncidentId).collect(Collectors.toList());
104        // let's find the ones that aren't stuck so that we can resolve them
105        List<String> notStuckIncidentIds = new ArrayList<>(stuckDocumentIncidentIds);
106        notStuckIncidentIds.removeAll(stuckIncidentIds);
107        if (!notStuckIncidentIds.isEmpty()) {
108            List<StuckDocumentIncident> notStuckIncidents = findIncidents(notStuckIncidentIds);
109            notStuckIncidents.forEach(this::resolve);
110        }
111        return stuckIncidents;
112    }
113
114    protected StuckDocumentIncident resolve(StuckDocumentIncident stuckDocumentIncident) {
115        checkNotNull(stuckDocumentIncident);
116        if (stuckDocumentIncident.getStatus().equals(StuckDocumentIncident.Status.PENDING)) {
117            // if it was pending that means we just went through the quiet period and the document unstuck itself,
118            // let's get rid of it's incident since it's just noise
119            getStuckDocumentDao().deleteIncident(stuckDocumentIncident);
120            return stuckDocumentIncident;
121        } else {
122            stuckDocumentIncident.setStatus(StuckDocumentIncident.Status.FIXED);
123            stuckDocumentIncident.setEndDate(new Timestamp(System.currentTimeMillis()));
124            return getStuckDocumentDao().saveIncident(stuckDocumentIncident);
125        }
126    }
127
128    @Override
129    public StuckDocumentIncident startFixingIncident(StuckDocumentIncident stuckDocumentIncident) {
130        checkNotNull(stuckDocumentIncident);
131        stuckDocumentIncident.setStatus(StuckDocumentIncident.Status.FIXING);
132        return getStuckDocumentDao().saveIncident(stuckDocumentIncident);
133    }
134
135    @Override
136    public StuckDocumentIncident recordIncidentFailure(StuckDocumentIncident stuckDocumentIncident) {
137        checkNotNull(stuckDocumentIncident);
138        stuckDocumentIncident.setStatus(StuckDocumentIncident.Status.FAILED);
139        stuckDocumentIncident.setEndDate(new Timestamp(System.currentTimeMillis()));
140        stuckDocumentIncident = getStuckDocumentDao().saveIncident(stuckDocumentIncident);
141        notifyIncidentFailure(stuckDocumentIncident);
142        return stuckDocumentIncident;
143    }
144
145    protected void notifyIncidentFailure(StuckDocumentIncident stuckDocumentIncident) {
146        if (getFailureNotificationEnabled().getValueAsBoolean()) {
147            List<StuckDocumentFixAttempt> attempts = getStuckDocumentDao().findAllFixAttempts(stuckDocumentIncident.getStuckDocumentIncidentId());
148            notifier.notifyIncidentFailure(stuckDocumentIncident, attempts);
149        }
150    }
151
152    protected StuckDocumentDao getStuckDocumentDao() {
153        return stuckDocumentDao;
154    }
155
156    @Required
157    public void setStuckDocumentDao(StuckDocumentDao stuckDocumentDao) {
158        this.stuckDocumentDao = stuckDocumentDao;
159    }
160
161    protected StuckDocumentNotifier getNotifier() {
162        return notifier;
163    }
164
165    @Required
166    public void setNotifier(StuckDocumentNotifier notifier) {
167        this.notifier = notifier;
168    }
169
170    protected RuntimeConfig getFailureNotificationEnabled() {
171        return failureNotificationEnabled;
172    }
173
174    @Required
175    public void setFailureNotificationEnabled(RuntimeConfig failureNotificationEnabled) {
176        this.failureNotificationEnabled = failureNotificationEnabled;
177    }
178}