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