001/*
002 * Copyright 2002-2013 the original author or authors.
003 *
004 * Licensed under the Apache 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 *      https://www.apache.org/licenses/LICENSE-2.0
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
017package org.springframework.scheduling.support;
018
019import java.util.concurrent.Future;
020
021import org.apache.commons.logging.Log;
022import org.apache.commons.logging.LogFactory;
023
024import org.springframework.util.ErrorHandler;
025import org.springframework.util.ReflectionUtils;
026
027/**
028 * Utility methods for decorating tasks with error handling.
029 *
030 * <p><b>NOTE:</b> This class is intended for internal use by Spring's scheduler
031 * implementations. It is only public so that it may be accessed from impl classes
032 * within other packages. It is <i>not</i> intended for general use.
033 *
034 * @author Mark Fisher
035 * @author Juergen Hoeller
036 * @since 3.0
037 */
038public abstract class TaskUtils {
039
040        /**
041         * An ErrorHandler strategy that will log the Exception but perform
042         * no further handling. This will suppress the error so that
043         * subsequent executions of the task will not be prevented.
044         */
045        public static final ErrorHandler LOG_AND_SUPPRESS_ERROR_HANDLER = new LoggingErrorHandler();
046
047        /**
048         * An ErrorHandler strategy that will log at error level and then
049         * re-throw the Exception. Note: this will typically prevent subsequent
050         * execution of a scheduled task.
051         */
052        public static final ErrorHandler LOG_AND_PROPAGATE_ERROR_HANDLER = new PropagatingErrorHandler();
053
054
055        /**
056         * Decorate the task for error handling. If the provided {@link ErrorHandler}
057         * is not {@code null}, it will be used. Otherwise, repeating tasks will have
058         * errors suppressed by default whereas one-shot tasks will have errors
059         * propagated by default since those errors may be expected through the
060         * returned {@link Future}. In both cases, the errors will be logged.
061         */
062        public static DelegatingErrorHandlingRunnable decorateTaskWithErrorHandler(
063                        Runnable task, ErrorHandler errorHandler, boolean isRepeatingTask) {
064
065                if (task instanceof DelegatingErrorHandlingRunnable) {
066                        return (DelegatingErrorHandlingRunnable) task;
067                }
068                ErrorHandler eh = (errorHandler != null ? errorHandler : getDefaultErrorHandler(isRepeatingTask));
069                return new DelegatingErrorHandlingRunnable(task, eh);
070        }
071
072        /**
073         * Return the default {@link ErrorHandler} implementation based on the boolean
074         * value indicating whether the task will be repeating or not. For repeating tasks
075         * it will suppress errors, but for one-time tasks it will propagate. In both
076         * cases, the error will be logged.
077         */
078        public static ErrorHandler getDefaultErrorHandler(boolean isRepeatingTask) {
079                return (isRepeatingTask ? LOG_AND_SUPPRESS_ERROR_HANDLER : LOG_AND_PROPAGATE_ERROR_HANDLER);
080        }
081
082
083        /**
084         * An {@link ErrorHandler} implementation that logs the Throwable at error
085         * level. It does not perform any additional error handling. This can be
086         * useful when suppression of errors is the intended behavior.
087         */
088        private static class LoggingErrorHandler implements ErrorHandler {
089
090                private final Log logger = LogFactory.getLog(LoggingErrorHandler.class);
091
092                @Override
093                public void handleError(Throwable t) {
094                        if (logger.isErrorEnabled()) {
095                                logger.error("Unexpected error occurred in scheduled task.", t);
096                        }
097                }
098        }
099
100
101        /**
102         * An {@link ErrorHandler} implementation that logs the Throwable at error
103         * level and then propagates it.
104         */
105        private static class PropagatingErrorHandler extends LoggingErrorHandler {
106
107                @Override
108                public void handleError(Throwable t) {
109                        super.handleError(t);
110                        ReflectionUtils.rethrowRuntimeException(t);
111                }
112        }
113
114}