#region License
/*
* Copyright 2002-2004 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 Common.Logging;
using Spring.Objects.Factory;
namespace Spring.Transaction.Support{
/// <summary>
/// Helper class that simplifies programmatic transaction demarcation and
/// transaction exception handling.
/// </summary>
/// <remarks>
/// <p>
/// The central methods are
/// <see cref="Spring.Transaction.Support.TransactionTemplate.Execute(ITransactionCallback)"/>
/// and <see cref="Spring.Transaction.Support.TransactionTemplate.Execute(TransactionDelegate)"/>
/// supporting transactional code wrapped in the delegate instance. It handles the
/// transaction lifecycle and possible exceptions such that neither the delegate
/// implementation nor the calling code needs to explicitly handle transactions.
/// </p>
/// <p>
/// Can be used within a service implementation via direct instantiation with
/// a transaction manager reference, or get prepared in an application context
/// and given to services as object reference.
/// </p>
/// <note>
/// The transaction manager should always be configured as an object in the application
/// context, in the first case given to the service directly, in the second case to the
/// prepared template.
/// </note>
/// <p>
/// Supports setting the propagation behavior and the isolation level by name,
/// for convenient configuration in context definitions.
/// </p>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <author>Mark Pollack (.NET)</author>
/// <author>Griffin Caprio (.NET)</author>
public class TransactionTemplate : DefaultTransactionDefinition, ITransactionOperations, IInitializingObject
{
private IPlatformTransactionManager _platformTransactionManager;
#region Logging Definition
protected readonly ILog log = LogManager.GetLogger(typeof(TransactionTemplate));
#endregion
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Transaction.Support.TransactionTemplate"/> class.
/// </summary>
/// <remarks>
/// <p>
/// Mainly targeted at configuration by an object factory.
/// </p>
/// <note>
/// The
/// <see cref="Spring.Transaction.Support.TransactionTemplate.PlatformTransactionManager"/>
/// property must be set before any calls to the
/// <see cref="Spring.Transaction.Support.TransactionTemplate.Execute(ITransactionCallback)"/>
/// or <see cref="Spring.Transaction.Support.TransactionTemplate.Execute(TransactionDelegate)"/>
/// method.
/// </note>
/// </remarks>
/// <seealso cref="Spring.Transaction.IPlatformTransactionManager"/>
public TransactionTemplate() {}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Transaction.Support.TransactionTemplate"/> class.
/// </summary>
/// <remarks>
/// <p>
/// Mainly targeted at configuration by an object factory.
/// </p>
/// </remarks>
/// <param name="platformTransactionManager">
/// The transaction management strategy to be used.
/// </param>
public TransactionTemplate( IPlatformTransactionManager platformTransactionManager )
{
_platformTransactionManager = platformTransactionManager;
}
/// <summary>
/// Gets and sets the <see cref="Spring.Transaction.IPlatformTransactionManager"/> to
/// be used.
/// </summary>
public IPlatformTransactionManager PlatformTransactionManager
{
get { return _platformTransactionManager; }
set { _platformTransactionManager = value; }
}
#region IInitializingObject Members
/// <summary>
/// Ensures that the
/// <see cref="Spring.Transaction.Support.TransactionTemplate.PlatformTransactionManager"/>
/// has been set.
/// </summary>
public void AfterPropertiesSet()
{
if ( _platformTransactionManager == null )
{
throw new ArgumentException( "IPlatformTransactionManager instance is required." );
}
}
#endregion
/// <summary>
/// Executes the the action specified by the given delegate callback within a transaction.
/// </summary>
/// <param name="transactionMethod">The delegate that specifies the transactional action.</param>
/// <returns>
/// A result object returned by the callback, or <code>null</code> if one
/// </returns>
/// <remarks>Allows for returning a result object created within the transaction, that is,
/// a domain object or a collection of domain objects. An exception thrown by the callback
/// is treated as a fatal exception that enforces a rollback. Such an exception gets
/// propagated to the caller of the template.
/// </remarks>
/// <exception cref="Spring.Transaction.TransactionException">
/// In case of initialization or system errors.
/// </exception>
public object Execute( TransactionDelegate transactionMethod )
{
ITransactionStatus status = _platformTransactionManager.GetTransaction( this );
object result;
try
{
result = transactionMethod( status );
}
catch ( Exception ex )
{
rollbackOnException( status, ex );
throw;
}
_platformTransactionManager.Commit( status );
return result;
}
/// <summary>
/// Executes the action specified by the given callback object within a transaction.
/// </summary>
/// <param name="action">The callback object that specifies the transactional action.</param>
/// <returns>
/// A result object returned by the callback, or <code>null</code> if one
/// </returns>
/// <remarks>Allows for returning a result object created within the transaction, that is,
/// a domain object or a collection of domain objects. An exception thrown by the callback
/// is treated as a fatal exception that enforces a rollback. Such an exception gets
/// propagated to the caller of the template.
/// </remarks>
/// <exception cref="Spring.Transaction.TransactionException">
/// In case of initialization or system errors.
/// </exception>
public object Execute(ITransactionCallback action)
{
ITransactionStatus status = _platformTransactionManager.GetTransaction( this );
object result;
try
{
result = action.DoInTransaction(status);
}
catch ( Exception ex )
{
rollbackOnException( status, ex );
throw;
}
_platformTransactionManager.Commit( status );
return result;
}
/// <summary>
/// Perform a rollback, handling rollback exceptions properly.
/// </summary>
/// <param name="status">The object representing the transaction.</param>
/// <param name="exception">The thrown application exception or error.</param>
private void rollbackOnException( ITransactionStatus status, Exception exception )
{
if (log.IsDebugEnabled)
{
log.Debug("Initiating transaction rollback on application exception", exception);
}
try
{
_platformTransactionManager.Rollback( status );
}
catch ( Exception ex )
{
log.Error("Application exception overridden by rollback exception", ex);
throw;
}
}
}
}
|