SPRNET-1057 - Add new 'execute' action for ExceptionTranslationAdvice

SPRNET-1056 - Provide easier configuration of exception handlers in ExceptionTranslationAdvice.
This commit is contained in:
markpollack
2008-10-13 21:34:01 +00:00
parent b444429cf8
commit 60b85ad33c
10 changed files with 719 additions and 44 deletions

View File

@@ -79,7 +79,7 @@ namespace Spring.Aspects
/// Gets the source exception names.
/// </summary>
/// <value>The source exception names.</value>
public IList SourceExceptionNames
public virtual IList SourceExceptionNames
{
get { return sourceExceptionNames; }
set { sourceExceptionNames = value; }
@@ -89,7 +89,7 @@ namespace Spring.Aspects
/// Gets the source exception types.
/// </summary>
/// <value>The source exception types.</value>
public IList SourceExceptionTypes
public virtual IList SourceExceptionTypes
{
get { return sourceExceptionTypes; }
set { sourceExceptionTypes = value; }
@@ -99,7 +99,7 @@ namespace Spring.Aspects
/// Gets the action translation expression text
/// </summary>
/// <value>The action translation expression.</value>
public string ActionExpressionText
public virtual string ActionExpressionText
{
get { return actionExpressionText; }
set { actionExpressionText = value; }

View File

@@ -23,6 +23,9 @@ using System.Collections;
using System.Reflection;
using AopAlliance.Intercept;
using Common.Logging;
using Spring.Context;
using Spring.Objects.Factory.Config;
using Spring.Util;
namespace Spring.Aspects.Exceptions
{
@@ -72,14 +75,19 @@ namespace Spring.Aspects.Exceptions
/// <summary>
/// Log instance available to subclasses
/// </summary>
protected static readonly ILog log = LogManager.GetLogger(typeof(ExceptionHandlerAdvice));
protected static ILog log = LogManager.GetLogger(typeof(ExceptionHandlerAdvice));
private IList exceptionHandlers = new ArrayList();
private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(log|translate|wrap|replace|return|swallow)\s*(.*?)$";
/// <summary>
/// Holds shared handler definition templates
/// </summary>
private ExceptionHandlerTable exceptionHandlerTable = new ExceptionHandlerTable();
private string onExceptionNameRegex = @"^(on\s+exception\s+name)\s+(.*?)\s+(log|translate|wrap|replace|return|swallow|execute)\s*(.*?)$";
private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(log|translate|wrap|replace|return|swallow|execute)\s*(.*?)$";
private string onExceptionRegex = @"^(on\s+exception\s+)(\(.*?\))\s+(log|translate|wrap|replace|return|swallow)\s*(.*?)$";
#endregion
#region Properties
@@ -114,6 +122,19 @@ namespace Spring.Aspects.Exceptions
set { exceptionHandlers = value; }
}
/// <summary>
/// Gets the exception handler dictionary. Allows for registration of a specific handler where the key
/// is the action type. This makes configuration of a custom exception handler easier, for example
/// LogExceptionHandler, in that only 'user friendly' properties such as LogName, etc., need to be configured
/// and not 'user unfriendly' properties such as ConstraintExpressionText and ActionExpressionText.
/// </summary>
/// <value>The exception handler dictionary.</value>
public ExceptionHandlerTable ExceptionHandlerDictionary
{
get { return exceptionHandlerTable; }
}
#endregion
#region IMethodInterceptor implementation
@@ -241,6 +262,7 @@ namespace Spring.Aspects.Exceptions
}
newExceptionHandlers.Add(handler);
}
//explicitly configured advice, must also configure ConstraintExpressionText and ActionExpressionText!
IExceptionHandler handlerObject = o as IExceptionHandler;
if (handlerObject != null)
{
@@ -315,42 +337,113 @@ namespace Spring.Aspects.Exceptions
{
if (parsedAdviceExpression.ActionText.IndexOf("log") >= 0)
{
//TODO support user selection of level, log.Debug , log.Info etc.
LogExceptionHandler handler = new LogExceptionHandler(parsedAdviceExpression.ExceptionNames);
IExceptionHandler handler;
if (exceptionHandlerTable.ContainsKey("log"))
{
handler = exceptionHandlerTable["log"];
AddExceptionNames(parsedAdviceExpression, handler);
} else
{
handler = CreateLogExceptionHandler(parsedAdviceExpression.ExceptionNames);
}
handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
handler.ActionExpressionText = "#log.Trace(" + parsedAdviceExpression.ActionExpressionText + ")";
handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText;
return handler;
}
else if (parsedAdviceExpression.ActionText.IndexOf("translate") >= 0)
{
TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
IExceptionHandler handler;
if (exceptionHandlerTable.Contains("translate"))
{
handler = exceptionHandlerTable["translate"];
AddExceptionNames(parsedAdviceExpression, handler);
}
else
{
handler = CreateTranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
}
handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText;
return handler;
}
else if (parsedAdviceExpression.ActionText.IndexOf("wrap") >= 0)
{
TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
IExceptionHandler handler;
if (exceptionHandlerTable.Contains("wrap"))
{
handler = exceptionHandlerTable["wrap"];
AddExceptionNames(parsedAdviceExpression, handler);
}
else
{
handler = CreateTranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
}
handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
handler.ActionExpressionText = ParseWrappedExceptionExpression("wrap", parsedAdviceExpression.AdviceExpression);
handler.ActionExpressionText = ParseWrappedExceptionExpression("wrap", parsedAdviceExpression.AdviceExpression);
return handler;
}
else if (parsedAdviceExpression.ActionText.IndexOf("replace") >= 0)
{
TranslationExceptionHandler handler = new TranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
IExceptionHandler handler;
if (exceptionHandlerTable.Contains("replace"))
{
handler = exceptionHandlerTable["replace"];
AddExceptionNames(parsedAdviceExpression, handler);
} else
{
handler = CreateTranslationExceptionHandler(parsedAdviceExpression.ExceptionNames);
}
handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
handler.ActionExpressionText = ParseWrappedExceptionExpression("replace", parsedAdviceExpression.AdviceExpression);
return handler;
}
else if (parsedAdviceExpression.ActionText.IndexOf("swallow") >= 0)
{
SwallowExceptionHandler handler = new SwallowExceptionHandler(parsedAdviceExpression.ExceptionNames);
IExceptionHandler handler;
if (exceptionHandlerTable.Contains("swallow"))
{
handler = exceptionHandlerTable["swallow"];
AddExceptionNames(parsedAdviceExpression, handler);
}
else
{
handler = CreateSwallowExceptionHander(parsedAdviceExpression);
}
handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
return handler;
}
else if (parsedAdviceExpression.ActionText.IndexOf("return") >= 0)
{
ReturnValueExceptionHandler handler = new ReturnValueExceptionHandler(parsedAdviceExpression.ExceptionNames);
IExceptionHandler handler;
if (exceptionHandlerTable.Contains("return"))
{
handler = exceptionHandlerTable["return"];
AddExceptionNames(parsedAdviceExpression, handler);
}
else
{
handler = CreateReturnValueExceptionHandler(parsedAdviceExpression);
}
handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText;
return handler;
}
else if (parsedAdviceExpression.ActionText.IndexOf("execute") >= 0)
{
IExceptionHandler handler;
if (exceptionHandlerTable.Contains("execute"))
{
handler = exceptionHandlerTable["execute"];
AddExceptionNames(parsedAdviceExpression, handler);
}
else
{
handler = CreateExecuteSpelExceptionHandler(parsedAdviceExpression);
}
handler.ConstraintExpressionText = parsedAdviceExpression.ConstraintExpression;
handler.ActionExpressionText = parsedAdviceExpression.ActionExpressionText;
return handler;
@@ -362,6 +455,62 @@ namespace Spring.Aspects.Exceptions
return null;
}
/// <summary>
/// Creates the execute spel exception handler.
/// </summary>
/// <param name="parsedAdviceExpression">The parsed advice expression.</param>
/// <returns></returns>
protected virtual IExceptionHandler CreateExecuteSpelExceptionHandler(ParsedAdviceExpression parsedAdviceExpression)
{
IExceptionHandler handler;
handler = new ExecuteSpelExceptionHandler(parsedAdviceExpression.ExceptionNames);
return handler;
}
/// <summary>
/// Creates the return value exception handler.
/// </summary>
/// <param name="parsedAdviceExpression">The parsed advice expression.</param>
/// <returns></returns>
protected virtual IExceptionHandler CreateReturnValueExceptionHandler(ParsedAdviceExpression parsedAdviceExpression)
{
IExceptionHandler handler;
handler = new ReturnValueExceptionHandler(parsedAdviceExpression.ExceptionNames);
return handler;
}
/// <summary>
/// Creates the swallow exception hander.
/// </summary>
/// <param name="parsedAdviceExpression">The parsed advice expression.</param>
/// <returns></returns>
protected virtual IExceptionHandler CreateSwallowExceptionHander(ParsedAdviceExpression parsedAdviceExpression)
{
IExceptionHandler handler;
handler = new SwallowExceptionHandler(parsedAdviceExpression.ExceptionNames);
return handler;
}
/// <summary>
/// Creates the translation exception handler.
/// </summary>
/// <param name="exceptionNames">The exception names.</param>
/// <returns></returns>
protected virtual IExceptionHandler CreateTranslationExceptionHandler(string[] exceptionNames)
{
return new TranslationExceptionHandler(exceptionNames);
}
/// <summary>
/// Creates the log exception handler.
/// </summary>
/// <param name="exceptionNames">The exception names.</param>
/// <returns>Log exception</returns>
protected virtual LogExceptionHandler CreateLogExceptionHandler(string[] exceptionNames)
{
return new LogExceptionHandler(exceptionNames);
}
/// <summary>
/// Parses the wrapped exception expression.
/// </summary>
@@ -404,7 +553,83 @@ namespace Spring.Aspects.Exceptions
}
private void AddExceptionNames(ParsedAdviceExpression parsedAdviceExpression, IExceptionHandler handler)
{
foreach (string exceptionName in parsedAdviceExpression.ExceptionNames)
{
handler.SourceExceptionNames.Add(exceptionName);
}
}
#endregion
#region ExceptionHandlerTable class
/// <summary>
/// A specialized dictionary for key value pairs of (string, IExceptionHandler)
/// </summary>
public class ExceptionHandlerTable : Hashtable
{
/// <summary>
/// Adds the specified key.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public void Add(string key, IExceptionHandler value)
{
lock (SyncRoot)
{
base[key] = value;
}
}
/// <summary>
/// Gets the <see cref="Spring.Aspects.IExceptionHandler"/> with the specified key.
/// </summary>
/// <value></value>
public IExceptionHandler this[string key]
{
get
{
lock (SyncRoot)
{
return (IExceptionHandler)base[key];
}
}
}
/// <summary>
/// Adds an element with the specified key and value into the <see cref="T:System.Collections.Hashtable"/>.
/// </summary>
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add. The value can be null.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="key"/> is null. </exception>
/// <exception cref="T:System.ArgumentException">An element with the same key already exists in the <see cref="T:System.Collections.Hashtable"/>.
/// or key is not a string or value is not an IExceptionHandler.</exception>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Hashtable"/> is read-only.-or- The <see cref="T:System.Collections.Hashtable"/> has a fixed size. </exception>
public override void Add(object key, object value)
{
AssertUtils.AssertArgumentType(key, "key", typeof(string), "Key must be a string");
AssertUtils.AssertArgumentType(value, "value", typeof(IExceptionHandler), "Key must be a IExceptionHandler");
this.Add((string)key, (IExceptionHandler)value);
}
/// <summary>
/// Gets the <see cref="System.Object"/> with the specified key.
/// </summary>
/// <value></value>
public override object this[object key]
{
get
{
return this[(string)key];
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections;
using Spring.Expressions;
namespace Spring.Aspects.Exceptions
{
/// <summary>
/// Executes an abribtrary Spring Expression Language (SpEL) expression as an action when handling an exception.
/// </summary>
public class ExecuteSpelExceptionHandler : AbstractExceptionHandler
{
/// <summary>
/// Initializes a new instance of the <see cref="ExecuteSpelExceptionHandler"/> class.
/// </summary>
public ExecuteSpelExceptionHandler()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExecuteSpelExceptionHandler"/> class.
/// </summary>
/// <param name="exceptionNames">The exception names.</param>
public ExecuteSpelExceptionHandler(string[] exceptionNames)
: base(exceptionNames)
{
}
/// <summary>
/// Handles the exception.
/// </summary>
/// <returns>The return value from handling the exception, if not rethrown or a new exception is thrown.</returns>
public override object HandleException(IDictionary callContextDictionary)
{
try
{
IExpression expression = Expression.Parse(ActionExpressionText);
expression.GetValue(null, callContextDictionary);
}
catch (Exception e)
{
log.Warn("Was not able to evaluate action expression [" + ActionExpressionText + "]", e);
}
return null;
}
}
}

View File

@@ -37,6 +37,11 @@ namespace Spring.Aspects.Exceptions
private LogLevel logLevel = LogLevel.Trace;
private bool logMessageOnly = false;
private bool first = true;
private string actionExpressionText;
#endregion
@@ -91,6 +96,35 @@ namespace Spring.Aspects.Exceptions
set { logMessageOnly = value; }
}
/// <summary>
/// Gets the action translation expression text. Overridden to add approprate settings to
/// the SpEL expression that does the logging so that it depends on the values of LogLevel and
/// LogMessageOnly. Those properties must be set to the desired values before calling this method.
///
/// </summary>
/// <value>The action translation expression.</value>
public override string ActionExpressionText
{
get { return actionExpressionText; }
set
{
if (first)
{
first = false;
string textPart1 = "#log." + LogLevel.ToString() + "(" + value;
if (logMessageOnly)
{
actionExpressionText = textPart1 + ")";
}
else
{
actionExpressionText = textPart1 + ", #e)";
}
}
}
}
/// <summary>
/// Handles the exception.
/// </summary>
@@ -100,8 +134,9 @@ namespace Spring.Aspects.Exceptions
/// </returns>
public override object HandleException(IDictionary callContextDictionary)
{
ILog log = LogManager.GetLogger(logName);
callContextDictionary.Add("log", log);
//TODO log name is targettype.
ILog adviceLogger = LogManager.GetLogger(logName);
callContextDictionary.Add("log", adviceLogger);
try
{
IExpression expression = Expression.Parse(ActionExpressionText);
@@ -113,5 +148,6 @@ namespace Spring.Aspects.Exceptions
}
return "logged";
}
}
}

View File

@@ -410,6 +410,7 @@
<Compile Include="Aspects\Cache\InvalidateCacheAdvisor.cs" />
<Compile Include="Aspects\Cache\InvalidateCacheAdvice.cs" />
<Compile Include="Aspects\Exceptions\ExceptionHandlerAdvice.cs" />
<Compile Include="Aspects\Exceptions\ExecuteSpelExceptionHandler.cs" />
<Compile Include="Aspects\Exceptions\LogExceptionHandler.cs" />
<Compile Include="Aspects\Exceptions\ReturnValueExceptionHandler.cs" />
<Compile Include="Aspects\Exceptions\SwallowExceptionHandler.cs" />

View File

@@ -0,0 +1,210 @@
using System;
using System.Collections;
using System.Globalization;
using System.Text;
using Common.Logging;
namespace Spring.Aspects.Exceptions
{
public class CaptureOutputLogger : ILog
{
private LogLevel _currentLogLevel = LogLevel.All;
private IList logMessages = new ArrayList();
public IList LogMessages
{
get { return logMessages; }
set { logMessages = value; }
}
/// <summary>
/// Do the actual logging by constructing the log message using a <see cref="StringBuilder" /> then
/// sending the output to <see cref="Console.Out" />.
/// </summary>
/// <param name="level">The <see cref="LogLevel" /> of the message.</param>
/// <param name="message">The log message.</param>
/// <param name="e">An optional <see cref="Exception" /> associated with the message.</param>
private void Write(LogLevel level, object message, Exception e)
{
// Use a StringBuilder for better performance
StringBuilder sb = new StringBuilder();
// Append date-time if so configured
// Append a readable representation of the log level
sb.Append(("[" + level.ToString().ToUpper() + "]").PadRight(8));
// Append the message
sb.Append(message);
// Append stack trace if not null
if (e != null)
{
sb.Append(Environment.NewLine).Append(e.ToString());
}
// Print to the appropriate destination
logMessages.Add(sb.ToString());
}
/// <summary>
/// Determines if the given log level is currently enabled.
/// </summary>
/// <param name="level"></param>
/// <returns></returns>
private bool IsLevelEnabled(LogLevel level)
{
int iLevel = (int)level;
int iCurrentLogLevel = (int)_currentLogLevel;
// return iLevel.CompareTo(iCurrentLogLevel); better ???
return (iLevel >= iCurrentLogLevel);
}
#region ILog Members
public void Trace(object message)
{
Trace(message, null);
}
public void Trace(object message, Exception e)
{
if (IsLevelEnabled(LogLevel.Trace))
{
Write(LogLevel.Trace, message, e);
}
}
public void Debug(object message)
{
Debug(message, null);
}
public void Debug(object message, Exception e)
{
if (IsLevelEnabled(LogLevel.Debug))
{
Write(LogLevel.Debug, message, e);
}
}
public void Error(object message)
{
Error(message, null);
}
public void Error(object message, Exception e)
{
if (IsLevelEnabled(LogLevel.Error))
{
Write(LogLevel.Error, message, e);
}
}
public void Fatal(object message)
{
Fatal(message, null);
}
public void Fatal(object message, Exception e)
{
if (IsLevelEnabled(LogLevel.Fatal))
{
Write(LogLevel.Fatal, message, e);
}
}
public void Info(object message)
{
Info(message, null);
}
public void Info(object message, Exception e)
{
if (IsLevelEnabled(LogLevel.Info))
{
Write(LogLevel.Info, message, e);
}
}
public void Warn(object message)
{
Warn(message, null);
}
public void Warn(object message, Exception e)
{
if (IsLevelEnabled(LogLevel.Warn))
{
Write(LogLevel.Warn, message, e);
}
}
/// <summary>
/// Returns <see langword="true" /> if the current <see cref="LogLevel" /> is greater than or
/// equal to <see cref="LogLevel.Trace" />. If it is, all messages will be sent to <see cref="Console.Out" />.
/// </summary>
public bool IsTraceEnabled
{
get { return IsLevelEnabled(LogLevel.Trace); }
}
/// <summary>
/// Returns <see langword="true" /> if the current <see cref="LogLevel" /> is greater than or
/// equal to <see cref="LogLevel.Debug" />. If it is, all messages will be sent to <see cref="Console.Out" />.
/// </summary>
public bool IsDebugEnabled
{
get { return IsLevelEnabled(LogLevel.Debug); }
}
/// <summary>
/// Returns <see langword="true" /> if the current <see cref="LogLevel" /> is greater than or
/// equal to <see cref="LogLevel.Error" />. If it is, only messages with a <see cref="LogLevel" /> of
/// <see cref="LogLevel.Error" /> and <see cref="LogLevel.Fatal" /> will be sent to <see cref="Console.Out" />.
/// </summary>
public bool IsErrorEnabled
{
get { return IsLevelEnabled(LogLevel.Error); }
}
/// <summary>
/// Returns <see langword="true" /> if the current <see cref="LogLevel" /> is greater than or
/// equal to <see cref="LogLevel.Fatal" />. If it is, only messages with a <see cref="LogLevel" /> of
/// <see cref="LogLevel.Fatal" /> will be sent to <see cref="Console.Out" />.
/// </summary>
public bool IsFatalEnabled
{
get { return IsLevelEnabled(LogLevel.Fatal); }
}
/// <summary>
/// Returns <see langword="true" /> if the current <see cref="LogLevel" /> is greater than or
/// equal to <see cref="LogLevel.Info" />. If it is, only messages with a <see cref="LogLevel" /> of
/// <see cref="LogLevel.Info" />, <see cref="LogLevel.Warn" />, <see cref="LogLevel.Error" />, and
/// <see cref="LogLevel.Fatal" /> will be sent to <see cref="Console.Out" />.
/// </summary>
public bool IsInfoEnabled
{
get { return IsLevelEnabled(LogLevel.Info); }
}
/// <summary>
/// Returns <see langword="true" /> if the current <see cref="LogLevel" /> is greater than or
/// equal to <see cref="LogLevel.Warn" />. If it is, only messages with a <see cref="LogLevel" /> of
/// <see cref="LogLevel.Warn" />, <see cref="LogLevel.Error" />, and <see cref="LogLevel.Fatal" />
/// will be sent to <see cref="Console.Out" />.
/// </summary>
public bool IsWarnEnabled
{
get { return IsLevelEnabled(LogLevel.Warn); }
}
#endregion
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Specialized;
using Common.Logging;
namespace Spring.Aspects.Exceptions
{
public class CaptureOutputLoggerFactoryAdapter : ILoggerFactoryAdapter
{
private CaptureOutputLogger adviceLogger;
public CaptureOutputLoggerFactoryAdapter()
{
}
public CaptureOutputLoggerFactoryAdapter(NameValueCollection properties)
{
}
public CaptureOutputLogger AdviceLogger
{
get { return adviceLogger; }
}
#region ILoggerFactoryAdapter Members
public ILog GetLogger(Type type)
{
return GetLogger(type.FullName);
}
public ILog GetLogger(string name)
{
CaptureOutputLogger logger = new CaptureOutputLogger();
if (name.Equals("adviceHandler") || name.IndexOf("LogExceptionHandler") >= 0)
{
adviceLogger = logger;
}
return logger;
}
#endregion
}
}

View File

@@ -30,6 +30,7 @@ using Spring.Aop.Framework;
using Spring.Aspects.Exceptions;
using Spring.Expressions;
using Spring.Objects;
using Spring.Util;
#endregion
@@ -43,24 +44,64 @@ namespace Spring.Aspects.Exceptions
public class ExceptionHandlerAspectIntegrationTests
{
private ExceptionHandlerAdvice exceptionHandlerAdvice;
private CaptureOutputLoggerFactoryAdapter loggerFactoryAdapter;
private ILoggerFactoryAdapter originalAdapter;
private static bool spelActionExecuted = false;
[SetUp]
public void Setup()
{
LogManager.Adapter = new ConsoleOutLoggerFactoryAdapter(new NameValueCollection());
exceptionHandlerAdvice = new ExceptionHandlerAdvice();
originalAdapter = LogManager.Adapter;
loggerFactoryAdapter = new CaptureOutputLoggerFactoryAdapter();
LogManager.Adapter = loggerFactoryAdapter;
exceptionHandlerAdvice = new ExceptionHandlerAdvice();
}
public void TearDown()
{
loggerFactoryAdapter.AdviceLogger.LogMessages.Clear();
//reset so other tests can produce some output if needed.
LogManager.Adapter = originalAdapter;
}
[Test]
public void ExecuteSpelAction()
{
string executeHandlerText =
"on exception name ArithmeticException execute Spring.Aspects.Exceptions.ExceptionHandlerAspectIntegrationTests.Executed(true)";
ITestObject to = CreateTestObjectProxy(executeHandlerText);
try
{
to.Exceptional(new ArithmeticException());
}
catch (ArithmeticException)
{
Assert.IsTrue(spelActionExecuted);
}
}
public static void Executed(bool val)
{
spelActionExecuted = val;
}
[Test]
public void LoggingTest()
{
CaptureOutputLoggerFactoryAdapter loggerFactoryAdapter = new CaptureOutputLoggerFactoryAdapter();
LogManager.Adapter = loggerFactoryAdapter;
LogExceptionHandler logHandler = new LogExceptionHandler();
string testText = @"#log.Debug('Hello World, exception message = ' + #e.Message + ', target method = ' + #method.Name)";
logHandler.LogName = "adviceHandler";
string testText = @"'Hello World, exception message = ' + #e.Message + ', target method = ' + #method.Name";
logHandler.SourceExceptionNames.Add("ArithmeticException");
logHandler.ActionExpressionText = testText;
exceptionHandlerAdvice.ExceptionHandlers.Add(logHandler);
exceptionHandlerAdvice.AfterPropertiesSet();
ProxyFactory pf = new ProxyFactory(new TestObject());
pf.AddAdvice(exceptionHandlerAdvice);
ITestObject to = (ITestObject) pf.GetProxy();
@@ -71,7 +112,17 @@ namespace Spring.Aspects.Exceptions
Assert.Fail("Should have thrown exception when only logging");
} catch (ArithmeticException)
{
//TODO need to create adapter implementation to replay logged text.
bool found = false;
foreach (string message in loggerFactoryAdapter.AdviceLogger.LogMessages)
{
if (message.IndexOf("Hello World") >= 0)
{
found = true;
}
}
Assert.IsTrue(found, "did not find logging output");
}
}
@@ -81,7 +132,15 @@ namespace Spring.Aspects.Exceptions
{
string logHandlerText = "on exception name ArithmeticException log 'My Message, Method Name ' + #method.Name";
ExecuteLoggingHandler(logHandlerText);
ExecuteLoggingHandler(logHandlerText, "My Message");
}
[Test]
public void LoggingTestWithStringExplicitHandler()
{
string logHandlerText = "on exception name ArithmeticException log 'My Message, Method Name ' + #method.Name";
ExecuteLoggingHandler(logHandlerText, "My Message");
}
[Test]
@@ -89,18 +148,26 @@ namespace Spring.Aspects.Exceptions
{
string logHandlerText = "on exception (#e is T(System.ArithmeticException)) log 'My Message, Method Name ' + #method.Name";
ExecuteLoggingHandler(logHandlerText);
ExecuteLoggingHandler(logHandlerText, "My Message");
}
[Test]
public void LoggingTestWithConstraintExpressionWithExceptionHandler()
public void LoggingTestWithConstraintExpressionWithExceptionHandlerInList()
{
LogExceptionHandler exHandler = new LogExceptionHandler();
exHandler.ConstraintExpressionText = "#e is T(System.ArithmeticException)";
exHandler.LogName = "Cms.Session.ExceptionHandler";
exHandler.LogName = "adviceHandler";
exHandler.ActionExpressionText = "#log.Fatal('Request Timeout occured', #e)";
ExecuteLoggingHandler(exHandler);
ExecuteLoggingHandlerInList(exHandler, "Request Timeout");
}
[Test]
public void LoggingTestWithConstraintExpressionWithKeyedExceptionHandler()
{
LogExceptionHandler exHandler = new LogExceptionHandler();
ExecuteLoggingHandlerWithKeyedLogHandler(exHandler,
@"on exception (#e is T(System.ArithmeticException)) log 'Request Timeout occured'", "Request Timeout");
}
[Test]
@@ -109,7 +176,7 @@ namespace Spring.Aspects.Exceptions
{
string logHandlerText = "on foobar name ArithmeticException log 'My Message, Method Name ' + #method.Name";
ExecuteLoggingHandler(logHandlerText);
ExecuteLoggingHandler(logHandlerText, "My Message");
}
[Test]
@@ -117,11 +184,8 @@ namespace Spring.Aspects.Exceptions
{
string logHandlerText = "on exception (#e is System.FooBar) log 'My Message, Method Name ' + #method.Name";
ExecuteLoggingHandler(logHandlerText);
//No exception is expected.
ExecuteLoggingHandler(logHandlerText, "[WARN] Was not able to evaluate constraint expression [#e is System.FooBar]");
//TODO need to make sure log statement was executed.
}
[Test]
@@ -129,14 +193,11 @@ namespace Spring.Aspects.Exceptions
{
string logHandlerText = "on exception (1+1) log 'My Message, Method Name ' + #method.Name";
ExecuteLoggingHandler(logHandlerText);
ExecuteLoggingHandler(logHandlerText, "[WARN] Was not able to unbox constraint expression to boolean [1+1]");
//No exception is expected.
//TODO need to make sure log statement was executed.
}
private void ExecuteLoggingHandler(string logHandlerText)
private void ExecuteLoggingHandler(string logHandlerText, string searchString)
{
ITestObject to = CreateTestObjectProxy(logHandlerText);
@@ -146,13 +207,13 @@ namespace Spring.Aspects.Exceptions
}
catch (ArithmeticException)
{
//TODO assert logging occured.
AssertSearchString(searchString);
}
}
private void ExecuteLoggingHandler(IExceptionHandler handler)
private void ExecuteLoggingHandlerInList(IExceptionHandler handler, string searchString)
{
ITestObject to = CreateTestObjectProxy(handler);
ITestObject to = CreateTestObjectProxyInList(handler);
try
{
@@ -160,11 +221,23 @@ namespace Spring.Aspects.Exceptions
}
catch (ArithmeticException)
{
//TODO assert logging occured.
AssertSearchString(searchString);
}
}
private void ExecuteLoggingHandlerWithKeyedLogHandler(IExceptionHandler handler, string handlerText, string searchString)
{
ITestObject to = CreateTestObjectProxyWithKeyedHandler(handler, handlerText);
try
{
to.Exceptional(new ArithmeticException());
}
catch (ArithmeticException)
{
AssertSearchString(searchString);
}
}
[Test]
public void TranslationWithString()
@@ -390,6 +463,19 @@ namespace Spring.Aspects.Exceptions
return CreateProxy();
}
private ITestObject CreateTestObjectProxyInList(IExceptionHandler exceptionHander)
{
exceptionHandlerAdvice.ExceptionHandlers.Add(exceptionHander);
return CreateProxy();
}
private ITestObject CreateTestObjectProxyWithKeyedHandler(IExceptionHandler exceptionHander, string handlerText)
{
exceptionHandlerAdvice.ExceptionHandlerDictionary.Add("log", exceptionHander);
exceptionHandlerAdvice.ExceptionHandlers.Add(handlerText);
return CreateProxy();
}
private ITestObject CreateProxy()
{
exceptionHandlerAdvice.AfterPropertiesSet();
@@ -397,6 +483,19 @@ namespace Spring.Aspects.Exceptions
pf.AddAdvice(exceptionHandlerAdvice);
return (ITestObject)pf.GetProxy();
}
private void AssertSearchString(string searchString)
{
bool found = false;
foreach (string message in loggerFactoryAdapter.AdviceLogger.LogMessages)
{
if (message.IndexOf(searchString) >= 0)
{
found = true;
}
}
Assert.IsTrue(found, "did not find logging output [" + searchString + "] Logging values = "
+ StringUtils.CollectionToCommaDelimitedString(loggerFactoryAdapter.AdviceLogger.LogMessages));
}
}
}

View File

@@ -251,6 +251,8 @@
<Compile Include="Aspects\Cache\CacheParameterAdviceTests.cs" />
<Compile Include="Aspects\Cache\CacheAspectIntegrationTests.cs" />
<Compile Include="Aspects\Cache\InvalidateCacheAdviceTests.cs" />
<Compile Include="Aspects\Exception\CaptureOutputLogger.cs" />
<Compile Include="Aspects\Exception\CaptureOutputLoggerFactoryAdapter.cs" />
<Compile Include="Aspects\Exception\ExceptionHandlerAspectIntegrationTests.cs" />
<Compile Include="Aspects\Logging\SimpleLoggingAdviceTests.cs" />
<Compile Include="Aspects\Logging\TestableSimpleLoggingAdvice.cs" />

View File

@@ -23,8 +23,15 @@ limitations under the License.
<common>
<logging>
<!--
<factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
<arg key="level" value="DEBUG" />
</factoryAdapter>
-->
<factoryAdapter type="Common.Logging.Simple.NoOpLoggerFactoryAdapter, Common.Logging">
</factoryAdapter>
</factoryAdapter>
</logging>
</common>
</configuration>