001/*
002 * Copyright 2006-2007 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.batch.repeat.exception;
018
019import java.util.Collection;
020import java.util.Collections;
021import java.util.HashMap;
022import java.util.Map;
023
024import org.springframework.batch.repeat.RepeatContext;
025import org.springframework.beans.factory.InitializingBean;
026
027/**
028 * Simple implementation of exception handler which looks for given exception
029 * types. If one of the types is found then a counter is incremented and the
030 * limit is checked to determine if it has been exceeded and the Throwable
031 * should be re-thrown. Also allows to specify list of 'fatal' exceptions that
032 * are never subject to counting, but are immediately re-thrown. The fatal list
033 * has higher priority so the two lists needn't be exclusive.
034 * 
035 * @author Dave Syer
036 * @author Robert Kasanicky
037 */
038public class SimpleLimitExceptionHandler implements ExceptionHandler, InitializingBean {
039
040        private RethrowOnThresholdExceptionHandler delegate = new RethrowOnThresholdExceptionHandler();
041
042        private Collection<Class<? extends Throwable>> exceptionClasses = Collections
043                        .<Class<? extends Throwable>> singleton(Exception.class);
044
045        private Collection<Class<? extends Throwable>> fatalExceptionClasses = Collections
046                        .<Class<? extends Throwable>> singleton(Error.class);
047
048        private int limit = 0;
049
050        /**
051         * Apply the provided properties to create a delegate handler.
052         * 
053         * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
054         */
055    @Override
056        public void afterPropertiesSet() throws Exception {
057                if (limit <= 0) {
058                        return;
059                }
060                Map<Class<? extends Throwable>, Integer> thresholds = new HashMap<Class<? extends Throwable>, Integer>();
061                for (Class<? extends Throwable> type : exceptionClasses) {
062                        thresholds.put(type, limit);
063                }
064                // do the fatalExceptionClasses last so they override the others
065                for (Class<? extends Throwable> type : fatalExceptionClasses) {
066                        thresholds.put(type, 0);
067                }
068                delegate.setThresholds(thresholds);
069        }
070
071        /**
072         * Flag to indicate the the exception counters should be shared between
073         * sibling contexts in a nested batch (i.e. inner loop). Default is false.
074         * Set this flag to true if you want to count exceptions for the whole
075         * (outer) loop in a typical container.
076         * 
077         * @param useParent true if the parent context should be used to store the
078         * counters.
079         */
080        public void setUseParent(boolean useParent) {
081                delegate.setUseParent(useParent);
082        }
083
084        /**
085         * Convenience constructor for the {@link SimpleLimitExceptionHandler} to
086         * set the limit.
087         * 
088         * @param limit the limit
089         */
090        public SimpleLimitExceptionHandler(int limit) {
091                this();
092                this.limit = limit;
093        }
094
095        /**
096         * Default constructor for the {@link SimpleLimitExceptionHandler}.
097         */
098        public SimpleLimitExceptionHandler() {
099                super();
100        }
101
102        /**
103         * Rethrows only if the limit is breached for this context on the exception
104         * type specified.
105         * 
106         * @see #setExceptionClasses(Collection)
107         * @see #setLimit(int)
108         * 
109         * @see org.springframework.batch.repeat.exception.ExceptionHandler#handleException(org.springframework.batch.repeat.RepeatContext,
110         * Throwable)
111         */
112    @Override
113        public void handleException(RepeatContext context, Throwable throwable) throws Throwable {
114                delegate.handleException(context, throwable);
115        }
116
117        /**
118         * The limit on the given exception type within a single context before it
119         * is rethrown.
120         * 
121         * @param limit the limit
122         */
123        public void setLimit(final int limit) {
124                this.limit = limit;
125        }
126
127        /**
128         * Setter for the exception classes that this handler counts. Defaults to
129         * {@link Exception}. If more exceptionClasses are specified handler uses
130         * single counter that is incremented when one of the recognized exception
131         * exceptionClasses is handled.
132         * @param classes exceptionClasses
133         */
134        public void setExceptionClasses(Collection<Class<? extends Throwable>> classes) {
135                this.exceptionClasses = classes;
136        }
137
138        /**
139         * Setter for the exception classes that shouldn't be counted, but rethrown
140         * immediately. This list has higher priority than
141         * {@link #setExceptionClasses(Collection)}.
142         * 
143         * @param fatalExceptionClasses defaults to {@link Error}
144         */
145        public void setFatalExceptionClasses(Collection<Class<? extends Throwable>> fatalExceptionClasses) {
146                this.fatalExceptionClasses = fatalExceptionClasses;
147        }
148
149}