Add IResourceTransactionManager to indicate which tx managers operate on a since tx resource.
Thread local storage slot name for MultiDelegatingDbProvider generated using Spring.Util.UniqueKey. Some simple code cleanup.
This commit is contained in:
@@ -1,153 +1,177 @@
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2006 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 Spring.Objects.Factory;
|
||||
using Spring.Util;
|
||||
|
||||
namespace Spring.Data.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="Spring.Objects.Factory.IFactoryObject"/> implementation that
|
||||
/// creates instances of the <see cref="IDbProvider"/> class.
|
||||
/// </summary>
|
||||
/// <remarks>Typically used as a convenience for retrieving shared
|
||||
/// <see cref="IDbProvider"/> in a Spring XML configuration file as compared to
|
||||
/// using explict factory method support.
|
||||
/// </remarks>
|
||||
public class DbProviderFactoryObject : IFactoryObject, IInitializingObject
|
||||
{
|
||||
private string provider;
|
||||
private string connectionString;
|
||||
private IDbProvider dbProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="DbProviderFactoryObject"/> class.
|
||||
/// </summary>
|
||||
public DbProviderFactoryObject()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return an instance of and IDbProvider as configured by this factory
|
||||
/// managed by this factory.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The same (singleton) instance of the IDbProvider managed by
|
||||
/// this factory.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <note type="caution">
|
||||
/// If this method is being called in the context of an enclosing IoC container and
|
||||
/// returns <see langword="null"/>, the IoC container will consider this factory
|
||||
/// object as not being fully initialized and throw a corresponding (and most
|
||||
/// probably fatal) exception.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
public object GetObject()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (dbProvider == null)
|
||||
{
|
||||
ValidateProperties();
|
||||
dbProvider = DbProviderFactory.GetDbProvider(Provider);
|
||||
if (connectionString != null)
|
||||
{
|
||||
dbProvider.ConnectionString = this.connectionString;
|
||||
}
|
||||
}
|
||||
|
||||
return dbProvider;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the type of <see cref="IDbProvider"/>
|
||||
/// </summary>
|
||||
public Type ObjectType
|
||||
{
|
||||
get { return typeof (IDbProvider); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true, as the the object managed by this factory is a singleton.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public bool IsSingleton
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that the provider name is specified.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
|
||||
/// after it has injected all of an object's dependencies.
|
||||
/// </remarks>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// In the event of not setting the ProviderName.
|
||||
/// </exception>
|
||||
public void AfterPropertiesSet()
|
||||
{
|
||||
ValidateProperties();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the database provider.
|
||||
/// </summary>
|
||||
/// <value>The name of the database provider.</value>
|
||||
public string Provider
|
||||
{
|
||||
get { return provider; }
|
||||
set
|
||||
{
|
||||
AssertUtils.ArgumentHasText(value, "The 'ProviderName' property must have a value.");
|
||||
provider = value.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the connection string.
|
||||
/// </summary>
|
||||
/// <value>The connection string.</value>
|
||||
public string ConnectionString
|
||||
{
|
||||
get { return connectionString; }
|
||||
set
|
||||
{
|
||||
AssertUtils.ArgumentHasText(value, "The 'ConnectionString' property must have a value.");
|
||||
connectionString = value.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the properties.
|
||||
/// </summary>
|
||||
private void ValidateProperties()
|
||||
{
|
||||
if (StringUtils.IsNullOrEmpty(Provider))
|
||||
{
|
||||
throw new ArgumentException("The 'DbProviderName' property has not been set.");
|
||||
}
|
||||
}
|
||||
}
|
||||
#region License
|
||||
|
||||
/*
|
||||
* Copyright <20> 2002-2006 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 Spring.Objects.Factory;
|
||||
using Spring.Util;
|
||||
|
||||
namespace Spring.Data.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="Spring.Objects.Factory.IFactoryObject"/> implementation that
|
||||
/// creates instances of the <see cref="IDbProvider"/> class.
|
||||
/// </summary>
|
||||
/// <remarks>Typically used as a convenience for retrieving shared
|
||||
/// <see cref="IDbProvider"/> in a Spring XML configuration file as compared to
|
||||
/// using explict factory method support.
|
||||
/// </remarks>
|
||||
public class DbProviderFactoryObject : IFactoryObject, IInitializingObject
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private string provider;
|
||||
private string connectionString;
|
||||
private IDbProvider dbProvider;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="DbProviderFactoryObject"/> class.
|
||||
/// </summary>
|
||||
public DbProviderFactoryObject()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the database provider.
|
||||
/// </summary>
|
||||
/// <value>The name of the database provider.</value>
|
||||
public string Provider
|
||||
{
|
||||
get { return provider; }
|
||||
set
|
||||
{
|
||||
AssertUtils.ArgumentHasText(value, "The 'ProviderName' property must have a value.");
|
||||
provider = value.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the connection string.
|
||||
/// </summary>
|
||||
/// <value>The connection string.</value>
|
||||
public string ConnectionString
|
||||
{
|
||||
get { return connectionString; }
|
||||
set
|
||||
{
|
||||
AssertUtils.ArgumentHasText(value, "The 'ConnectionString' property must have a value.");
|
||||
connectionString = value.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IFactoryObject Members
|
||||
|
||||
/// <summary>
|
||||
/// Return an instance of and IDbProvider as configured by this factory
|
||||
/// managed by this factory.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The same (singleton) instance of the IDbProvider managed by
|
||||
/// this factory.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <note type="caution">
|
||||
/// If this method is being called in the context of an enclosing IoC container and
|
||||
/// returns <see langword="null"/>, the IoC container will consider this factory
|
||||
/// object as not being fully initialized and throw a corresponding (and most
|
||||
/// probably fatal) exception.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
public object GetObject()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (dbProvider == null)
|
||||
{
|
||||
ValidateProperties();
|
||||
dbProvider = DbProviderFactory.GetDbProvider(Provider);
|
||||
if (connectionString != null)
|
||||
{
|
||||
dbProvider.ConnectionString = this.connectionString;
|
||||
}
|
||||
}
|
||||
|
||||
return dbProvider;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the type of <see cref="IDbProvider"/>
|
||||
/// </summary>
|
||||
public Type ObjectType
|
||||
{
|
||||
get { return typeof (IDbProvider); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true, as the the object managed by this factory is a singleton.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public bool IsSingleton
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IInitializingObject Memebers
|
||||
|
||||
/// <summary>
|
||||
/// Validates that the provider name is specified.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
|
||||
/// after it has injected all of an object's dependencies.
|
||||
/// </remarks>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// In the event of not setting the ProviderName.
|
||||
/// </exception>
|
||||
public void AfterPropertiesSet()
|
||||
{
|
||||
ValidateProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Memebers
|
||||
|
||||
/// <summary>
|
||||
/// Validates the properties.
|
||||
/// </summary>
|
||||
private void ValidateProperties()
|
||||
{
|
||||
if (StringUtils.IsNullOrEmpty(Provider))
|
||||
{
|
||||
throw new ArgumentException("The 'DbProviderName' property has not been set.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -36,13 +36,15 @@ namespace Spring.Data
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The name of which DbProvider to use, as provided to the IDictionary property TargetDbProviders
|
||||
/// is "dbProviderName". Once the target dbprovider name is known, set the name via a call to
|
||||
/// <code>LogicalThreadContext.SetData("dbProviderName", "database1ProviderName")</code>. The value
|
||||
/// is "dbProviderName". Once the target dbprovider name is known, set the name via a call to
|
||||
/// <code>LogicalThreadContext.SetData(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME, "database1ProviderName")</code>. The value
|
||||
/// "database1ProviderName" must match a key in the provided TargetDbProviders dictionary.
|
||||
/// </remarks>
|
||||
/// <author>Mark Pollack</author>
|
||||
public class MultiDelegatingDbProvider : IDbProvider, IInitializingObject
|
||||
{
|
||||
{
|
||||
private static readonly string CURRENT_DBPROVIDER_SLOTNAME = Spring.Util.UniqueKey.GetTypeScopedString(typeof(MultiDelegatingDbProvider), "Current");
|
||||
|
||||
private IDictionary targetDbProviders = new SynchronizedHashtable();
|
||||
|
||||
#region Constructors
|
||||
@@ -253,14 +255,27 @@ namespace Spring.Data
|
||||
/// </summary>
|
||||
/// <returns>The corresonding IDbProvider.</returns>
|
||||
protected virtual IDbProvider GetTargetProvider()
|
||||
{
|
||||
string dbProviderName = (string)LogicalThreadContext.GetData("dbProviderName");
|
||||
{
|
||||
string dbProviderName = (string)LogicalThreadContext.GetData(CURRENT_DBPROVIDER_SLOTNAME);
|
||||
if (targetDbProviders.Contains(dbProviderName))
|
||||
{
|
||||
return (IDbProvider)targetDbProviders[dbProviderName];
|
||||
}
|
||||
throw new InvalidDataAccessApiUsageException("'" + dbProviderName + "'"
|
||||
+ "was not under the thread local key 'dbProviderName'");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience method to sets the name of the DbProvider that will be used for the
|
||||
/// the current thread's procesing.
|
||||
/// </summary>
|
||||
/// <value>The name of the DbProvider to use for the current threads processing.</value>
|
||||
public static string CurrentDbProviderName
|
||||
{
|
||||
set
|
||||
{
|
||||
LogicalThreadContext.SetData(CURRENT_DBPROVIDER_SLOTNAME, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Spring.Data.Core
|
||||
/// interface.
|
||||
/// </summary>
|
||||
/// <author>Mark Pollack (.NET)</author>
|
||||
public class AdoPlatformTransactionManager : AbstractPlatformTransactionManager, IInitializingObject
|
||||
public class AdoPlatformTransactionManager : AbstractPlatformTransactionManager, IResourceTransactionManager, IInitializingObject
|
||||
{
|
||||
|
||||
private IDbProvider dbProvider;
|
||||
@@ -425,6 +425,19 @@ namespace Spring.Data.Core
|
||||
{
|
||||
throw new ArgumentException("DbProvider is required");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the resource factory that this transaction manager operates on,
|
||||
/// For the AdoPlatformTransactionManager this is the DbProvider
|
||||
/// </summary>
|
||||
/// <value>The DbProvider.</value>
|
||||
public object ResourceFactory
|
||||
{
|
||||
get
|
||||
{
|
||||
return dbProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,6 +257,7 @@
|
||||
<Compile Include="Transaction\Support\AbstractPlatformTransactionManager.cs" />
|
||||
<Compile Include="Transaction\Support\DefaultTransactionDefinition.cs" />
|
||||
<Compile Include="Transaction\Support\DefaultTransactionStatus.cs" />
|
||||
<Compile Include="Transaction\Support\IResourceTransactionManager.cs" />
|
||||
<Compile Include="Transaction\Support\ISmartTransactionObject.cs" />
|
||||
<Compile Include="Transaction\Support\ITransactionCallback.cs" />
|
||||
<Compile Include="Transaction\Support\ITransactionOperations.cs" />
|
||||
|
||||
@@ -336,8 +336,9 @@ namespace Spring.Transaction.Interceptor
|
||||
/// <returns>Transaction Info for declarative transaction management.</returns>
|
||||
protected TransactionInfo CreateTransactionIfNecessary(ITransactionAttribute sourceAttr, string joinpointIdentification)
|
||||
{
|
||||
ITransactionAttribute txAttr = sourceAttr;
|
||||
|
||||
ITransactionAttribute txAttr = sourceAttr;
|
||||
|
||||
// If no name specified, apply method identification as transaction name.
|
||||
if (txAttr != null && txAttr.Name == null)
|
||||
{
|
||||
txAttr = new DelegatingTransactionAttributeWithName(txAttr, joinpointIdentification);
|
||||
|
||||
@@ -232,7 +232,7 @@ namespace Spring.Transaction.Support
|
||||
|
||||
#endregion
|
||||
|
||||
#region Abstract Methods
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Return the current transaction object.
|
||||
@@ -412,7 +412,36 @@ namespace Spring.Transaction.Support
|
||||
protected virtual bool UseSavepointForNestedTransaction()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register the given list of transaction synchronizations with the existing transaction.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Invoked when the control of the Spring transaction manager and thus all Spring
|
||||
/// transaction synchronizations end, without the transaction being completed yet. This
|
||||
/// is for example the case when participating in an existing System.Transactions or
|
||||
/// EnterpriseServices transaction invoked via their APIs.
|
||||
/// <para>
|
||||
/// The default implementation simply invokes the <code>AfterCompletion</code> methods
|
||||
/// immediately, passing in TransactionSynchronizationStatus.Unknown.
|
||||
/// This is the best we can do if there's no chance to determine the actual
|
||||
/// outcome of the outer transaction.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="transaction">The transaction transaction object returned by <code>DoGetTransaction</code>.</param>
|
||||
/// <param name="synchronizations">The lList of TransactionSynchronization objects.</param>
|
||||
/// <exception cref="TransactionException">In case of errors</exception>
|
||||
/// <seealso cref="InvokeAfterCompletion"/>
|
||||
/// <seealso cref="ITransactionSynchronization.AfterCompletion"/>
|
||||
/// <seealso cref="TransactionSynchronizationStatus.Unknown"/>
|
||||
protected virtual void RegisterAfterCompletionWithExistingTransaction(Object transaction, IList synchronizations)
|
||||
{
|
||||
|
||||
log.Debug("Cannot register Spring after-completion synchronization with existing transaction - " +
|
||||
"processing Spring after-completion callbacks immediately, with outcome status 'unknown'");
|
||||
InvokeAfterCompletion(synchronizations, TransactionSynchronizationStatus.Unknown);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup resources after transaction completion.
|
||||
@@ -1129,7 +1158,8 @@ namespace Spring.Transaction.Support
|
||||
else
|
||||
{
|
||||
//TODO investigate parallel of JTA/System.Txs
|
||||
log.Info("Transaction controlled outside of spring tx manager.");
|
||||
log.Info("Transaction controlled outside of spring tx manager.");
|
||||
RegisterAfterCompletionWithExistingTransaction(status.Transaction, synchronizations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#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
|
||||
|
||||
namespace Spring.Transaction.Support
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension of the <see cref="IPlatformTransactionManager"/>
|
||||
/// interface, indicating a native resource transaction manager, operating on a single
|
||||
/// target resource. Such transaction managers differ from DTC based transaction managers in
|
||||
/// that they do not use transaction enlistment for an open number of resources but
|
||||
/// rather focus on leveraging the native power and simplicity of a single target resource.
|
||||
/// </summary>
|
||||
/// <para>
|
||||
/// This interface is mainly used for abstract introspection of a transaction manager,
|
||||
/// giving clients a hint on what kind of transaction manager they have been given
|
||||
/// and on what concrete resource the transaction manager is operating on.
|
||||
/// </para>
|
||||
/// <author>Juergen Hoeller</author>
|
||||
/// <author>Mark Pollack</author>
|
||||
public interface IResourceTransactionManager : IPlatformTransactionManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the resource factory that this transaction manager operates on,
|
||||
/// e.g. a IDbProvider or a Hibernate ISessionFactory.
|
||||
/// </summary>
|
||||
/// <value>The resource factory.</value>
|
||||
object ResourceFactory
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user