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 */
017package org.apache.camel.processor;
018
019import java.io.Serializable;
020import java.util.Random;
021
022import org.apache.camel.Exchange;
023import org.apache.camel.LoggingLevel;
024import org.apache.camel.Predicate;
025import org.apache.camel.util.ObjectHelper;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029/**
030 * The policy used to decide how many times to redeliver and the time between
031 * the redeliveries before being sent to a <a
032 * href="http://camel.apache.org/dead-letter-channel.html">Dead Letter
033 * Channel</a>
034 * <p>
035 * The default values are:
036 * <ul>
037 *   <li>maximumRedeliveries = 0</li>
038 *   <li>redeliveryDelay = 1000L (the initial delay)</li>
039 *   <li>maximumRedeliveryDelay = 60 * 1000L</li>
040 *   <li>asyncDelayedRedelivery = false</li>
041 *   <li>backOffMultiplier = 2</li>
042 *   <li>useExponentialBackOff = false</li>
043 *   <li>collisionAvoidanceFactor = 0.15d</li>
044 *   <li>useCollisionAvoidance = false</li>
045 *   <li>retriesExhaustedLogLevel = LoggingLevel.ERROR</li>
046 *   <li>retryAttemptedLogLevel = LoggingLevel.DEBUG</li>
047 *   <li>logRetryAttempted = true</li>
048 *   <li>logRetryStackTrace = false</li>
049 *   <li>logStackTrace = true</li>
050 *   <li>logHandled = false</li>
051 *   <li>logExhausted = true</li>
052 *   <li>logExhaustedMessageHistory = true</li>
053 *   <li>logNewException = true</li>
054 *   <li>allowRedeliveryWhileStopping = true</li>
055 * </ul>
056 * <p/>
057 * Setting the maximumRedeliveries to a negative value such as -1 will then always redeliver (unlimited).
058 * Setting the maximumRedeliveries to 0 will disable redelivery.
059 * <p/>
060 * This policy can be configured either by one of the following two settings:
061 * <ul>
062 *   <li>using conventional options, using all the options defined above</li>
063 *   <li>using delay pattern to declare intervals for delays</li>
064 * </ul>
065 * <p/>
066 * <b>Note:</b> If using delay patterns then the following options is not used (delay, backOffMultiplier, useExponentialBackOff, useCollisionAvoidance)
067 * <p/>
068 * <b>Using delay pattern</b>:
069 * <br/>The delay pattern syntax is: <tt>limit:delay;limit 2:delay 2;limit 3:delay 3;...;limit N:delay N</tt>.
070 * <p/>
071 * How it works is best illustrate with an example with this pattern: <tt>delayPattern=5:1000;10:5000:20:20000</tt>
072 * <br/>The delays will be for attempt in range 0..4 = 0 millis, 5..9 = 1000 millis, 10..19 = 5000 millis, >= 20 = 20000 millis.
073 * <p/>
074 * If you want to set a starting delay, then use 0 as the first limit, eg: <tt>0:1000;5:5000</tt> will use 1 sec delay
075 * until attempt number 5 where it will use 5 seconds going forward.
076 *
077 * @version 
078 */
079public class RedeliveryPolicy implements Cloneable, Serializable {
080    protected static Random randomNumberGenerator;
081    private static final long serialVersionUID = -338222777701473252L;
082    private static final Logger LOG = LoggerFactory.getLogger(RedeliveryPolicy.class);
083
084    protected long redeliveryDelay = 1000L;
085    protected int maximumRedeliveries;
086    protected long maximumRedeliveryDelay = 60 * 1000L;
087    protected double backOffMultiplier = 2;
088    protected boolean useExponentialBackOff;
089    // +/-15% for a 30% spread -cgs
090    protected double collisionAvoidanceFactor = 0.15d;
091    protected boolean useCollisionAvoidance;
092    protected LoggingLevel retriesExhaustedLogLevel = LoggingLevel.ERROR;
093    protected LoggingLevel retryAttemptedLogLevel = LoggingLevel.DEBUG;
094    protected boolean logStackTrace = true;
095    protected boolean logRetryStackTrace;
096    protected boolean logHandled;
097    protected boolean logContinued;
098    protected boolean logExhausted = true;
099    protected boolean logNewException = true;
100    protected Boolean logExhaustedMessageHistory;
101    protected boolean logRetryAttempted = true;
102    protected String delayPattern;
103    protected boolean asyncDelayedRedelivery;
104    protected boolean allowRedeliveryWhileStopping = true;
105    protected String exchangeFormatterRef;
106
107    public RedeliveryPolicy() {
108    }
109
110    @Override
111    public String toString() {
112        return "RedeliveryPolicy[maximumRedeliveries=" + maximumRedeliveries
113            + ", redeliveryDelay=" + redeliveryDelay
114            + ", maximumRedeliveryDelay=" + maximumRedeliveryDelay
115            + ", asyncDelayedRedelivery=" + asyncDelayedRedelivery
116            + ", allowRedeliveryWhileStopping=" + allowRedeliveryWhileStopping
117            + ", retriesExhaustedLogLevel=" + retriesExhaustedLogLevel
118            + ", retryAttemptedLogLevel=" + retryAttemptedLogLevel
119            + ", logRetryAttempted=" + logRetryAttempted
120            + ", logStackTrace=" + logStackTrace
121            + ", logRetryStackTrace=" + logRetryStackTrace
122            + ", logHandled=" + logHandled
123            + ", logContinued=" + logContinued
124            + ", logExhausted=" + logExhausted
125            + ", logNewException=" + logNewException
126            + ", logExhaustedMessageHistory=" + logExhaustedMessageHistory
127            + ", useExponentialBackOff="  + useExponentialBackOff
128            + ", backOffMultiplier=" + backOffMultiplier
129            + ", useCollisionAvoidance=" + useCollisionAvoidance
130            + ", collisionAvoidanceFactor=" + collisionAvoidanceFactor
131            + ", delayPattern=" + delayPattern 
132            + ", exchangeFormatterRef=" + exchangeFormatterRef + "]";
133    }
134
135    public RedeliveryPolicy copy() {
136        try {
137            return (RedeliveryPolicy)clone();
138        } catch (CloneNotSupportedException e) {
139            throw new RuntimeException("Could not clone: " + e, e);
140        }
141    }
142
143    /**
144     * Returns true if the policy decides that the message exchange should be
145     * redelivered.
146     *
147     * @param exchange  the current exchange
148     * @param redeliveryCounter  the current retry counter
149     * @param retryWhile  an optional predicate to determine if we should redeliver or not
150     * @return true to redeliver, false to stop
151     */
152    public boolean shouldRedeliver(Exchange exchange, int redeliveryCounter, Predicate retryWhile) {
153        // predicate is always used if provided
154        if (retryWhile != null) {
155            return retryWhile.matches(exchange);
156        }
157
158        if (getMaximumRedeliveries() < 0) {
159            // retry forever if negative value
160            return true;
161        }
162        // redeliver until we hit the max
163        return redeliveryCounter <= getMaximumRedeliveries();
164    }
165
166
167    /**
168     * Calculates the new redelivery delay based on the last one and then <b>sleeps</b> for the necessary amount of time.
169     * <p/>
170     * This implementation will block while sleeping.
171     *
172     * @param redeliveryDelay  previous redelivery delay
173     * @param redeliveryCounter  number of previous redelivery attempts
174     * @return the calculate delay
175     * @throws InterruptedException is thrown if the sleep is interrupted likely because of shutdown
176     */
177    public long sleep(long redeliveryDelay, int redeliveryCounter) throws InterruptedException {
178        redeliveryDelay = calculateRedeliveryDelay(redeliveryDelay, redeliveryCounter);
179
180        if (redeliveryDelay > 0) {
181            sleep(redeliveryDelay);
182        }
183        return redeliveryDelay;
184    }
185
186    /**
187     * Sleeps for the given delay
188     *
189     * @param redeliveryDelay  the delay
190     * @throws InterruptedException is thrown if the sleep is interrupted likely because of shutdown
191     */
192    public void sleep(long redeliveryDelay) throws InterruptedException {
193        LOG.debug("Sleeping for: {} millis until attempting redelivery", redeliveryDelay);
194        Thread.sleep(redeliveryDelay);
195    }
196
197    /**
198     * Calculates the new redelivery delay based on the last one
199     *
200     * @param previousDelay  previous redelivery delay
201     * @param redeliveryCounter  number of previous redelivery attempts
202     * @return the calculate delay
203     */
204    public long calculateRedeliveryDelay(long previousDelay, int redeliveryCounter) {
205        if (ObjectHelper.isNotEmpty(delayPattern)) {
206            // calculate delay using the pattern
207            return calculateRedeliverDelayUsingPattern(delayPattern, redeliveryCounter);
208        }
209
210        // calculate the delay using the conventional parameters
211        long redeliveryDelayResult;
212        if (previousDelay == 0) {
213            redeliveryDelayResult = redeliveryDelay;
214        } else if (useExponentialBackOff && backOffMultiplier > 1) {
215            redeliveryDelayResult = Math.round(backOffMultiplier * previousDelay);
216        } else {
217            redeliveryDelayResult = previousDelay;
218        }
219
220        if (useCollisionAvoidance) {
221
222            /*
223             * First random determines +/-, second random determines how far to
224             * go in that direction. -cgs
225             */
226            Random random = getRandomNumberGenerator();
227            double variance = (random.nextBoolean() ? collisionAvoidanceFactor : -collisionAvoidanceFactor)
228                              * random.nextDouble();
229            redeliveryDelayResult += redeliveryDelayResult * variance;
230        }
231
232        // ensure the calculated result is not bigger than the max delay (if configured)
233        if (maximumRedeliveryDelay > 0 && redeliveryDelayResult > maximumRedeliveryDelay) {
234            redeliveryDelayResult = maximumRedeliveryDelay;
235        }
236
237        return redeliveryDelayResult;
238    }
239
240    /**
241     * Calculates the delay using the delay pattern
242     */
243    protected static long calculateRedeliverDelayUsingPattern(String delayPattern, int redeliveryCounter) {
244        String[] groups = delayPattern.split(";");
245        // find the group where the redelivery counter matches
246        long answer = 0;
247        for (String group : groups) {
248            long delay = Long.valueOf(ObjectHelper.after(group, ":"));
249            int count = Integer.valueOf(ObjectHelper.before(group, ":"));
250            if (count > redeliveryCounter) {
251                break;
252            } else {
253                answer = delay;
254            }
255        }
256
257        return answer;
258    }
259
260    // Builder methods
261    // -------------------------------------------------------------------------
262
263    /**
264     * Sets the initial redelivery delay in milliseconds
265     *
266     * @deprecated will be removed in the near future. Instead use {@link #redeliveryDelay(long)} instead
267     */
268    @Deprecated
269    public RedeliveryPolicy redeliverDelay(long delay) {
270        return redeliveryDelay(delay);
271    }
272
273    /**
274     * Sets the initial redelivery delay in milliseconds
275     */
276    public RedeliveryPolicy redeliveryDelay(long delay) {
277        setRedeliveryDelay(delay);
278        return this;
279    }
280
281    /**
282     * Sets the maximum number of times a message exchange will be redelivered
283     */
284    public RedeliveryPolicy maximumRedeliveries(int maximumRedeliveries) {
285        setMaximumRedeliveries(maximumRedeliveries);
286        return this;
287    }
288
289    /**
290     * Enables collision avoidance which adds some randomization to the backoff
291     * timings to reduce contention probability
292     */
293    public RedeliveryPolicy useCollisionAvoidance() {
294        setUseCollisionAvoidance(true);
295        return this;
296    }
297
298    /**
299     * Enables exponential backoff using the {@link #getBackOffMultiplier()} to
300     * increase the time between retries
301     */
302    public RedeliveryPolicy useExponentialBackOff() {
303        setUseExponentialBackOff(true);
304        return this;
305    }
306
307    /**
308     * Enables exponential backoff and sets the multiplier used to increase the
309     * delay between redeliveries
310     */
311    public RedeliveryPolicy backOffMultiplier(double multiplier) {
312        useExponentialBackOff();
313        setBackOffMultiplier(multiplier);
314        return this;
315    }
316
317    /**
318     * Enables collision avoidance and sets the percentage used
319     */
320    public RedeliveryPolicy collisionAvoidancePercent(double collisionAvoidancePercent) {
321        useCollisionAvoidance();
322        setCollisionAvoidancePercent(collisionAvoidancePercent);
323        return this;
324    }
325
326    /**
327     * Sets the maximum redelivery delay if using exponential back off.
328     * Use -1 if you wish to have no maximum
329     */
330    public RedeliveryPolicy maximumRedeliveryDelay(long maximumRedeliveryDelay) {
331        setMaximumRedeliveryDelay(maximumRedeliveryDelay);
332        return this;
333    }
334
335    /**
336     * Sets the logging level to use for log messages when retries have been exhausted.
337     */
338    public RedeliveryPolicy retriesExhaustedLogLevel(LoggingLevel retriesExhaustedLogLevel) {
339        setRetriesExhaustedLogLevel(retriesExhaustedLogLevel);
340        return this;
341    }    
342
343    /**
344     * Sets the logging level to use for log messages when retries are attempted.
345     */    
346    public RedeliveryPolicy retryAttemptedLogLevel(LoggingLevel retryAttemptedLogLevel) {
347        setRetryAttemptedLogLevel(retryAttemptedLogLevel);
348        return this;
349    }
350
351    /**
352     * Sets whether to log retry attempts
353     */
354    public RedeliveryPolicy logRetryAttempted(boolean logRetryAttempted) {
355        setLogRetryAttempted(logRetryAttempted);
356        return this;
357    }
358
359    /**
360     * Sets whether to log stacktrace for failed messages.
361     */
362    public RedeliveryPolicy logStackTrace(boolean logStackTrace) {
363        setLogStackTrace(logStackTrace);
364        return this;
365    }
366
367    /**
368     * Sets whether to log stacktrace for failed redelivery attempts
369     */
370    public RedeliveryPolicy logRetryStackTrace(boolean logRetryStackTrace) {
371        setLogRetryStackTrace(logRetryStackTrace);
372        return this;
373    }
374
375    /**
376     * Sets whether to log errors even if its handled
377     */
378    public RedeliveryPolicy logHandled(boolean logHandled) {
379        setLogHandled(logHandled);
380        return this;
381    }
382
383    /**
384     * Sets whether errors should be logged when a new exception occurred during handling a previous exception
385     */
386    public RedeliveryPolicy logNewException(boolean logNewException) {
387        setLogNewException(logNewException);
388        return this;
389    }
390
391    /**
392     * Sets whether to log exhausted errors
393     */
394    public RedeliveryPolicy logExhausted(boolean logExhausted) {
395        setLogExhausted(logExhausted);
396        return this;
397    }
398
399    /**
400     * Sets whether to log exhausted errors including message history
401     */
402    public RedeliveryPolicy logExhaustedMessageHistory(boolean logExhaustedMessageHistory) {
403        setLogExhaustedMessageHistory(logExhaustedMessageHistory);
404        return this;
405    }
406
407    /**
408     * Sets the delay pattern with delay intervals.
409     */
410    public RedeliveryPolicy delayPattern(String delayPattern) {
411        setDelayPattern(delayPattern);
412        return this;
413    }
414
415    /**
416     * Disables redelivery by setting maximum redeliveries to 0.
417     */
418    public RedeliveryPolicy disableRedelivery() {
419        setMaximumRedeliveries(0);
420        return this;
421    }
422
423    /**
424     * Allow asynchronous delayed redelivery.
425     *
426     * @see #setAsyncDelayedRedelivery(boolean)
427     */
428    public RedeliveryPolicy asyncDelayedRedelivery() {
429        setAsyncDelayedRedelivery(true);
430        return this;
431    }
432
433    /**
434     * Controls whether to allow redelivery while stopping/shutting down a route that uses error handling.
435     *
436     * @param redeliverWhileStopping <tt>true</tt> to allow redelivery, <tt>false</tt> to reject redeliveries
437     */
438    public RedeliveryPolicy allowRedeliveryWhileStopping(boolean redeliverWhileStopping) {
439        setAllowRedeliveryWhileStopping(redeliverWhileStopping);
440        return this;
441    }
442    
443    /**
444     * Sets the reference of the instance of {@link org.apache.camel.spi.ExchangeFormatter} to generate the log message from exchange.
445     *
446     * @param exchangeFormatterRef name of the instance of {@link org.apache.camel.spi.ExchangeFormatter}
447     * @return the builder
448     */
449    public RedeliveryPolicy exchangeFormatterRef(String exchangeFormatterRef) {
450        setExchangeFormatterRef(exchangeFormatterRef);
451        return this;
452    }
453
454    // Properties
455    // -------------------------------------------------------------------------
456
457    /**
458     * @deprecated will be removed in the near future. Instead use {@link #getRedeliveryDelay()}
459     */
460    @Deprecated
461    public long getRedeliverDelay() {
462        return getRedeliveryDelay();
463    }
464
465    /**
466     * @deprecated will be removed in the near future. Instead use {@link #setRedeliveryDelay(long)}
467     */
468    @Deprecated
469    public void setRedeliverDelay(long redeliveryDelay) {
470        setRedeliveryDelay(redeliveryDelay);
471    }
472    
473    public long getRedeliveryDelay() {
474        return redeliveryDelay;
475    }
476
477    /**
478     * Sets the initial redelivery delay in milliseconds
479     */
480    public void setRedeliveryDelay(long redeliverDelay) {
481        this.redeliveryDelay = redeliverDelay;
482        // if max enabled then also set max to this value in case max was too low
483        if (maximumRedeliveryDelay > 0 && redeliverDelay > maximumRedeliveryDelay) {
484            this.maximumRedeliveryDelay = redeliverDelay;
485        }
486    }
487
488    public double getBackOffMultiplier() {
489        return backOffMultiplier;
490    }
491
492    /**
493     * Sets the multiplier used to increase the delay between redeliveries if
494     * {@link #setUseExponentialBackOff(boolean)} is enabled
495     */
496    public void setBackOffMultiplier(double backOffMultiplier) {
497        this.backOffMultiplier = backOffMultiplier;
498    }
499
500    public long getCollisionAvoidancePercent() {
501        return Math.round(collisionAvoidanceFactor * 100);
502    }
503
504    /**
505     * Sets the percentage used for collision avoidance if enabled via
506     * {@link #setUseCollisionAvoidance(boolean)}
507     */
508    public void setCollisionAvoidancePercent(double collisionAvoidancePercent) {
509        this.collisionAvoidanceFactor = collisionAvoidancePercent * 0.01d;
510    }
511
512    public double getCollisionAvoidanceFactor() {
513        return collisionAvoidanceFactor;
514    }
515
516    /**
517     * Sets the factor used for collision avoidance if enabled via
518     * {@link #setUseCollisionAvoidance(boolean)}
519     */
520    public void setCollisionAvoidanceFactor(double collisionAvoidanceFactor) {
521        this.collisionAvoidanceFactor = collisionAvoidanceFactor;
522    }
523
524    public int getMaximumRedeliveries() {
525        return maximumRedeliveries;
526    }
527
528    /**
529     * Sets the maximum number of times a message exchange will be redelivered.
530     * Setting a negative value will retry forever.
531     */
532    public void setMaximumRedeliveries(int maximumRedeliveries) {
533        this.maximumRedeliveries = maximumRedeliveries;
534    }
535
536    public long getMaximumRedeliveryDelay() {
537        return maximumRedeliveryDelay;
538    }
539
540    /**
541     * Sets the maximum redelivery delay.
542     * Use -1 if you wish to have no maximum
543     */
544    public void setMaximumRedeliveryDelay(long maximumRedeliveryDelay) {
545        this.maximumRedeliveryDelay = maximumRedeliveryDelay;
546    }
547
548    public boolean isUseCollisionAvoidance() {
549        return useCollisionAvoidance;
550    }
551
552    /**
553     * Enables/disables collision avoidance which adds some randomization to the
554     * backoff timings to reduce contention probability
555     */
556    public void setUseCollisionAvoidance(boolean useCollisionAvoidance) {
557        this.useCollisionAvoidance = useCollisionAvoidance;
558    }
559
560    public boolean isUseExponentialBackOff() {
561        return useExponentialBackOff;
562    }
563
564    /**
565     * Enables/disables exponential backoff using the
566     * {@link #getBackOffMultiplier()} to increase the time between retries
567     */
568    public void setUseExponentialBackOff(boolean useExponentialBackOff) {
569        this.useExponentialBackOff = useExponentialBackOff;
570    }
571
572    protected static synchronized Random getRandomNumberGenerator() {
573        if (randomNumberGenerator == null) {
574            randomNumberGenerator = new Random();
575        }
576        return randomNumberGenerator;
577    }
578
579    /**
580     * Sets the logging level to use for log messages when retries have been exhausted.
581     */    
582    public void setRetriesExhaustedLogLevel(LoggingLevel retriesExhaustedLogLevel) {
583        this.retriesExhaustedLogLevel = retriesExhaustedLogLevel;        
584    }
585    
586    public LoggingLevel getRetriesExhaustedLogLevel() {
587        return retriesExhaustedLogLevel;
588    }
589
590    /**
591     * Sets the logging level to use for log messages when retries are attempted.
592     */    
593    public void setRetryAttemptedLogLevel(LoggingLevel retryAttemptedLogLevel) {
594        this.retryAttemptedLogLevel = retryAttemptedLogLevel;
595    }
596
597    public LoggingLevel getRetryAttemptedLogLevel() {
598        return retryAttemptedLogLevel;
599    }
600
601    public String getDelayPattern() {
602        return delayPattern;
603    }
604
605    /**
606     * Sets an optional delay pattern to use instead of fixed delay.
607     */
608    public void setDelayPattern(String delayPattern) {
609        this.delayPattern = delayPattern;
610    }
611
612    public boolean isLogStackTrace() {
613        return logStackTrace;
614    }
615
616    /**
617     * Sets whether stack traces should be logged or not
618     */
619    public void setLogStackTrace(boolean logStackTrace) {
620        this.logStackTrace = logStackTrace;
621    }
622
623    public boolean isLogRetryStackTrace() {
624        return logRetryStackTrace;
625    }
626
627    /**
628     * Sets whether stack traces should be logged or not
629     */
630    public void setLogRetryStackTrace(boolean logRetryStackTrace) {
631        this.logRetryStackTrace = logRetryStackTrace;
632    }
633
634    public boolean isLogHandled() {
635        return logHandled;
636    }
637
638    /**
639     * Sets whether errors should be logged even if its handled
640     */
641    public void setLogHandled(boolean logHandled) {
642        this.logHandled = logHandled;
643    }
644
645    public boolean isLogNewException() {
646        return logNewException;
647    }
648
649    /**
650     * Sets whether errors should be logged when a new exception occurred during handling a previous exception
651     */
652    public void setLogNewException(boolean logNewException) {
653        this.logNewException = logNewException;
654    }
655
656    public boolean isLogContinued() {
657        return logContinued;
658    }
659
660    /**
661     * Sets whether errors should be logged even if its continued
662     */
663    public void setLogContinued(boolean logContinued) {
664        this.logContinued = logContinued;
665    }
666
667    public boolean isLogRetryAttempted() {
668        return logRetryAttempted;
669    }
670
671    /**
672     * Sets whether retry attempts should be logged or not
673     */
674    public void setLogRetryAttempted(boolean logRetryAttempted) {
675        this.logRetryAttempted = logRetryAttempted;
676    }
677
678    public boolean isLogExhausted() {
679        return logExhausted;
680    }
681
682    /**
683     * Sets whether exhausted exceptions should be logged or not
684     */
685    public void setLogExhausted(boolean logExhausted) {
686        this.logExhausted = logExhausted;
687    }
688
689    public boolean isLogExhaustedMessageHistory() {
690        // should default be enabled
691        return logExhaustedMessageHistory == null || logExhaustedMessageHistory;
692    }
693
694    /**
695     * Whether the option logExhaustedMessageHistory has been configured or not
696     *
697     * @return <tt>null</tt> if not configured, or the configured value as true or false
698     * @see #isLogExhaustedMessageHistory()
699     */
700    public Boolean getLogExhaustedMessageHistory() {
701        return logExhaustedMessageHistory;
702    }
703
704    /**
705     * Sets whether exhausted exceptions should be logged with message history included.
706     */
707    public void setLogExhaustedMessageHistory(boolean logExhaustedMessageHistory) {
708        this.logExhaustedMessageHistory = logExhaustedMessageHistory;
709    }
710
711    public boolean isAsyncDelayedRedelivery() {
712        return asyncDelayedRedelivery;
713    }
714
715    /**
716     * Sets whether asynchronous delayed redelivery is allowed.
717     * <p/>
718     * This is disabled by default.
719     * <p/>
720     * When enabled it allows Camel to schedule a future task for delayed
721     * redelivery which prevents current thread from blocking while waiting.
722     * <p/>
723     * Exchange which is transacted will however always use synchronous delayed redelivery
724     * because the transaction must execute in the same thread context.
725     *
726     * @param asyncDelayedRedelivery whether asynchronous delayed redelivery is allowed
727     */
728    public void setAsyncDelayedRedelivery(boolean asyncDelayedRedelivery) {
729        this.asyncDelayedRedelivery = asyncDelayedRedelivery;
730    }
731
732    public boolean isAllowRedeliveryWhileStopping() {
733        return allowRedeliveryWhileStopping;
734    }
735
736    /**
737     * Controls whether to allow redelivery while stopping/shutting down a route that uses error handling.
738     *
739     * @param allowRedeliveryWhileStopping <tt>true</tt> to allow redelivery, <tt>false</tt> to reject redeliveries
740     */
741    public void setAllowRedeliveryWhileStopping(boolean allowRedeliveryWhileStopping) {
742        this.allowRedeliveryWhileStopping = allowRedeliveryWhileStopping;
743    }
744
745    public String getExchangeFormatterRef() {
746        return exchangeFormatterRef;
747    }
748
749    /**
750     * Sets the reference of the instance of {@link org.apache.camel.spi.ExchangeFormatter} to generate the log message from exchange.
751     */
752    public void setExchangeFormatterRef(String exchangeFormatterRef) {
753        this.exchangeFormatterRef = exchangeFormatterRef;
754    }
755
756}