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