#region License
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
using System;
using System.Collections;
using AopAlliance.Intercept;
using Spring.Objects.Factory;
using Spring.Objects.Factory.Config;
using Spring.Util;
namespace Spring.Dao.Support{
/// <summary>
/// AOP MethodInterceptor that provides persistence exception translation
/// based on a given PersistenceExceptionTranslator.
/// </summary>
/// <remarks>
/// Delegates to the given <see cref="IPersistenceExceptionTranslator"/> to translate
/// an Exception thrown into Spring's DataAccessException hierarchy
/// (if appropriate).
/// </remarks>
/// <author>Rod Johnson</author>
/// <author>Juergen Hoeller</author>
/// <author>Mark Pollack (.NET)</author>
public class PersistenceExceptionTranslationInterceptor : IMethodInterceptor, IObjectFactoryAware, IInitializingObject
{
private IPersistenceExceptionTranslator persistenceExceptionTranslator;
/// <summary>
/// Initializes a new instance of the <see cref="PersistenceExceptionTranslationInterceptor"/> class.
/// Needs to be configured with a PersistenceExceptionTranslator afterwards.
/// </summary>
public PersistenceExceptionTranslationInterceptor()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PersistenceExceptionTranslationInterceptor"/> class for the
/// given IPersistenceExceptionTranslator
/// </summary>
/// <param name="persistenceExceptionTranslator">The persistence exception translator to use.</param>
public PersistenceExceptionTranslationInterceptor(IPersistenceExceptionTranslator persistenceExceptionTranslator)
{
this.persistenceExceptionTranslator = persistenceExceptionTranslator;
}
/// <summary>
/// Initializes a new instance of the <see cref="PersistenceExceptionTranslationInterceptor"/> class, autodetecting
/// IPersistenceExceptionTranslators in the given object factory.
/// </summary>
/// <param name="objectFactory">The object factory to obtain all IPersistenceExceptionTranslators from.</param>
public PersistenceExceptionTranslationInterceptor(IListableObjectFactory objectFactory)
{
this.persistenceExceptionTranslator = DetectPersistenceExceptionTranslators(objectFactory);
}
/// <summary>
/// Sets the persistence exception translator. The default is to autodetect all IPersistenceExceptionTranslators
/// in the containing object factory, using them in a chain.
/// </summary>
/// <value>The persistence exception translator.</value>
public IPersistenceExceptionTranslator PersistenceExceptionTranslator
{
set
{
AssertUtils.ArgumentNotNull(value, "IPersistenceExceptionTranslator must not be null");
persistenceExceptionTranslator = value;
}
}
/// <summary>
/// Callback that supplies the owning factory to an object instance.
/// </summary>
/// <value>
/// Owning <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// (may not be <see langword="null"/>). The object can immediately
/// call methods on the factory.
/// </value>
/// <remarks>
/// <p>
/// Invoked after population of normal object properties but before an init
/// callback like <see cref="Spring.Objects.Factory.IInitializingObject"/>'s
/// <see cref="Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet"/>
/// method or a custom init-method.
/// </p>
/// </remarks>
/// <exception cref="Spring.Objects.ObjectsException">
/// In case of initialization errors.
/// </exception>
public IObjectFactory ObjectFactory
{
set
{
if (this.persistenceExceptionTranslator == null)
{
// No explicit exception translator specified - perform autodetection.
IListableObjectFactory owningFactory = value as IListableObjectFactory;
if (owningFactory == null)
{
throw new ArgumentException("Cannot use IPersistenceExceptionTranslator autodetection without IListableObjectFactory");
}
this.persistenceExceptionTranslator = DetectPersistenceExceptionTranslators(owningFactory);
}
}
}
/// <summary>
/// Ensures that the property PersistenceExceptionTranslator has been set.
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// after it has injected all of an object's dependencies.
/// </summary>
/// <exception cref="System.Exception">
/// In the event of misconfiguration (such as the failure to set a
/// required property) or if initialization fails.
/// </exception>
public void AfterPropertiesSet()
{
if (this.persistenceExceptionTranslator == null)
{
throw new ArgumentException("Property 'PersistenceExceptionTranslator' is required");
}
}
/// <summary>
/// Detects the petsistence exception translators in the given object factory.
/// </summary>
/// <param name="objectFactory">The object factory for obtaining all IPersistenceExceptionTranslators.</param>
/// <returns>A chained IPersistenceExceptionTranslator, combining all PersistenceExceptionTranslators found in the factory
/// </returns>
/// <seealso cref="ChainedPersistenceExceptionTranslator"/>
protected IPersistenceExceptionTranslator DetectPersistenceExceptionTranslators(IListableObjectFactory objectFactory)
{
// Find all translators, being careful not to activate FactoryObjects.
IDictionary pets =
ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(objectFactory,
typeof (IPersistenceExceptionTranslator), false,
false);
if (pets.Count == 0)
{
throw new InvalidOperationException("No persistence exception translators found in container. Cannot perform exception translation.");
}
ChainedPersistenceExceptionTranslator cpet = new ChainedPersistenceExceptionTranslator();
foreach (DictionaryEntry pet in pets)
{
cpet.AddTranslator((IPersistenceExceptionTranslator)pet.Value);
}
return cpet;
}
/// <summary>
/// Return a translated exception if this is appropriate, otherwise rethrow the original exception.
/// </summary>
/// <param name="invocation"></param>
/// <returns></returns>
public object Invoke(IMethodInvocation invocation)
{
try
{
return invocation.Proceed();
} catch (Exception ex)
{
DataAccessException dex = DataAccessUtils.TranslateIfNecessary(ex, persistenceExceptionTranslator);
if (dex == null)
{
throw;
} else
{
throw dex;
}
}
}
}
}
|