001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.builder;
018    
019    import java.util.concurrent.ScheduledExecutorService;
020    
021    import org.apache.camel.CamelContext;
022    import org.apache.camel.Endpoint;
023    import org.apache.camel.Expression;
024    import org.apache.camel.LoggingLevel;
025    import org.apache.camel.Predicate;
026    import org.apache.camel.Processor;
027    import org.apache.camel.processor.DefaultErrorHandler;
028    import org.apache.camel.processor.RedeliveryPolicy;
029    import org.apache.camel.spi.ExecutorServiceManager;
030    import org.apache.camel.spi.Language;
031    import org.apache.camel.spi.RouteContext;
032    import org.apache.camel.spi.ThreadPoolProfile;
033    import org.apache.camel.util.CamelLogger;
034    import org.apache.camel.util.ExpressionToPredicateAdapter;
035    import org.slf4j.LoggerFactory;
036    
037    /**
038     * The default error handler builder.
039     *
040     * @version 
041     */
042    public class DefaultErrorHandlerBuilder extends ErrorHandlerBuilderSupport {
043    
044        protected CamelLogger logger;
045        protected RedeliveryPolicy redeliveryPolicy;
046        protected Processor onRedelivery;
047        protected Predicate retryWhile;
048        protected String retryWhileRef;
049        protected Processor failureProcessor;
050        protected Endpoint deadLetter;
051        protected String deadLetterUri;
052        protected boolean useOriginalMessage;
053        protected boolean asyncDelayedRedelivery;
054        protected String executorServiceRef;
055        protected ScheduledExecutorService executorService;
056    
057        public DefaultErrorHandlerBuilder() {
058        }
059    
060        public Processor createErrorHandler(RouteContext routeContext, Processor processor) throws Exception {
061            DefaultErrorHandler answer = new DefaultErrorHandler(routeContext.getCamelContext(), processor, getLogger(), getOnRedelivery(), 
062                getRedeliveryPolicy(), getExceptionPolicyStrategy(), getRetryWhilePolicy(routeContext.getCamelContext()), getExecutorService(routeContext.getCamelContext()));
063            // configure error handler before we can use it
064            configure(routeContext, answer);
065            return answer;
066        }
067    
068        public boolean supportTransacted() {
069            return false;
070        }
071    
072        // Builder methods
073        // -------------------------------------------------------------------------
074        public DefaultErrorHandlerBuilder backOffMultiplier(double backOffMultiplier) {
075            getRedeliveryPolicy().backOffMultiplier(backOffMultiplier);
076            return this;
077        }
078    
079        public DefaultErrorHandlerBuilder collisionAvoidancePercent(double collisionAvoidancePercent) {
080            getRedeliveryPolicy().collisionAvoidancePercent(collisionAvoidancePercent);
081            return this;
082        }
083    
084        /**
085         * @deprecated will be removed in the near future. Use {@link #redeliveryDelay(long)} instead
086         */
087        @Deprecated
088        public DefaultErrorHandlerBuilder redeliverDelay(long delay) {
089            getRedeliveryPolicy().redeliveryDelay(delay);
090            return this;
091        }
092    
093        public DefaultErrorHandlerBuilder redeliveryDelay(long delay) {
094            getRedeliveryPolicy().redeliveryDelay(delay);
095            return this;
096        }
097    
098        public DefaultErrorHandlerBuilder delayPattern(String delayPattern) {
099            getRedeliveryPolicy().delayPattern(delayPattern);
100            return this;
101        }
102    
103        public DefaultErrorHandlerBuilder maximumRedeliveries(int maximumRedeliveries) {
104            getRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries);
105            return this;
106        }
107    
108        public DefaultErrorHandlerBuilder disableRedelivery() {
109            getRedeliveryPolicy().maximumRedeliveries(0);
110            return this;
111        }
112    
113        public DefaultErrorHandlerBuilder maximumRedeliveryDelay(long maximumRedeliveryDelay) {
114            getRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay);
115            return this;
116        }
117    
118        public DefaultErrorHandlerBuilder useCollisionAvoidance() {
119            getRedeliveryPolicy().useCollisionAvoidance();
120            return this;
121        }
122    
123        public DefaultErrorHandlerBuilder useExponentialBackOff() {
124            getRedeliveryPolicy().useExponentialBackOff();
125            return this;
126        }
127    
128        public DefaultErrorHandlerBuilder retriesExhaustedLogLevel(LoggingLevel retriesExhaustedLogLevel) {
129            getRedeliveryPolicy().setRetriesExhaustedLogLevel(retriesExhaustedLogLevel);
130            return this;
131        }
132    
133        public DefaultErrorHandlerBuilder retryAttemptedLogLevel(LoggingLevel retryAttemptedLogLevel) {
134            getRedeliveryPolicy().setRetryAttemptedLogLevel(retryAttemptedLogLevel);
135            return this;
136        }
137    
138        public DefaultErrorHandlerBuilder logStackTrace(boolean logStackTrace) {
139            getRedeliveryPolicy().setLogStackTrace(logStackTrace);
140            return this;
141        }
142    
143        public DefaultErrorHandlerBuilder logRetryStackTrace(boolean logRetryStackTrace) {
144            getRedeliveryPolicy().setLogRetryStackTrace(logRetryStackTrace);
145            return this;
146        }
147    
148        public DefaultErrorHandlerBuilder logHandled(boolean logHandled) {
149            getRedeliveryPolicy().setLogHandled(logHandled);
150            return this;
151        }
152    
153        public DefaultErrorHandlerBuilder logExhausted(boolean logExhausted) {
154            getRedeliveryPolicy().setLogExhausted(logExhausted);
155            return this;
156        }
157    
158        /**
159         * Will allow asynchronous delayed redeliveries.
160         *
161         * @see org.apache.camel.processor.RedeliveryPolicy#setAsyncDelayedRedelivery(boolean)
162         * @return the builder
163         */
164        public DefaultErrorHandlerBuilder asyncDelayedRedelivery() {
165            getRedeliveryPolicy().setAsyncDelayedRedelivery(true);
166            return this;
167        }
168    
169        /**
170         * Sets a reference to a thread pool to be used for redelivery.
171         *
172         * @param ref reference to a scheduled thread pool
173         * @return the builder.
174         */
175        public DefaultErrorHandlerBuilder executorServiceRef(String ref) {
176            setExecutorServiceRef(ref);
177            return this;
178        }
179    
180        /**
181         * Sets the logger used for caught exceptions
182         *
183         * @param logger the logger
184         * @return the builder
185         */
186        public DefaultErrorHandlerBuilder logger(CamelLogger logger) {
187            setLogger(logger);
188            return this;
189        }
190    
191        /**
192         * Sets the logging level of exceptions caught
193         *
194         * @param level the logging level
195         * @return the builder
196         */
197        public DefaultErrorHandlerBuilder loggingLevel(LoggingLevel level) {
198            getLogger().setLevel(level);
199            return this;
200        }
201    
202        /**
203         * Sets the log used for caught exceptions
204         *
205         * @param log the logger
206         * @return the builder
207         */
208        public DefaultErrorHandlerBuilder log(org.slf4j.Logger log) {
209            getLogger().setLog(log);
210            return this;
211        }
212    
213        /**
214         * Sets the log used for caught exceptions
215         *
216         * @param log the log name
217         * @return the builder
218         */
219        public DefaultErrorHandlerBuilder log(String log) {
220            return log(LoggerFactory.getLogger(log));
221        }
222    
223        /**
224         * Sets the log used for caught exceptions
225         *
226         * @param log the log class
227         * @return the builder
228         */
229        public DefaultErrorHandlerBuilder log(Class<?> log) {
230            return log(LoggerFactory.getLogger(log));
231        }
232    
233        /**
234         * Sets a processor that should be processed <b>before</b> a redelivery attempt.
235         * <p/>
236         * Can be used to change the {@link org.apache.camel.Exchange} <b>before</b> its being redelivered.
237         *
238         * @param processor the processor
239         * @return the builder
240         */
241        public DefaultErrorHandlerBuilder onRedelivery(Processor processor) {
242            setOnRedelivery(processor);
243            return this;
244        }
245    
246        /**
247         * Sets the retry while expression.
248         * <p/>
249         * Will continue retrying until expression evaluates to <tt>false</tt>.
250         *
251         * @param retryWhile expression that determines when to stop retrying
252         * @return the builder
253         */
254        public DefaultErrorHandlerBuilder retryWhile(Expression retryWhile) {
255            setRetryWhile(ExpressionToPredicateAdapter.toPredicate(retryWhile));
256            return this;
257        }
258    
259        /**
260         * Will use the original input {@link org.apache.camel.Message} when an {@link org.apache.camel.Exchange}
261         * is moved to the dead letter queue.
262         * <p/>
263         * <b>Notice:</b> this only applies when all redeliveries attempt have failed and the {@link org.apache.camel.Exchange}
264         * is doomed for failure.
265         * <br/>
266         * Instead of using the current inprogress {@link org.apache.camel.Exchange} IN message we use the original
267         * IN message instead. This allows you to store the original input in the dead letter queue instead of the inprogress
268         * snapshot of the IN message.
269         * For instance if you route transform the IN body during routing and then failed. With the original exchange
270         * store in the dead letter queue it might be easier to manually re submit the {@link org.apache.camel.Exchange}
271         * again as the IN message is the same as when Camel received it.
272         * So you should be able to send the {@link org.apache.camel.Exchange} to the same input.
273         * <p/>
274         * By default this feature is off.
275         *
276         * @return the builder
277         */
278        public DefaultErrorHandlerBuilder useOriginalMessage() {
279            setUseOriginalMessage(true);
280            return this;
281        }
282    
283        // Properties
284        // -------------------------------------------------------------------------
285    
286        public Processor getFailureProcessor() {
287            return failureProcessor;
288        }
289    
290        public void setFailureProcessor(Processor failureProcessor) {
291            this.failureProcessor = failureProcessor;
292        }
293    
294        public RedeliveryPolicy getRedeliveryPolicy() {
295            if (redeliveryPolicy == null) {
296                redeliveryPolicy = createRedeliveryPolicy();
297            }
298            return redeliveryPolicy;
299        }
300    
301        /**
302         * Sets the redelivery policy
303         */
304        public void setRedeliveryPolicy(RedeliveryPolicy redeliveryPolicy) {
305            this.redeliveryPolicy = redeliveryPolicy;
306        }
307    
308        public CamelLogger getLogger() {
309            if (logger == null) {
310                logger = createLogger();
311            }
312            return logger;
313        }
314    
315        public void setLogger(CamelLogger logger) {
316            this.logger = logger;
317        }
318    
319        public Processor getOnRedelivery() {
320            return onRedelivery;
321        }
322    
323        public void setOnRedelivery(Processor onRedelivery) {
324            this.onRedelivery = onRedelivery;
325        }
326    
327        public Predicate getRetryWhilePolicy(CamelContext context) {
328            Predicate answer = getRetryWhile();
329    
330            if (getRetryWhileRef() != null) {
331                // its a bean expression
332                Language bean = context.resolveLanguage("bean");
333                answer = bean.createPredicate(getRetryWhileRef());
334            }
335    
336            return answer;
337        }
338    
339        public Predicate getRetryWhile() {
340            return retryWhile;
341        }
342    
343        public void setRetryWhile(Predicate retryWhile) {
344            this.retryWhile = retryWhile;
345        }
346    
347        public String getRetryWhileRef() {
348            return retryWhileRef;
349        }
350    
351        public void setRetryWhileRef(String retryWhileRef) {
352            this.retryWhileRef = retryWhileRef;
353        }
354    
355        public String getDeadLetterUri() {
356            return deadLetterUri;
357        }
358    
359        public void setDeadLetterUri(String deadLetterUri) {
360            this.deadLetter = null;
361            this.deadLetterUri = deadLetterUri;
362        }
363    
364        public Endpoint getDeadLetter() {
365            return deadLetter;
366        }
367    
368        public void setDeadLetter(Endpoint deadLetter) {
369            this.deadLetter = deadLetter;
370            this.deadLetterUri = deadLetter.getEndpointUri();
371        }
372    
373        public boolean isUseOriginalMessage() {
374            return useOriginalMessage;
375        }
376    
377        public void setUseOriginalMessage(boolean useOriginalMessage) {
378            this.useOriginalMessage = useOriginalMessage;
379        }
380    
381        public boolean isAsyncDelayedRedelivery() {
382            return asyncDelayedRedelivery;
383        }
384    
385        public void setAsyncDelayedRedelivery(boolean asyncDelayedRedelivery) {
386            this.asyncDelayedRedelivery = asyncDelayedRedelivery;
387        }
388    
389        public String getExecutorServiceRef() {
390            return executorServiceRef;
391        }
392    
393        public void setExecutorServiceRef(String executorServiceRef) {
394            this.executorServiceRef = executorServiceRef;
395        }
396    
397        protected RedeliveryPolicy createRedeliveryPolicy() {
398            RedeliveryPolicy policy = new RedeliveryPolicy();
399            policy.disableRedelivery();
400            policy.setRedeliveryDelay(0);
401            return policy;
402        }
403    
404        protected CamelLogger createLogger() {
405            return new CamelLogger(LoggerFactory.getLogger(DefaultErrorHandler.class), LoggingLevel.ERROR);
406        }
407    
408        protected synchronized ScheduledExecutorService getExecutorService(CamelContext camelContext) {
409            if (executorService == null || executorService.isShutdown()) {
410                // camel context will shutdown the executor when it shutdown so no need to shut it down when stopping
411                if (executorServiceRef != null) {
412                    executorService = camelContext.getRegistry().lookup(executorServiceRef, ScheduledExecutorService.class);
413                    if (executorService == null) {
414                        ExecutorServiceManager manager = camelContext.getExecutorServiceManager();
415                        ThreadPoolProfile profile = manager.getThreadPoolProfile(executorServiceRef);
416                        executorService = manager.newScheduledThreadPool(this, executorServiceRef, profile);
417                    }
418                    if (executorService == null) {
419                        throw new IllegalArgumentException("ExecutorServiceRef " + executorServiceRef + " not found in registry.");
420                    }
421                } else {
422                    // use default shared thread pool for error handlers
423                    executorService = camelContext.getErrorHandlerExecutorService();
424                }
425            }
426            return executorService;
427        }
428    
429        @Override
430        public String toString() {
431            return "DefaultErrorHandlerBuilder";
432        }
433    
434    }