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