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