#if NET_2_0
#region License
/*
* Copyright 2007 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.Transactions;
using Spring.Data.Support;
using Spring.Objects.Factory;
using Spring.Transaction;
using Spring.Transaction.Support;
namespace Spring.Data.Core{
/// <summary>
/// TransactionManager that uses TransactionScope provided by System.Transactions.
/// </summary>
/// <author>Mark Pollack (.NET)</author>
public class TxScopeTransactionManager : AbstractPlatformTransactionManager, IInitializingObject
{
private readonly ITransactionScopeAdapter txAdapter;
/// <summary>
/// Initializes a new instance of the <see cref="TxScopeTransactionManager"/> class.
/// </summary>
public TxScopeTransactionManager()
{
// noop
}
/// <summary>
/// Initializes a new instance of the <see cref="TxScopeTransactionManager"/> class.
/// </summary>
/// <remarks>This is indented only for unit testing purposes and should not be
/// called by production application code.</remarks>
/// <param name="txAdapter">The tx adapter.</param>
public TxScopeTransactionManager(ITransactionScopeAdapter txAdapter)
{
this.txAdapter = txAdapter;
}
#region IInitializingObject Members
/// <summary>
/// No-op initialization
/// </summary>
public void AfterPropertiesSet()
{
// placeholder for more advanced configurations.
}
#endregion
protected override object DoGetTransaction()
{
PromotableTxScopeTransactionObject txObject = new PromotableTxScopeTransactionObject();
if (txAdapter != null)
{
txObject.TxScopeAdapter = txAdapter;
}
return txObject;
}
protected override bool IsExistingTransaction(object transaction)
{
PromotableTxScopeTransactionObject txObject =
(PromotableTxScopeTransactionObject)transaction;
return txObject.TxScopeAdapter.IsExistingTransaction;
}
protected override void DoBegin(object transaction, Spring.Transaction.ITransactionDefinition definition)
{
PromotableTxScopeTransactionObject txObject =
(PromotableTxScopeTransactionObject)transaction;
try
{
DoTxScopeBegin(txObject, definition);
}
catch (Exception e)
{
throw new CannotCreateTransactionException("Transaction Scope failure on begin", e);
}
}
protected override object DoSuspend(object transaction)
{
// Passing the current TxScopeAdapter as the 'suspended resource', even though it is not used just to avoid passing null
// TxScopeTransactionManager is not binding any resources to the local thread, instead delegating to
// System.Transactions to handle thread local resources.
PromotableTxScopeTransactionObject txMgrStateObject = (PromotableTxScopeTransactionObject) transaction;
return txMgrStateObject.TxScopeAdapter;
}
protected override void DoResume(object transaction, object suspendedResources)
{
}
protected override void DoCommit(DefaultTransactionStatus status)
{
PromotableTxScopeTransactionObject txObject =
(PromotableTxScopeTransactionObject)status.Transaction;
try
{
txObject.TxScopeAdapter.Complete();
txObject.TxScopeAdapter.Dispose();
}
catch (TransactionAbortedException ex)
{
throw new UnexpectedRollbackException("Transaction unexpectedly rolled back (maybe due to a timeout)", ex);
}
catch (TransactionInDoubtException ex)
{
throw new HeuristicCompletionException(TransactionOutcomeState.Unknown, ex);
}
catch (Exception ex)
{
throw new TransactionSystemException("Failure on Transaction Scope Commit", ex);
}
}
protected override void DoRollback(DefaultTransactionStatus status)
{
PromotableTxScopeTransactionObject txObject =
(PromotableTxScopeTransactionObject)status.Transaction;
try
{
txObject.TxScopeAdapter.Dispose();
}
catch (Exception e)
{
throw new Spring.Transaction.TransactionSystemException("Failure on Transaction Scope rollback.", e);
}
}
protected override void DoSetRollbackOnly(DefaultTransactionStatus status)
{
if (status.Debug)
{
log.Debug("Setting transaction rollback-only");
}
try
{
System.Transactions.Transaction.Current.Rollback();
} catch (Exception ex)
{
throw new TransactionSystemException("Failure on System.Transactions.Transaction.Current.Rollback", ex);
}
}
protected override bool ShouldCommitOnGlobalRollbackOnly
{
get { return true; }
}
private void DoTxScopeBegin(PromotableTxScopeTransactionObject txObject,
Spring.Transaction.ITransactionDefinition definition)
{
TransactionScopeOption txScopeOption = CreateTransactionScopeOptions(definition);
TransactionOptions txOptions = CreateTransactionOptions(definition);
txObject.TxScopeAdapter.CreateTransactionScope(txScopeOption, txOptions, definition.EnterpriseServicesInteropOption);
}
private static TransactionOptions CreateTransactionOptions(ITransactionDefinition definition)
{
TransactionOptions txOptions = new TransactionOptions();
switch (definition.TransactionIsolationLevel )
{
case System.Data.IsolationLevel.Chaos:
txOptions.IsolationLevel = IsolationLevel.Chaos;
break;
case System.Data.IsolationLevel.ReadCommitted:
txOptions.IsolationLevel = IsolationLevel.ReadCommitted;
break;
case System.Data.IsolationLevel.ReadUncommitted:
txOptions.IsolationLevel = IsolationLevel.ReadUncommitted;
break;
case System.Data.IsolationLevel.RepeatableRead:
txOptions.IsolationLevel = IsolationLevel.RepeatableRead;
break;
case System.Data.IsolationLevel.Serializable:
txOptions.IsolationLevel = IsolationLevel.Serializable;
break;
case System.Data.IsolationLevel.Snapshot:
txOptions.IsolationLevel = IsolationLevel.Snapshot;
break;
case System.Data.IsolationLevel.Unspecified:
txOptions.IsolationLevel = IsolationLevel.Unspecified;
break;
}
if (definition.TransactionTimeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
{
txOptions.Timeout = new TimeSpan(0, 0, definition.TransactionTimeout);
}
return txOptions;
}
private static TransactionScopeOption CreateTransactionScopeOptions(ITransactionDefinition definition)
{
TransactionScopeOption txScopeOption;
if (definition.PropagationBehavior == TransactionPropagation.Required)
{
txScopeOption = TransactionScopeOption.Required;
}
else if (definition.PropagationBehavior == TransactionPropagation.RequiresNew)
{
txScopeOption = TransactionScopeOption.RequiresNew;
}
else
{
throw new Spring.Transaction.TransactionSystemException("Transaction Propagation Behavior" +
definition.PropagationBehavior +
" not supported by TransactionScope. Use Required or RequiredNew");
}
return txScopeOption;
}
/// <summary>
/// The transaction resource object that encapsulates the state and functionality
/// contained in TransactionScope and Transaction.Current via the ITransactionScopeAdapter
/// property.
/// </summary>
public class PromotableTxScopeTransactionObject : ISmartTransactionObject
{
private ITransactionScopeAdapter txScopeAdapter;
/// <summary>
/// Initializes a new instance of the <see cref="PromotableTxScopeTransactionObject"/> class.
/// Will create an instance of <see cref="DefaultTransactionScopeAdapter"/>.
/// </summary>
public PromotableTxScopeTransactionObject()
{
txScopeAdapter = new DefaultTransactionScopeAdapter();
}
/// <summary>
/// Gets or sets the transaction scope adapter.
/// </summary>
/// <value>The transaction scope adapter.</value>
public ITransactionScopeAdapter TxScopeAdapter
{
get { return txScopeAdapter; }
set { txScopeAdapter = value; }
}
/// <summary>
/// Return whether the transaction is internally marked as rollback-only.
/// </summary>
/// <value></value>
/// <returns>True of the transaction is marked as rollback-only.</returns>
public bool RollbackOnly
{
get {
return txScopeAdapter.RollbackOnly;
}
}
}
}
}
#endif
|