diff --git a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs index 50382bc5..9eef2cea 100644 --- a/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs +++ b/src/Spring/Spring.Aop/Aspects/AbstractExceptionHandler.cs @@ -79,7 +79,7 @@ namespace Spring.Aspects /// Gets the source exception names. /// /// The source exception names. - 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. /// /// The source exception types. - 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 /// /// The action translation expression. - public string ActionExpressionText + public virtual string ActionExpressionText { get { return actionExpressionText; } set { actionExpressionText = value; } diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs index 5d0cf6d6..3785a7ee 100644 --- a/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs +++ b/src/Spring/Spring.Aop/Aspects/Exceptions/ExceptionHandlerAdvice.cs @@ -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 /// /// Log instance available to subclasses /// - 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*(.*?)$"; + /// + /// Holds shared handler definition templates + /// + 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; } } + + /// + /// 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. + /// + /// The exception handler dictionary. + 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; } + /// + /// Creates the execute spel exception handler. + /// + /// The parsed advice expression. + /// + protected virtual IExceptionHandler CreateExecuteSpelExceptionHandler(ParsedAdviceExpression parsedAdviceExpression) + { + IExceptionHandler handler; + handler = new ExecuteSpelExceptionHandler(parsedAdviceExpression.ExceptionNames); + return handler; + } + + /// + /// Creates the return value exception handler. + /// + /// The parsed advice expression. + /// + protected virtual IExceptionHandler CreateReturnValueExceptionHandler(ParsedAdviceExpression parsedAdviceExpression) + { + IExceptionHandler handler; + handler = new ReturnValueExceptionHandler(parsedAdviceExpression.ExceptionNames); + return handler; + } + + /// + /// Creates the swallow exception hander. + /// + /// The parsed advice expression. + /// + protected virtual IExceptionHandler CreateSwallowExceptionHander(ParsedAdviceExpression parsedAdviceExpression) + { + IExceptionHandler handler; + handler = new SwallowExceptionHandler(parsedAdviceExpression.ExceptionNames); + return handler; + } + + /// + /// Creates the translation exception handler. + /// + /// The exception names. + /// + protected virtual IExceptionHandler CreateTranslationExceptionHandler(string[] exceptionNames) + { + return new TranslationExceptionHandler(exceptionNames); + } + + /// + /// Creates the log exception handler. + /// + /// The exception names. + /// Log exception + protected virtual LogExceptionHandler CreateLogExceptionHandler(string[] exceptionNames) + { + return new LogExceptionHandler(exceptionNames); + } + /// /// Parses the wrapped exception expression. /// @@ -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 + + /// + /// A specialized dictionary for key value pairs of (string, IExceptionHandler) + /// + public class ExceptionHandlerTable : Hashtable + { + /// + /// Adds the specified key. + /// + /// The key. + /// The value. + public void Add(string key, IExceptionHandler value) + { + lock (SyncRoot) + { + base[key] = value; + } + } + + /// + /// Gets the with the specified key. + /// + /// + public IExceptionHandler this[string key] + { + get + { + lock (SyncRoot) + { + return (IExceptionHandler)base[key]; + } + } + } + + /// + /// Adds an element with the specified key and value into the . + /// + /// The key of the element to add. + /// The value of the element to add. The value can be null. + /// + /// is null. + /// An element with the same key already exists in the . + /// or key is not a string or value is not an IExceptionHandler. + /// The is read-only.-or- The has a fixed size. + 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); + } + + /// + /// Gets the with the specified key. + /// + /// + public override object this[object key] + { + get + { + return this[(string)key]; + } + } + } #endregion } + + } \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/ExecuteSpelExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/ExecuteSpelExceptionHandler.cs new file mode 100644 index 00000000..4204fc64 --- /dev/null +++ b/src/Spring/Spring.Aop/Aspects/Exceptions/ExecuteSpelExceptionHandler.cs @@ -0,0 +1,48 @@ + + +using System; +using System.Collections; +using Spring.Expressions; + +namespace Spring.Aspects.Exceptions +{ + /// + /// Executes an abribtrary Spring Expression Language (SpEL) expression as an action when handling an exception. + /// + public class ExecuteSpelExceptionHandler : AbstractExceptionHandler + { + /// + /// Initializes a new instance of the class. + /// + public ExecuteSpelExceptionHandler() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The exception names. + public ExecuteSpelExceptionHandler(string[] exceptionNames) + : base(exceptionNames) + { + } + + /// + /// Handles the exception. + /// + /// The return value from handling the exception, if not rethrown or a new exception is thrown. + 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; + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs b/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs index f4cd6492..f550fa00 100644 --- a/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs +++ b/src/Spring/Spring.Aop/Aspects/Exceptions/LogExceptionHandler.cs @@ -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; } } + + /// + /// 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. + /// + /// + /// The action translation expression. + 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)"; + } + } + } + } + /// /// Handles the exception. /// @@ -100,8 +134,9 @@ namespace Spring.Aspects.Exceptions /// 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"; } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Aop/Spring.Aop.2008.csproj b/src/Spring/Spring.Aop/Spring.Aop.2008.csproj index be7de0b1..224a1ce9 100644 --- a/src/Spring/Spring.Aop/Spring.Aop.2008.csproj +++ b/src/Spring/Spring.Aop/Spring.Aop.2008.csproj @@ -410,6 +410,7 @@ + diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Exception/CaptureOutputLogger.cs b/test/Spring/Spring.Aop.Tests/Aspects/Exception/CaptureOutputLogger.cs new file mode 100644 index 00000000..724afaa1 --- /dev/null +++ b/test/Spring/Spring.Aop.Tests/Aspects/Exception/CaptureOutputLogger.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; } + } + + /// + /// Do the actual logging by constructing the log message using a then + /// sending the output to . + /// + /// The of the message. + /// The log message. + /// An optional associated with the message. + 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()); + } + + /// + /// Determines if the given log level is currently enabled. + /// + /// + /// + 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); + } + } + + /// + /// Returns if the current is greater than or + /// equal to . If it is, all messages will be sent to . + /// + public bool IsTraceEnabled + { + get { return IsLevelEnabled(LogLevel.Trace); } + } + + /// + /// Returns if the current is greater than or + /// equal to . If it is, all messages will be sent to . + /// + public bool IsDebugEnabled + { + get { return IsLevelEnabled(LogLevel.Debug); } + } + + /// + /// Returns if the current is greater than or + /// equal to . If it is, only messages with a of + /// and will be sent to . + /// + public bool IsErrorEnabled + { + get { return IsLevelEnabled(LogLevel.Error); } + } + + /// + /// Returns if the current is greater than or + /// equal to . If it is, only messages with a of + /// will be sent to . + /// + public bool IsFatalEnabled + { + get { return IsLevelEnabled(LogLevel.Fatal); } + } + + /// + /// Returns if the current is greater than or + /// equal to . If it is, only messages with a of + /// , , , and + /// will be sent to . + /// + public bool IsInfoEnabled + { + get { return IsLevelEnabled(LogLevel.Info); } + } + + + /// + /// Returns if the current is greater than or + /// equal to . If it is, only messages with a of + /// , , and + /// will be sent to . + /// + public bool IsWarnEnabled + { + get { return IsLevelEnabled(LogLevel.Warn); } + } + + #endregion + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Exception/CaptureOutputLoggerFactoryAdapter.cs b/test/Spring/Spring.Aop.Tests/Aspects/Exception/CaptureOutputLoggerFactoryAdapter.cs new file mode 100644 index 00000000..d6bd5993 --- /dev/null +++ b/test/Spring/Spring.Aop.Tests/Aspects/Exception/CaptureOutputLoggerFactoryAdapter.cs @@ -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 + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs b/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs index d6e89750..b7bf57d6 100644 --- a/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs +++ b/test/Spring/Spring.Aop.Tests/Aspects/Exception/ExceptionHandlerAspectIntegrationTests.cs @@ -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)); + } } } \ No newline at end of file diff --git a/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2008.csproj b/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2008.csproj index 409b6c12..939054a5 100644 --- a/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2008.csproj +++ b/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2008.csproj @@ -251,6 +251,8 @@ + + diff --git a/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.dll.config b/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.dll.config index 7aec1f96..62a67b4a 100644 --- a/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.dll.config +++ b/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.dll.config @@ -23,8 +23,15 @@ limitations under the License. + - + + \ No newline at end of file