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