diff --git a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcutAdvisor.cs b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcutAdvisor.cs
index d72f960c..4fb30f5d 100644
--- a/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcutAdvisor.cs
+++ b/src/Spring/Spring.Aop/Aop/Support/AttributeMatchMethodPointcutAdvisor.cs
@@ -53,12 +53,31 @@ namespace Spring.Aop.Support
/// class
/// for the supplied .
///
- ///
+ /// the advice to apply if the pointcut matches
public AttributeMatchMethodPointcutAdvisor(IAdvice advice)
{
this._advice = advice;
}
+ ///
+ /// Creates a new instance of the
+ /// class
+ /// for the supplied .
+ ///
+ ///
+ /// The to match.
+ ///
+ ///
+ /// Flag that controls whether or not the inheritance tree of the
+ /// method to be included in the search for the ?
+ ///
+ /// the advice to apply if the pointcut matches
+ public AttributeMatchMethodPointcutAdvisor(Type attribute, bool inherit, IAdvice advice)
+ :base(attribute, inherit)
+ {
+ this._advice = advice;
+ }
+
///
/// Is this advice associated with a particular instance?
///
diff --git a/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs b/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs
index 3d9b186a..a364cc86 100644
--- a/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs
+++ b/src/Spring/Spring.Aop/Aspects/RetryAdvice.cs
@@ -41,6 +41,11 @@ namespace Spring.Aspects
[Serializable]
public class RetryAdvice : AbstractExceptionHandlerAdvice
{
+ ///
+ ///The type of the callback that is called for delaying retries.
+ ///
+ public delegate void SleepHandler(TimeSpan duration);
+
private static readonly ILog log;
private static readonly TimeSpanConverter timeSpanConverter;
@@ -52,6 +57,8 @@ namespace Spring.Aspects
#region Fields
+ private SleepHandler sleepHandler;
+
[NonSerialized]
private RetryExceptionHandler retryExceptionHandler;
@@ -102,6 +109,21 @@ namespace Spring.Aspects
#endregion
+ ///
+ /// Creates a new RetryAdvice instance, using for delaying retries
+ ///
+ public RetryAdvice()
:this(new SleepHandler(Thread.Sleep))
+ {
+ }
+
+ ///
+ /// Creates a new RetryAdvice instance, using any arbitrary callback for delaying retries
+ ///
+ public RetryAdvice(SleepHandler sleepHandler)
+ {
+ this.sleepHandler = sleepHandler;
+ }
+
#region IMethodInterceptor implementation
///
@@ -158,7 +180,7 @@ namespace Spring.Aspects
log.Trace("Retrying " + invocation.Method.Name);
}
callContextDictionary["n"] = numAttempts;
- Sleep(retryExceptionHandler, callContextDictionary);
+ Sleep(retryExceptionHandler, callContextDictionary, sleepHandler);
}
}
else
@@ -173,11 +195,11 @@ namespace Spring.Aspects
return returnVal;
}
- private static void Sleep(RetryExceptionHandler handler, IDictionary callContextDictionary)
+ private static void Sleep(RetryExceptionHandler handler, IDictionary callContextDictionary, SleepHandler sleepHandler)
{
if (handler.IsDelayBased)
{
- Thread.Sleep(handler.DelayTimeSpan);
+ sleepHandler(handler.DelayTimeSpan);
}
else
{
@@ -186,19 +208,19 @@ namespace Spring.Aspects
IExpression expression = Expression.Parse(handler.DelayRateExpression);
object result = expression.GetValue(null, callContextDictionary);
decimal d = decimal.Parse(result.ToString());
- decimal rounded = decimal.Round(d*1000,0);
- int sleepInSeconds = decimal.ToInt32(rounded);
- Thread.Sleep(sleepInSeconds);
+ decimal rounded = decimal.Round(d*1000,0);
+ TimeSpan duration = TimeSpan.FromMilliseconds(decimal.ToDouble(rounded));
+ sleepHandler(duration);
}
catch (InvalidCastException e)
{
- log.Warn("Was not able to cast expression to decimal [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
- Thread.Sleep(1000);
+ log.Warn("Was not able to cast expression to decimal [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
+ sleepHandler(new TimeSpan(0,0,1));
}
catch (Exception e)
{
- log.Warn("Was not able to evaluate rate expression [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
- Thread.Sleep(1000);
+ log.Warn("Was not able to evaluate rate expression [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
+ sleepHandler(new TimeSpan(0,0,1));
}
}
}
diff --git a/test/Spring/Spring.Aop.Tests/Aspects/RetryAdviceTests.cs b/test/Spring/Spring.Aop.Tests/Aspects/RetryAdviceTests.cs
index 05ace27c..f109c69a 100644
--- a/test/Spring/Spring.Aop.Tests/Aspects/RetryAdviceTests.cs
+++ b/test/Spring/Spring.Aop.Tests/Aspects/RetryAdviceTests.cs
@@ -21,6 +21,7 @@
#region Imports
using System;
+using System.Collections;
using NUnit.Framework;
using Spring.Aop.Framework;
@@ -58,23 +59,28 @@ namespace Spring.Aspects
private static void InvokeOncePassOnceFail(bool useExceptionName, bool isDelay)
{
- ITestRemoteService rs = GetRemoteService(2, useExceptionName, isDelay);
+ TestSleepHandler testSleepHandler = new TestSleepHandler();
+ ITestRemoteService rs = GetRemoteService(2, useExceptionName, isDelay, testSleepHandler);
rs.DoTransfer();
+ AssertSleepsAndReset(testSleepHandler, 2, isDelay);
- rs = GetRemoteService(3, useExceptionName, isDelay);
+ rs = GetRemoteService(3, useExceptionName, isDelay, testSleepHandler);
try
{
rs.DoTransfer();
Assert.Fail("Should have failed.");
} catch (ArithmeticException)
{
-
+ // they maximum retry count is 3, thus only 2 sleep calls
+ AssertSleepsAndReset(testSleepHandler, 2, isDelay);
}
}
+
private static void InvokeOnceFailWithUnexceptedException(bool useExceptionName, bool isDelay)
{
- ITestRemoteService rs = GetRemoteService(3, useExceptionName, isDelay);
+ TestSleepHandler testSleepHandler = new TestSleepHandler();
+ ITestRemoteService rs = GetRemoteService(3, useExceptionName, isDelay, testSleepHandler);
try
{
rs.DoTransfer2();
@@ -86,12 +92,40 @@ namespace Spring.Aspects
}
}
- private static ITestRemoteService GetRemoteService(int numFailures, bool usingExceptionName, bool isDelay)
+ private static void AssertSleepsAndReset(TestSleepHandler testSleepHandler, int numFailures, bool isDelay)
+ {
+ Assert.AreEqual(numFailures, testSleepHandler.CalledTimeSpans.Count);
+ for(int i=0;iFalse
..\..\..\lib\Net\2.0\Common.Logging.dll
-
- False
- ..\..\..\lib\Net\2.0\nunit.core.interfaces.dll
-
False
..\..\..\lib\Net\2.0\nunit.framework.dll