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