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        @Override
073        public ErrorHandlerBuilder cloneBuilder() {
074            DefaultErrorHandlerBuilder answer = new DefaultErrorHandlerBuilder();
075            cloneBuilder(answer);
076            return answer;
077        }
078    
079        protected void cloneBuilder(DefaultErrorHandlerBuilder other) {
080            super.cloneBuilder(other);
081    
082            if (logger != null) {
083                other.setLogger(logger);
084            }
085            if (redeliveryPolicy != null) {
086                other.setRedeliveryPolicy(redeliveryPolicy.copy());
087            }
088            if (onRedelivery != null) {
089                other.setOnRedelivery(onRedelivery);
090            }
091            if (retryWhile != null) {
092                other.setRetryWhile(retryWhile);
093            }
094            if (retryWhileRef != null) {
095                other.setRetryWhileRef(retryWhileRef);
096            }
097            if (failureProcessor != null) {
098                other.setFailureProcessor(failureProcessor);
099            }
100            if (deadLetter != null) {
101                other.setDeadLetter(deadLetter);
102            }
103            if (deadLetterUri != null) {
104                other.setDeadLetterUri(deadLetterUri);
105            }
106            other.setUseOriginalMessage(useOriginalMessage);
107            other.setAsyncDelayedRedelivery(asyncDelayedRedelivery);
108            other.setExecutorServiceRef(executorServiceRef);
109        }
110    
111        // Builder methods
112        // -------------------------------------------------------------------------
113        public DefaultErrorHandlerBuilder backOffMultiplier(double backOffMultiplier) {
114            getRedeliveryPolicy().backOffMultiplier(backOffMultiplier);
115            return this;
116        }
117    
118        public DefaultErrorHandlerBuilder collisionAvoidancePercent(double collisionAvoidancePercent) {
119            getRedeliveryPolicy().collisionAvoidancePercent(collisionAvoidancePercent);
120            return this;
121        }
122    
123        /**
124         * @deprecated will be removed in the near future. Use {@link #redeliveryDelay(long)} instead
125         */
126        @Deprecated
127        public DefaultErrorHandlerBuilder redeliverDelay(long delay) {
128            getRedeliveryPolicy().redeliveryDelay(delay);
129            return this;
130        }
131    
132        public DefaultErrorHandlerBuilder redeliveryDelay(long delay) {
133            getRedeliveryPolicy().redeliveryDelay(delay);
134            return this;
135        }
136    
137        public DefaultErrorHandlerBuilder delayPattern(String delayPattern) {
138            getRedeliveryPolicy().delayPattern(delayPattern);
139            return this;
140        }
141    
142        public DefaultErrorHandlerBuilder maximumRedeliveries(int maximumRedeliveries) {
143            getRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries);
144            return this;
145        }
146    
147        public DefaultErrorHandlerBuilder disableRedelivery() {
148            getRedeliveryPolicy().maximumRedeliveries(0);
149            return this;
150        }
151    
152        public DefaultErrorHandlerBuilder maximumRedeliveryDelay(long maximumRedeliveryDelay) {
153            getRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay);
154            return this;
155        }
156    
157        public DefaultErrorHandlerBuilder useCollisionAvoidance() {
158            getRedeliveryPolicy().useCollisionAvoidance();
159            return this;
160        }
161    
162        public DefaultErrorHandlerBuilder useExponentialBackOff() {
163            getRedeliveryPolicy().useExponentialBackOff();
164            return this;
165        }
166    
167        public DefaultErrorHandlerBuilder retriesExhaustedLogLevel(LoggingLevel retriesExhaustedLogLevel) {
168            getRedeliveryPolicy().setRetriesExhaustedLogLevel(retriesExhaustedLogLevel);
169            return this;
170        }
171    
172        public DefaultErrorHandlerBuilder retryAttemptedLogLevel(LoggingLevel retryAttemptedLogLevel) {
173            getRedeliveryPolicy().setRetryAttemptedLogLevel(retryAttemptedLogLevel);
174            return this;
175        }
176    
177        public DefaultErrorHandlerBuilder logStackTrace(boolean logStackTrace) {
178            getRedeliveryPolicy().setLogStackTrace(logStackTrace);
179            return this;
180        }
181    
182        public DefaultErrorHandlerBuilder logRetryStackTrace(boolean logRetryStackTrace) {
183            getRedeliveryPolicy().setLogRetryStackTrace(logRetryStackTrace);
184            return this;
185        }
186    
187        public DefaultErrorHandlerBuilder logHandled(boolean logHandled) {
188            getRedeliveryPolicy().setLogHandled(logHandled);
189            return this;
190        }
191    
192        public DefaultErrorHandlerBuilder logExhausted(boolean logExhausted) {
193            getRedeliveryPolicy().setLogExhausted(logExhausted);
194            return this;
195        }
196    
197        public DefaultErrorHandlerBuilder logExhaustedMessageHistory(boolean logExhaustedMessageHistory) {
198            getRedeliveryPolicy().setLogExhaustedMessageHistory(logExhaustedMessageHistory);
199            return this;
200        }
201    
202        /**
203         * Will allow asynchronous delayed redeliveries.
204         *
205         * @see org.apache.camel.processor.RedeliveryPolicy#setAsyncDelayedRedelivery(boolean)
206         * @return the builder
207         */
208        public DefaultErrorHandlerBuilder asyncDelayedRedelivery() {
209            getRedeliveryPolicy().setAsyncDelayedRedelivery(true);
210            return this;
211        }
212    
213        /**
214         * Controls whether to allow redelivery while stopping/shutting down a route that uses error handling.
215         *
216         * @param allowRedeliveryWhileStopping <tt>true</tt> to allow redelivery, <tt>false</tt> to reject redeliveries
217         * @return the builder
218         */
219        public DefaultErrorHandlerBuilder allowRedeliveryWhileStopping(boolean allowRedeliveryWhileStopping) {
220            getRedeliveryPolicy().setAllowRedeliveryWhileStopping(allowRedeliveryWhileStopping);
221            return this;
222        }
223    
224        /**
225         * Sets a reference to a thread pool to be used for redelivery.
226         *
227         * @param ref reference to a scheduled thread pool
228         * @return the builder.
229         */
230        public DefaultErrorHandlerBuilder executorServiceRef(String ref) {
231            setExecutorServiceRef(ref);
232            return this;
233        }
234    
235        /**
236         * Sets the logger used for caught exceptions
237         *
238         * @param logger the logger
239         * @return the builder
240         */
241        public DefaultErrorHandlerBuilder logger(CamelLogger logger) {
242            setLogger(logger);
243            return this;
244        }
245    
246        /**
247         * Sets the logging level of exceptions caught
248         *
249         * @param level the logging level
250         * @return the builder
251         */
252        public DefaultErrorHandlerBuilder loggingLevel(LoggingLevel level) {
253            getLogger().setLevel(level);
254            return this;
255        }
256    
257        /**
258         * Sets the log used for caught exceptions
259         *
260         * @param log the logger
261         * @return the builder
262         */
263        public DefaultErrorHandlerBuilder log(org.slf4j.Logger log) {
264            getLogger().setLog(log);
265            return this;
266        }
267    
268        /**
269         * Sets the log used for caught exceptions
270         *
271         * @param log the log name
272         * @return the builder
273         */
274        public DefaultErrorHandlerBuilder log(String log) {
275            return log(LoggerFactory.getLogger(log));
276        }
277    
278        /**
279         * Sets the log used for caught exceptions
280         *
281         * @param log the log class
282         * @return the builder
283         */
284        public DefaultErrorHandlerBuilder log(Class<?> log) {
285            return log(LoggerFactory.getLogger(log));
286        }
287    
288        /**
289         * Sets a processor that should be processed <b>before</b> a redelivery attempt.
290         * <p/>
291         * Can be used to change the {@link org.apache.camel.Exchange} <b>before</b> its being redelivered.
292         *
293         * @param processor the processor
294         * @return the builder
295         */
296        public DefaultErrorHandlerBuilder onRedelivery(Processor processor) {
297            setOnRedelivery(processor);
298            return this;
299        }
300    
301        /**
302         * Sets the retry while expression.
303         * <p/>
304         * Will continue retrying until expression evaluates to <tt>false</tt>.
305         *
306         * @param retryWhile expression that determines when to stop retrying
307         * @return the builder
308         */
309        public DefaultErrorHandlerBuilder retryWhile(Expression retryWhile) {
310            setRetryWhile(ExpressionToPredicateAdapter.toPredicate(retryWhile));
311            return this;
312        }
313    
314        /**
315         * Will use the original input {@link org.apache.camel.Message} when an {@link org.apache.camel.Exchange}
316         * is moved to the dead letter queue.
317         * <p/>
318         * <b>Notice:</b> this only applies when all redeliveries attempt have failed and the {@link org.apache.camel.Exchange}
319         * is doomed for failure.
320         * <br/>
321         * Instead of using the current inprogress {@link org.apache.camel.Exchange} IN message we use the original
322         * IN message instead. This allows you to store the original input in the dead letter queue instead of the inprogress
323         * snapshot of the IN message.
324         * For instance if you route transform the IN body during routing and then failed. With the original exchange
325         * store in the dead letter queue it might be easier to manually re submit the {@link org.apache.camel.Exchange}
326         * again as the IN message is the same as when Camel received it.
327         * So you should be able to send the {@link org.apache.camel.Exchange} to the same input.
328         * <p/>
329         * By default this feature is off.
330         *
331         * @return the builder
332         */
333        public DefaultErrorHandlerBuilder useOriginalMessage() {
334            setUseOriginalMessage(true);
335            return this;
336        }
337    
338        // Properties
339        // -------------------------------------------------------------------------
340    
341        public Processor getFailureProcessor() {
342            return failureProcessor;
343        }
344    
345        public void setFailureProcessor(Processor failureProcessor) {
346            this.failureProcessor = failureProcessor;
347        }
348    
349        public RedeliveryPolicy getRedeliveryPolicy() {
350            if (redeliveryPolicy == null) {
351                redeliveryPolicy = createRedeliveryPolicy();
352            }
353            return redeliveryPolicy;
354        }
355    
356        /**
357         * Sets the redelivery policy
358         */
359        public void setRedeliveryPolicy(RedeliveryPolicy redeliveryPolicy) {
360            this.redeliveryPolicy = redeliveryPolicy;
361        }
362    
363        public CamelLogger getLogger() {
364            if (logger == null) {
365                logger = createLogger();
366            }
367            return logger;
368        }
369    
370        public void setLogger(CamelLogger logger) {
371            this.logger = logger;
372        }
373    
374        public Processor getOnRedelivery() {
375            return onRedelivery;
376        }
377    
378        public void setOnRedelivery(Processor onRedelivery) {
379            this.onRedelivery = onRedelivery;
380        }
381    
382        public Predicate getRetryWhilePolicy(CamelContext context) {
383            Predicate answer = getRetryWhile();
384    
385            if (getRetryWhileRef() != null) {
386                // its a bean expression
387                Language bean = context.resolveLanguage("bean");
388                answer = bean.createPredicate(getRetryWhileRef());
389            }
390    
391            return answer;
392        }
393    
394        public Predicate getRetryWhile() {
395            return retryWhile;
396        }
397    
398        public void setRetryWhile(Predicate retryWhile) {
399            this.retryWhile = retryWhile;
400        }
401    
402        public String getRetryWhileRef() {
403            return retryWhileRef;
404        }
405    
406        public void setRetryWhileRef(String retryWhileRef) {
407            this.retryWhileRef = retryWhileRef;
408        }
409    
410        public String getDeadLetterUri() {
411            return deadLetterUri;
412        }
413    
414        public void setDeadLetterUri(String deadLetterUri) {
415            this.deadLetter = null;
416            this.deadLetterUri = deadLetterUri;
417        }
418    
419        public Endpoint getDeadLetter() {
420            return deadLetter;
421        }
422    
423        public void setDeadLetter(Endpoint deadLetter) {
424            this.deadLetter = deadLetter;
425            this.deadLetterUri = deadLetter.getEndpointUri();
426        }
427    
428        public boolean isUseOriginalMessage() {
429            return useOriginalMessage;
430        }
431    
432        public void setUseOriginalMessage(boolean useOriginalMessage) {
433            this.useOriginalMessage = useOriginalMessage;
434        }
435    
436        public boolean isAsyncDelayedRedelivery() {
437            return asyncDelayedRedelivery;
438        }
439    
440        public void setAsyncDelayedRedelivery(boolean asyncDelayedRedelivery) {
441            this.asyncDelayedRedelivery = asyncDelayedRedelivery;
442        }
443    
444        public String getExecutorServiceRef() {
445            return executorServiceRef;
446        }
447    
448        public void setExecutorServiceRef(String executorServiceRef) {
449            this.executorServiceRef = executorServiceRef;
450        }
451    
452        protected RedeliveryPolicy createRedeliveryPolicy() {
453            RedeliveryPolicy policy = new RedeliveryPolicy();
454            policy.disableRedelivery();
455            policy.setRedeliveryDelay(0);
456            return policy;
457        }
458    
459        protected CamelLogger createLogger() {
460            return new CamelLogger(LoggerFactory.getLogger(DefaultErrorHandler.class), LoggingLevel.ERROR);
461        }
462    
463        protected synchronized ScheduledExecutorService getExecutorService(CamelContext camelContext) {
464            if (executorService == null || executorService.isShutdown()) {
465                // camel context will shutdown the executor when it shutdown so no need to shut it down when stopping
466                if (executorServiceRef != null) {
467                    executorService = camelContext.getRegistry().lookupByNameAndType(executorServiceRef, ScheduledExecutorService.class);
468                    if (executorService == null) {
469                        ExecutorServiceManager manager = camelContext.getExecutorServiceManager();
470                        ThreadPoolProfile profile = manager.getThreadPoolProfile(executorServiceRef);
471                        executorService = manager.newScheduledThreadPool(this, executorServiceRef, profile);
472                    }
473                    if (executorService == null) {
474                        throw new IllegalArgumentException("ExecutorServiceRef " + executorServiceRef + " not found in registry.");
475                    }
476                } else {
477                    // no explicit configured thread pool, so leave it up to the error handler to decide if it need
478                    // a default thread pool from CamelContext#getErrorHandlerExecutorService
479                    executorService = null;
480                }
481            }
482            return executorService;
483        }
484    
485        @Override
486        public String toString() {
487            return "DefaultErrorHandlerBuilder";
488        }
489    
490    }