SPRNET-1057 - Add new 'execute' action for ExceptionTranslationAdvice
SPRNET-1056 - Provide easier configuration of exception handlers in ExceptionTranslationAdvice.
This commit is contained in:
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user