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.activemq;
018
019import java.io.Serializable;
020import java.util.Random;
021
022/**
023 * Configuration options used to control how messages are re-delivered when they
024 * are rolled back.
025 *
026 * @org.apache.xbean.XBean element="redeliveryPolicy"
027 *
028 */
029public class RedeliveryPolicy implements Cloneable, Serializable {
030
031    public static final int NO_MAXIMUM_REDELIVERIES = -1;
032    private static Random randomNumberGenerator;
033
034    // +/-15% for a 30% spread -cgs
035    private double collisionAvoidanceFactor = 0.15d;
036    private int maximumRedeliveries = 6;
037    private long maximumRedeliveryDelay = -1;
038    private long initialRedeliveryDelay = 1000L;
039    private boolean useCollisionAvoidance;
040    private boolean useExponentialBackOff;
041    private double backOffMultiplier = 5.0;
042    private long redeliveryDelay = initialRedeliveryDelay;
043
044    public RedeliveryPolicy() {
045    }
046
047    public RedeliveryPolicy copy() {
048        try {
049            return (RedeliveryPolicy)clone();
050        } catch (CloneNotSupportedException e) {
051            throw new RuntimeException("Could not clone: " + e, e);
052        }
053    }
054
055    public double getBackOffMultiplier() {
056        return backOffMultiplier;
057    }
058
059    public void setBackOffMultiplier(double backOffMultiplier) {
060        this.backOffMultiplier = backOffMultiplier;
061    }
062
063    public short getCollisionAvoidancePercent() {
064        return (short)Math.round(collisionAvoidanceFactor * 100);
065    }
066
067    public void setCollisionAvoidancePercent(short collisionAvoidancePercent) {
068        this.collisionAvoidanceFactor = collisionAvoidancePercent * 0.01d;
069    }
070
071    public long getInitialRedeliveryDelay() {
072        return initialRedeliveryDelay;
073    }
074
075    public void setInitialRedeliveryDelay(long initialRedeliveryDelay) {
076        this.initialRedeliveryDelay = initialRedeliveryDelay;
077    }
078
079    public long getMaximumRedeliveryDelay() {
080        return maximumRedeliveryDelay;
081    }
082
083    public void setMaximumRedeliveryDelay(long maximumRedeliveryDelay) {
084        this.maximumRedeliveryDelay = maximumRedeliveryDelay;
085    }
086
087    public int getMaximumRedeliveries() {
088        return maximumRedeliveries;
089    }
090
091    public void setMaximumRedeliveries(int maximumRedeliveries) {
092        this.maximumRedeliveries = maximumRedeliveries;
093    }
094
095    public long getNextRedeliveryDelay(long previousDelay) {
096        long nextDelay;
097
098        if (previousDelay == 0) {
099            nextDelay = redeliveryDelay;
100        } else if (useExponentialBackOff && backOffMultiplier > 1) {
101            nextDelay = (long) (previousDelay * backOffMultiplier);
102            if(maximumRedeliveryDelay != -1 && nextDelay > maximumRedeliveryDelay) {
103                // in case the user made max redelivery delay less than redelivery delay for some reason.
104                nextDelay = Math.max(maximumRedeliveryDelay, redeliveryDelay);
105            }
106        } else {
107            nextDelay = previousDelay;
108        }
109
110        if (useCollisionAvoidance) {
111            /*
112             * First random determines +/-, second random determines how far to
113             * go in that direction. -cgs
114             */
115            Random random = getRandomNumberGenerator();
116            double variance = (random.nextBoolean() ? collisionAvoidanceFactor : -collisionAvoidanceFactor) * random.nextDouble();
117            nextDelay += nextDelay * variance;
118        }
119
120        return nextDelay;
121    }
122
123    public boolean isUseCollisionAvoidance() {
124        return useCollisionAvoidance;
125    }
126
127    public void setUseCollisionAvoidance(boolean useCollisionAvoidance) {
128        this.useCollisionAvoidance = useCollisionAvoidance;
129    }
130
131    public boolean isUseExponentialBackOff() {
132        return useExponentialBackOff;
133    }
134
135    public void setUseExponentialBackOff(boolean useExponentialBackOff) {
136        this.useExponentialBackOff = useExponentialBackOff;
137    }
138
139    protected static synchronized Random getRandomNumberGenerator() {
140        if (randomNumberGenerator == null) {
141            randomNumberGenerator = new Random();
142        }
143        return randomNumberGenerator;
144    }
145
146    public void setRedeliveryDelay(long redeliveryDelay) {
147        this.redeliveryDelay = redeliveryDelay;
148    }
149
150    public long getRedeliveryDelay() {
151        return redeliveryDelay;
152    }
153}