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 // Code taken from the ActiveMQ codebase
023
024 /**
025 * The policy used to decide how many times to redeliver and the time between
026 * the redeliveries before being sent to a <a
027 * href="http://activemq.apache.org/camel/dead-letter-channel.html">Dead Letter
028 * Channel</a>
029 * <p>
030 * The default values is:
031 * <ul>
032 * <li>maximumRedeliveries = 6</li>
033 * <li>initialRedeliveryDelay = 1000L</li>
034 * <li>backOffMultiplier = 2</li>
035 * <li>useExponentialBackOff = false</li>
036 * <li>collisionAvoidanceFactor = 0.15d</li>
037 * <li>useCollisionAvoidance = false</li>
038 * </ul>
039 *
040 * @version $Revision: 37863 $
041 */
042 public class RedeliveryPolicy implements Cloneable, Serializable {
043 protected static transient Random randomNumberGenerator;
044 protected int maximumRedeliveries = 6;
045 protected long initialRedeliveryDelay = 1000L;
046 protected double backOffMultiplier = 2;
047 protected boolean useExponentialBackOff;
048 // +/-15% for a 30% spread -cgs
049 protected double collisionAvoidanceFactor = 0.15d;
050 protected boolean useCollisionAvoidance;
051
052 public RedeliveryPolicy() {
053 }
054
055 @Override
056 public String toString() {
057 return "RedeliveryPolicy[maximumRedeliveries=" + maximumRedeliveries + "]";
058 }
059
060 public RedeliveryPolicy copy() {
061 try {
062 return (RedeliveryPolicy)clone();
063 } catch (CloneNotSupportedException e) {
064 throw new RuntimeException("Could not clone: " + e, e);
065 }
066 }
067
068 /**
069 * Returns true if the policy decides that the message exchange should be
070 * redelivered
071 */
072 public boolean shouldRedeliver(int redeliveryCounter) {
073 if (getMaximumRedeliveries() < 0) {
074 return true;
075 }
076 return redeliveryCounter < getMaximumRedeliveries();
077 }
078
079 // Builder methods
080 // -------------------------------------------------------------------------
081
082 /**
083 * Sets the maximum number of times a message exchange will be redelivered
084 */
085 public RedeliveryPolicy maximumRedeliveries(int maximumRedeliveries) {
086 setMaximumRedeliveries(maximumRedeliveries);
087 return this;
088 }
089
090 /**
091 * Sets the initial redelivery delay in milliseconds on the first redelivery
092 */
093 public RedeliveryPolicy initialRedeliveryDelay(long initialRedeliveryDelay) {
094 setInitialRedeliveryDelay(initialRedeliveryDelay);
095 return this;
096 }
097
098 /**
099 * Enables collision avoidence which adds some randomization to the backoff
100 * timings to reduce contention probability
101 */
102 public RedeliveryPolicy useCollisionAvoidance() {
103 setUseCollisionAvoidance(true);
104 return this;
105 }
106
107 /**
108 * Enables exponential backof using the {@link #getBackOffMultiplier()} to
109 * increase the time between retries
110 */
111 public RedeliveryPolicy useExponentialBackOff() {
112 setUseExponentialBackOff(true);
113 return this;
114 }
115
116 /**
117 * Enables exponential backoff and sets the multiplier used to increase the
118 * delay between redeliveries
119 */
120 public RedeliveryPolicy backOffMultiplier(double multiplier) {
121 useExponentialBackOff();
122 setBackOffMultiplier(multiplier);
123 return this;
124 }
125
126 /**
127 * Enables collision avoidence and sets the percentage used
128 */
129 public RedeliveryPolicy collisionAvoidancePercent(double collisionAvoidancePercent) {
130 useCollisionAvoidance();
131 setCollisionAvoidancePercent(collisionAvoidancePercent);
132 return this;
133 }
134
135 // Properties
136 // -------------------------------------------------------------------------
137 public double getBackOffMultiplier() {
138 return backOffMultiplier;
139 }
140
141 /**
142 * Sets the multiplier used to increase the delay between redeliveries if
143 * {@link #setUseExponentialBackOff(boolean)} is enabled
144 */
145 public void setBackOffMultiplier(double backOffMultiplier) {
146 this.backOffMultiplier = backOffMultiplier;
147 }
148
149 public short getCollisionAvoidancePercent() {
150 return (short)Math.round(collisionAvoidanceFactor * 100);
151 }
152
153 /**
154 * Sets the percentage used for collision avoidence if enabled via
155 * {@link #setUseCollisionAvoidance(boolean)}
156 */
157 public void setCollisionAvoidancePercent(double collisionAvoidancePercent) {
158 this.collisionAvoidanceFactor = collisionAvoidancePercent * 0.01d;
159 }
160
161 public double getCollisionAvoidanceFactor() {
162 return collisionAvoidanceFactor;
163 }
164
165 /**
166 * Sets the factor used for collision avoidence if enabled via
167 * {@link #setUseCollisionAvoidance(boolean)}
168 */
169 public void setCollisionAvoidanceFactor(double collisionAvoidanceFactor) {
170 this.collisionAvoidanceFactor = collisionAvoidanceFactor;
171 }
172
173 public long getInitialRedeliveryDelay() {
174 return initialRedeliveryDelay;
175 }
176
177 /**
178 * Sets the initial redelivery delay in milliseconds on the first redelivery
179 */
180 public void setInitialRedeliveryDelay(long initialRedeliveryDelay) {
181 this.initialRedeliveryDelay = initialRedeliveryDelay;
182 }
183
184 public int getMaximumRedeliveries() {
185 return maximumRedeliveries;
186 }
187
188 /**
189 * Sets the maximum number of times a message exchange will be redelivered.
190 * Setting a negative value will retry forever.
191 */
192 public void setMaximumRedeliveries(int maximumRedeliveries) {
193 this.maximumRedeliveries = maximumRedeliveries;
194 }
195
196 public long getRedeliveryDelay(long previousDelay) {
197 long redeliveryDelay;
198
199 if (previousDelay == 0) {
200 redeliveryDelay = initialRedeliveryDelay;
201 } else if (useExponentialBackOff && backOffMultiplier > 1) {
202 redeliveryDelay = Math.round(backOffMultiplier * previousDelay);
203 } else {
204 redeliveryDelay = previousDelay;
205 }
206
207 if (useCollisionAvoidance) {
208
209 /*
210 * First random determines +/-, second random determines how far to
211 * go in that direction. -cgs
212 */
213 Random random = getRandomNumberGenerator();
214 double variance = (random.nextBoolean() ? collisionAvoidanceFactor : -collisionAvoidanceFactor)
215 * random.nextDouble();
216 redeliveryDelay += redeliveryDelay * variance;
217 }
218
219 return redeliveryDelay;
220 }
221
222 public boolean isUseCollisionAvoidance() {
223 return useCollisionAvoidance;
224 }
225
226 /**
227 * Enables/disables collision avoidence which adds some randomization to the
228 * backoff timings to reduce contention probability
229 */
230 public void setUseCollisionAvoidance(boolean useCollisionAvoidance) {
231 this.useCollisionAvoidance = useCollisionAvoidance;
232 }
233
234 public boolean isUseExponentialBackOff() {
235 return useExponentialBackOff;
236 }
237
238 /**
239 * Enables/disables exponential backof using the
240 * {@link #getBackOffMultiplier()} to increase the time between retries
241 */
242 public void setUseExponentialBackOff(boolean useExponentialBackOff) {
243 this.useExponentialBackOff = useExponentialBackOff;
244 }
245
246 protected static synchronized Random getRandomNumberGenerator() {
247 if (randomNumberGenerator == null) {
248 randomNumberGenerator = new Random();
249 }
250 return randomNumberGenerator;
251 }
252 }