blob: 30cff9058034b4aa9f8a25074a437459492a918d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace Apache.NMS.Policies
{
/// <summary>
/// A policy used to customize exactly how you want the redelivery to work.
/// </summary>
public class RedeliveryPolicy : IRedeliveryPolicy
{
private static readonly object syncObject = new object();
private double collisionAvoidanceFactor = .15;
private int initialRedeliveryDelay = 1000;
private int maximumRedeliveries = 6;
private int backOffMultiplier = 5;
private bool useCollisionAvoidance = false;
private bool useExponentialBackOff = false;
private static Random randomNumberGenerator;
private static bool nextBool = false;
#region IRedeliveryPolicy Members
public int CollisionAvoidancePercent
{
get { return Convert.ToInt32(Math.Round(collisionAvoidanceFactor * 100)); }
set { collisionAvoidanceFactor = Convert.ToDouble(value) * .01; }
}
public bool UseCollisionAvoidance
{
get { return this.useCollisionAvoidance; }
set { this.useCollisionAvoidance = value; }
}
public int InitialRedeliveryDelay
{
get { return this.initialRedeliveryDelay; }
set { this.initialRedeliveryDelay = value; }
}
public int MaximumRedeliveries
{
get { return this.maximumRedeliveries; }
set { this.maximumRedeliveries = value; }
}
public virtual int RedeliveryDelay(int redeliveredCounter)
{
int delay = 0;
if(redeliveredCounter == 0)
{
// The first time through there is no delay, the Rollback should be immediate.
return 0;
}
if(UseExponentialBackOff && BackOffMultiplier > 1)
{
delay = initialRedeliveryDelay * Convert.ToInt32(Math.Pow(BackOffMultiplier, redeliveredCounter - 1));
}
else
{
delay = InitialRedeliveryDelay;
}
if(UseCollisionAvoidance)
{
Random random = RandomNumberGenerator;
double variance = (NextBool ? collisionAvoidanceFactor : collisionAvoidanceFactor *= -1) * random.NextDouble();
delay += Convert.ToInt32(Convert.ToDouble(delay) * variance);
}
return delay;
}
public bool UseExponentialBackOff
{
get { return this.useExponentialBackOff; }
set { this.useExponentialBackOff = value; }
}
public int BackOffMultiplier
{
get { return backOffMultiplier; }
set { backOffMultiplier = value; }
}
#endregion
/// <summary>
/// Gets the random number generator.
/// </summary>
/// <value>The random number generator.</value>
protected static Random RandomNumberGenerator
{
get
{
if(randomNumberGenerator == null)
{
lock(syncObject)
{
if(randomNumberGenerator == null)
{
randomNumberGenerator = new Random(DateTime.Now.Second);
}
}
}
return randomNumberGenerator;
}
}
/// <summary>
/// Gets the next boolean
/// </summary>
/// <value><c>true</c> if [next bool]; otherwise, <c>false</c>.</value>
protected static bool NextBool
{
get
{
lock(syncObject)
{
nextBool = !nextBool;
return nextBool;
}
}
}
/// <summery>
/// Clone this object and return a new instance that the caller now owns.
/// </summery>
public Object Clone()
{
// Since we are a derived class use the base's Clone()
// to perform the shallow copy. Since it is shallow it
// will include our derived class. Since we are derived,
// this method is an override.
return this.MemberwiseClone();
}
}
}