diff --git a/src/Spring/Spring.Data/Data/Common/DbProviderFactoryObject.cs b/src/Spring/Spring.Data/Data/Common/DbProviderFactoryObject.cs
index 38e9ddf5..e6831338 100644
--- a/src/Spring/Spring.Data/Data/Common/DbProviderFactoryObject.cs
+++ b/src/Spring/Spring.Data/Data/Common/DbProviderFactoryObject.cs
@@ -1,153 +1,177 @@
-#region License
-
-/*
- * Copyright © 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
-{
- ///
- /// A implementation that
- /// creates instances of the class.
- ///
- /// Typically used as a convenience for retrieving shared
- /// in a Spring XML configuration file as compared to
- /// using explict factory method support.
- ///
- public class DbProviderFactoryObject : IFactoryObject, IInitializingObject
- {
- private string provider;
- private string connectionString;
- private IDbProvider dbProvider;
-
- ///
- /// Creates a new instance of the class.
- ///
- public DbProviderFactoryObject()
- {
- }
-
- ///
- /// Return an instance of and IDbProvider as configured by this factory
- /// managed by this factory.
- ///
- ///
- /// The same (singleton) instance of the IDbProvider managed by
- /// this factory.
- ///
- ///
- ///
- /// If this method is being called in the context of an enclosing IoC container and
- /// returns , the IoC container will consider this factory
- /// object as not being fully initialized and throw a corresponding (and most
- /// probably fatal) exception.
- ///
- ///
- public object GetObject()
- {
- lock (this)
- {
- if (dbProvider == null)
- {
- ValidateProperties();
- dbProvider = DbProviderFactory.GetDbProvider(Provider);
- if (connectionString != null)
- {
- dbProvider.ConnectionString = this.connectionString;
- }
- }
-
- return dbProvider;
- }
- }
-
- ///
- /// Return the type of
- ///
- public Type ObjectType
- {
- get { return typeof (IDbProvider); }
- }
-
- ///
- /// Returns true, as the the object managed by this factory is a singleton.
- ///
- ///
- public bool IsSingleton
- {
- get { return true; }
- }
-
- ///
- /// Validates that the provider name is specified.
- ///
- ///
- /// Invoked by an
- /// after it has injected all of an object's dependencies.
- ///
- ///
- /// In the event of not setting the ProviderName.
- ///
- public void AfterPropertiesSet()
- {
- ValidateProperties();
- }
-
- ///
- /// Gets or sets the name of the database provider.
- ///
- /// The name of the database provider.
- public string Provider
- {
- get { return provider; }
- set
- {
- AssertUtils.ArgumentHasText(value, "The 'ProviderName' property must have a value.");
- provider = value.Trim();
- }
- }
-
- ///
- /// Gets or sets the connection string.
- ///
- /// The connection string.
- public string ConnectionString
- {
- get { return connectionString; }
- set
- {
- AssertUtils.ArgumentHasText(value, "The 'ConnectionString' property must have a value.");
- connectionString = value.Trim();
- }
- }
-
- ///
- /// Validates the properties.
- ///
- private void ValidateProperties()
- {
- if (StringUtils.IsNullOrEmpty(Provider))
- {
- throw new ArgumentException("The 'DbProviderName' property has not been set.");
- }
- }
- }
+#region License
+
+/*
+ * Copyright © 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
+{
+ ///
+ /// A implementation that
+ /// creates instances of the class.
+ ///
+ /// Typically used as a convenience for retrieving shared
+ /// in a Spring XML configuration file as compared to
+ /// using explict factory method support.
+ ///
+ public class DbProviderFactoryObject : IFactoryObject, IInitializingObject
+ {
+ #region Fields
+
+ private string provider;
+ private string connectionString;
+ private IDbProvider dbProvider;
+
+ #endregion
+
+ #region Constructor
+
+ ///
+ /// Creates a new instance of the class.
+ ///
+ public DbProviderFactoryObject()
+ {
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets the name of the database provider.
+ ///
+ /// The name of the database provider.
+ public string Provider
+ {
+ get { return provider; }
+ set
+ {
+ AssertUtils.ArgumentHasText(value, "The 'ProviderName' property must have a value.");
+ provider = value.Trim();
+ }
+ }
+
+ ///
+ /// Gets or sets the connection string.
+ ///
+ /// The connection string.
+ public string ConnectionString
+ {
+ get { return connectionString; }
+ set
+ {
+ AssertUtils.ArgumentHasText(value, "The 'ConnectionString' property must have a value.");
+ connectionString = value.Trim();
+ }
+ }
+
+ #endregion
+
+ #region IFactoryObject Members
+
+ ///
+ /// Return an instance of and IDbProvider as configured by this factory
+ /// managed by this factory.
+ ///
+ ///
+ /// The same (singleton) instance of the IDbProvider managed by
+ /// this factory.
+ ///
+ ///
+ ///
+ /// If this method is being called in the context of an enclosing IoC container and
+ /// returns , the IoC container will consider this factory
+ /// object as not being fully initialized and throw a corresponding (and most
+ /// probably fatal) exception.
+ ///
+ ///
+ public object GetObject()
+ {
+ lock (this)
+ {
+ if (dbProvider == null)
+ {
+ ValidateProperties();
+ dbProvider = DbProviderFactory.GetDbProvider(Provider);
+ if (connectionString != null)
+ {
+ dbProvider.ConnectionString = this.connectionString;
+ }
+ }
+
+ return dbProvider;
+ }
+ }
+
+ ///
+ /// Return the type of
+ ///
+ public Type ObjectType
+ {
+ get { return typeof (IDbProvider); }
+ }
+
+ ///
+ /// Returns true, as the the object managed by this factory is a singleton.
+ ///
+ ///
+ public bool IsSingleton
+ {
+ get { return true; }
+ }
+
+ #endregion
+
+ #region IInitializingObject Memebers
+
+ ///
+ /// Validates that the provider name is specified.
+ ///
+ ///
+ /// Invoked by an
+ /// after it has injected all of an object's dependencies.
+ ///
+ ///
+ /// In the event of not setting the ProviderName.
+ ///
+ public void AfterPropertiesSet()
+ {
+ ValidateProperties();
+ }
+
+ #endregion
+
+ #region Private Memebers
+
+ ///
+ /// Validates the properties.
+ ///
+ private void ValidateProperties()
+ {
+ if (StringUtils.IsNullOrEmpty(Provider))
+ {
+ throw new ArgumentException("The 'DbProviderName' property has not been set.");
+ }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs b/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs
index f5a1c5fb..83620328 100644
--- a/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs
+++ b/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs
@@ -36,13 +36,15 @@ namespace Spring.Data
///
///
/// 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
- /// LogicalThreadContext.SetData("dbProviderName", "database1ProviderName"). The value
+ /// is "dbProviderName". Once the target dbprovider name is known, set the name via a call to
+ /// LogicalThreadContext.SetData(MultiDelegatingDbProvider.CURRENT_DBPROVIDER_SLOTNAME, "database1ProviderName"). The value
/// "database1ProviderName" must match a key in the provided TargetDbProviders dictionary.
///
/// Mark Pollack
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
///
/// The corresonding IDbProvider.
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'");
+ }
+
+ ///
+ /// Convenience method to sets the name of the DbProvider that will be used for the
+ /// the current thread's procesing.
+ ///
+ /// The name of the DbProvider to use for the current threads processing.
+ public static string CurrentDbProviderName
+ {
+ set
+ {
+ LogicalThreadContext.SetData(CURRENT_DBPROVIDER_SLOTNAME, value);
+ }
}
}
}
diff --git a/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs b/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs
index 388290e7..d4b84b9d 100644
--- a/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs
+++ b/src/Spring/Spring.Data/Data/Core/AdoPlatformTransactionManager.cs
@@ -37,7 +37,7 @@ namespace Spring.Data.Core
/// interface.
///
/// Mark Pollack (.NET)
- 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");
}
+ }
+
+ ///
+ /// Gets the resource factory that this transaction manager operates on,
+ /// For the AdoPlatformTransactionManager this is the DbProvider
+ ///
+ /// The DbProvider.
+ public object ResourceFactory
+ {
+ get
+ {
+ return dbProvider;
+ }
}
}
}
diff --git a/src/Spring/Spring.Data/Spring.Data.2005.csproj b/src/Spring/Spring.Data/Spring.Data.2005.csproj
index 06d2bfdc..d205235d 100644
--- a/src/Spring/Spring.Data/Spring.Data.2005.csproj
+++ b/src/Spring/Spring.Data/Spring.Data.2005.csproj
@@ -257,6 +257,7 @@
+
diff --git a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAspectSupport.cs b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAspectSupport.cs
index e0eab33d..be827cbe 100644
--- a/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAspectSupport.cs
+++ b/src/Spring/Spring.Data/Transaction/Interceptor/TransactionAspectSupport.cs
@@ -336,8 +336,9 @@ namespace Spring.Transaction.Interceptor
/// Transaction Info for declarative transaction management.
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);
diff --git a/src/Spring/Spring.Data/Transaction/Support/AbstractPlatformTransactionManager.cs b/src/Spring/Spring.Data/Transaction/Support/AbstractPlatformTransactionManager.cs
index 7acfc1a2..49374a53 100644
--- a/src/Spring/Spring.Data/Transaction/Support/AbstractPlatformTransactionManager.cs
+++ b/src/Spring/Spring.Data/Transaction/Support/AbstractPlatformTransactionManager.cs
@@ -232,7 +232,7 @@ namespace Spring.Transaction.Support
#endregion
- #region Abstract Methods
+ #region Protected Methods
///
/// Return the current transaction object.
@@ -412,7 +412,36 @@ namespace Spring.Transaction.Support
protected virtual bool UseSavepointForNestedTransaction()
{
return true;
- }
+ }
+
+ ///
+ /// Register the given list of transaction synchronizations with the existing transaction.
+ ///
+ ///
+ /// 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.
+ ///
+ /// The default implementation simply invokes the AfterCompletion 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.
+ ///
+ ///
+ /// The transaction transaction object returned by DoGetTransaction.
+ /// The lList of TransactionSynchronization objects.
+ /// In case of errors
+ ///
+ ///
+ ///
+ 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);
+ }
///
/// 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);
}
}
}
diff --git a/src/Spring/Spring.Data/Transaction/Support/IResourceTransactionManager.cs b/src/Spring/Spring.Data/Transaction/Support/IResourceTransactionManager.cs
new file mode 100644
index 00000000..a04e7176
--- /dev/null
+++ b/src/Spring/Spring.Data/Transaction/Support/IResourceTransactionManager.cs
@@ -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
+{
+ ///
+ /// Extension of the
+ /// 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.
+ ///
+ ///
+ /// 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.
+ ///
+ /// Juergen Hoeller
+ /// Mark Pollack
+ public interface IResourceTransactionManager : IPlatformTransactionManager
+ {
+ ///
+ /// Gets the resource factory that this transaction manager operates on,
+ /// e.g. a IDbProvider or a Hibernate ISessionFactory.
+ ///
+ /// The resource factory.
+ object ResourceFactory
+ {
+ get;
+ }
+ }
+}
\ No newline at end of file