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