diff --git a/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs b/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs index ae47e2c4..1090bebe 100644 --- a/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs +++ b/src/Spring/Spring.Data/Data/Common/MultiDelegatingDbProvider.cs @@ -21,14 +21,14 @@ using System; using System.Collections; using System.Data; +using Common.Logging; using Spring.Collections; using Spring.Dao; -using Spring.Data.Common; using Spring.Objects.Factory; using Spring.Threading; -namespace Spring.Data +namespace Spring.Data.Common { /// /// A wrapper implementation for IDbProvider such that multiple DbProvider instances can be @@ -49,6 +49,12 @@ namespace Spring.Data private IDictionary targetDbProviders = new SynchronizedHashtable(); + #region Logging Definition + + private static readonly ILog LOG = LogManager.GetLogger(typeof(MultiDelegatingDbProvider)); + + #endregion + #region Constructors /// /// Initializes a new instance of the class. @@ -102,12 +108,12 @@ namespace Spring.Data { if (! entry.Key.GetType().Equals(typeof(string))) { - throw new ArgumentException("Key identifying target IDbProvider in TargetDbProviders dictionary property is required to be of type string. Key = " + entry.Key); + throw new ArgumentException("Key identifying target IDbProvider in TargetDbProviders dictionary property is required to be of type string. Key = [" + entry.Key + "], type = [" + entry.Key.GetType() + "]"); } IDbProvider targetProvider = entry.Value as IDbProvider; if (targetProvider == null) { - throw new ArgumentException("Value in TargetDbProviders dictionary is not of type IDbProvider."); + throw new ArgumentException("Value in TargetDbProviders dictionary is not of type IDbProvider. Type = [" + entry.Value.GetType() + "]"); } } } @@ -268,16 +274,26 @@ namespace Spring.Data protected virtual IDbProvider GetTargetProvider() { string dbProviderName = (string)LogicalThreadContext.GetData(CURRENT_DBPROVIDER_SLOTNAME); - if (targetDbProviders.Contains(dbProviderName)) + if (dbProviderName != null && targetDbProviders.Contains(dbProviderName)) { return (IDbProvider)targetDbProviders[dbProviderName]; } + //Fall back to default if available if (defaultDbProvider != null) { + if (LOG.IsDebugEnabled) + { + LOG.Debug("No DbProvider defined in thread local storage, falling back to use DefaultDbProvider."); + } return defaultDbProvider; } + if (dbProviderName == null) + { + throw new InvalidDataAccessApiUsageException( + "No provider name found in thread local storage. Consider setting the property DefaultDbProvider to fallback to a default value."); + } throw new InvalidDataAccessApiUsageException("'" + dbProviderName + "'" - + "was not under the thread local key 'dbProviderName' and no default IDbProvider was set."); + + " was not under the thread local key 'dbProviderName' and no default IDbProvider was set."); } /// diff --git a/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs b/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs index 547fa746..025acfa2 100644 --- a/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs @@ -20,11 +20,9 @@ using System; using System.Globalization; -using System.Reflection; using System.Threading; using NUnit.Framework; using Spring.Context; -using Spring.Core.IO; using Spring.Threading; using Spring.Util; diff --git a/test/Spring/Spring.Data.Tests/Data/Common/MultiDelegatingDbProviderTests.cs b/test/Spring/Spring.Data.Tests/Data/Common/MultiDelegatingDbProviderTests.cs new file mode 100644 index 00000000..02ff9d54 --- /dev/null +++ b/test/Spring/Spring.Data.Tests/Data/Common/MultiDelegatingDbProviderTests.cs @@ -0,0 +1,162 @@ +#region License + +/* + * Copyright 2002-2009 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 NUnit.Framework; +using Spring.Dao; +using Spring.Objects; + +namespace Spring.Data.Common +{ + /// + /// Test for MultiDelegatingDbProvider + /// + /// Mark Pollack (.NET) + [TestFixture] + public class MultiDelegatingDbProviderTests + { + [Test] + [ExpectedException(typeof(ArgumentException))] + public void CreationWhenNoRequiredPropertiesSet() + { + MultiDelegatingDbProvider dbProvider = new MultiDelegatingDbProvider(); + dbProvider.AfterPropertiesSet(); + } + + + + [Test] + public void CreationWithWrongTypeDictionaryKeys() + { + try + { + MultiDelegatingDbProvider dbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add(1, "bar"); + dbProvider.TargetDbProviders = targetDbProviders; + dbProvider.AfterPropertiesSet(); + Assert.Fail("Should have thrown ArgumentException"); + } catch (ArgumentException ex) + { + Assert.AreEqual("Key identifying target IDbProvider in TargetDbProviders dictionary property is required to be of type string. Key = [1], type = [System.Int32]", ex.Message); + } + } + + [Test] + public void CreationWithWrongTypeDictionaryValues() + { + try + { + MultiDelegatingDbProvider dbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("foo", 1); + dbProvider.TargetDbProviders = targetDbProviders; + dbProvider.AfterPropertiesSet(); + Assert.Fail("Should have thrown ArgumentException"); + } + catch (ArgumentException ex) + { + Assert.AreEqual("Value in TargetDbProviders dictionary is not of type IDbProvider. Type = [System.Int32]", ex.Message); + } + } + + [Test] + public void NoDefaultProvided() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider.ConnectionString = "connString1"; + MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("db1", provider); + multiDbProvider.TargetDbProviders = targetDbProviders; + multiDbProvider.AfterPropertiesSet(); + try + { + Assert.AreEqual("connString1", multiDbProvider.ConnectionString); + Assert.Fail("InvalidDataAccessApiUsageException should have been thrown"); + } catch (InvalidDataAccessApiUsageException exception) + { + Assert.AreEqual("No provider name found in thread local storage. Consider setting the property DefaultDbProvider to fallback to a default value.", exception.Message); + } + } + + [Test] + public void NoMatchingProviderDefinedInThreadLocalStorage() + { + IDbProvider provider = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider.ConnectionString = "connString1"; + MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("db1", provider); + multiDbProvider.TargetDbProviders = targetDbProviders; + multiDbProvider.AfterPropertiesSet(); + try + { + MultiDelegatingDbProvider.CurrentDbProviderName = "db2"; + Assert.AreEqual("connString1", multiDbProvider.ConnectionString); + Assert.Fail("InvalidDataAccessApiUsageException should have been thrown"); + } + catch (InvalidDataAccessApiUsageException exception) + { + Assert.AreEqual("'db2' was not under the thread local key 'dbProviderName' and no default IDbProvider was set.", exception.Message); + } + } + + [Test] + public void MatchingProviderDefinedInThreadLocalStorage() + { + IDbProvider provider1 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider1.ConnectionString = "connString1"; + IDbProvider provider2 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider2.ConnectionString = "connString2"; + MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("db1", provider1); + targetDbProviders.Add("db2", provider2); + multiDbProvider.DefaultDbProvider = provider1; + multiDbProvider.TargetDbProviders = targetDbProviders; + multiDbProvider.AfterPropertiesSet(); + + MultiDelegatingDbProvider.CurrentDbProviderName = "db2"; + Assert.AreEqual("connString2", multiDbProvider.ConnectionString); + } + + [Test] + public void FallbackToDefault() + { + IDbProvider provider1 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider1.ConnectionString = "connString1"; + IDbProvider provider2 = DbProviderFactory.GetDbProvider("System.Data.SqlClient"); + provider2.ConnectionString = "connString2"; + MultiDelegatingDbProvider multiDbProvider = new MultiDelegatingDbProvider(); + IDictionary targetDbProviders = new Hashtable(); + targetDbProviders.Add("db1", provider1); + targetDbProviders.Add("db2", provider2); + multiDbProvider.DefaultDbProvider = provider1; + multiDbProvider.TargetDbProviders = targetDbProviders; + multiDbProvider.AfterPropertiesSet(); + + MultiDelegatingDbProvider.CurrentDbProviderName = "db314"; + Assert.AreEqual("connString1", multiDbProvider.ConnectionString); + } + } + +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.Tests/Spring.Data.Tests.2008.csproj b/test/Spring/Spring.Data.Tests/Spring.Data.Tests.2008.csproj index f322a9e3..43a30026 100644 --- a/test/Spring/Spring.Data.Tests/Spring.Data.Tests.2008.csproj +++ b/test/Spring/Spring.Data.Tests/Spring.Data.Tests.2008.csproj @@ -177,6 +177,7 @@ +