From 733402b15faf20398116ad7edf271f542f84f2cf Mon Sep 17 00:00:00 2001 From: eeichinger Date: Sun, 20 Jul 2008 12:10:15 +0000 Subject: [PATCH] performance improvements fixed SynchronizedHashtable SPRNET-974: support private ctors with ConstructorNode SPRNET-975: treat alias case insensitive as well SPRNET-976: defered registering WebObjectFactory event handlers with VirtualEnvironment to when they are really needed SPRNET-977: avoid unnecessary usages of HttpContextSwitch in WebObjectFactory.ConfigureObject() added tests added VirtualEnvironment HttpSessionState/HttpRequest abstraction --- Spring.Net.2003.sln | 8 +- Spring.Net.2005.sln | 5 - .../Collections/CaseInsensitiveHashtable.cs | 87 + .../Collections/SynchronizedHashtable.cs | 761 ++-- .../Expressions/ConstructorNode.cs | 2 +- .../Objects/Factory/ObjectFactoryUtils.cs | 11 +- .../Factory/Support/AbstractObjectFactory.cs | 3926 +++++++++-------- .../Support/DefaultListableObjectFactory.cs | 1785 ++++---- .../Spring.Core/Spring.Core.2003.csproj | 5 + .../Spring.Core/Spring.Core.2005.csproj | 1 + .../Spring.Core/Util/DynamicCodeManager.cs | 285 +- .../Spring.Data/Spring.Data.2003.csproj | 25 + .../Context/Support/WebApplicationContext.cs | 3 +- .../Factory/Support/WebObjectFactory.cs | 41 +- src/Spring/Spring.Web/Spring.Web.2003.csproj | 5 + src/Spring/Spring.Web/Spring.Web.2005.csproj | 1 + src/Spring/Spring.Web/Util/ISessionState.cs | 48 + .../Spring.Web/Util/IVirtualEnvironment.cs | 10 + .../Spring.Web/Util/VirtualEnvironment.cs | 166 +- .../Web/Support/AbstractProcessHandler.cs | 3 +- .../Web/Support/PageHandlerFactory.cs | 2 +- .../CaseInsensitiveHashtableTests.cs | 116 + .../Collections/SynchronizedHashtableTests.cs | 94 +- .../Expressions/ConstructorNodeTests.cs | 112 + .../Factory/AbstractObjectFactoryTests.cs | 77 +- .../Xml/XmlListableObjectFactoryTests.cs | 6 +- .../Spring.Core.Tests.2003.csproj | 5 + .../Spring.Core.Tests.2005.csproj | 2 + .../Spring.Web.Tests.2003.csproj | 27 +- .../Spring.Web.Tests.2005.csproj | 1 + .../TestSupport/SessionMock.cs | 89 + .../Spring.Web.Tests/TestSupport/TestPage.cs | 3 +- .../TestSupport/TestWebContext.cs | 26 +- .../TestSupport/VirtualEnvironmentMock.cs | 19 +- .../Util/WebDIPerformanceTests.cs | 44 +- 35 files changed, 4386 insertions(+), 3415 deletions(-) create mode 100644 src/Spring/Spring.Core/Collections/CaseInsensitiveHashtable.cs create mode 100644 src/Spring/Spring.Web/Util/ISessionState.cs create mode 100644 test/Spring/Spring.Core.Tests/Collections/CaseInsensitiveHashtableTests.cs create mode 100644 test/Spring/Spring.Core.Tests/Expressions/ConstructorNodeTests.cs create mode 100644 test/Spring/Spring.Web.Tests/TestSupport/SessionMock.cs diff --git a/Spring.Net.2003.sln b/Spring.Net.2003.sln index a58ecbe4..3354399d 100644 --- a/Spring.Net.2003.sln +++ b/Spring.Net.2003.sln @@ -211,12 +211,12 @@ Global {E2689B4A-A951-420E-A274-BE5EBCD5F8D8}.Release-1.1.Build.0 = Release-1.1|.NET {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Debug.ActiveCfg = Debug|.NET {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Debug.Build.0 = Debug|.NET - {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Debug-1.1.ActiveCfg = Debug|.NET - {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Debug-1.1.Build.0 = Debug|.NET + {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Debug-1.1.ActiveCfg = Debug-1.1|.NET + {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Debug-1.1.Build.0 = Debug-1.1|.NET {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Release.ActiveCfg = Release|.NET {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Release.Build.0 = Release|.NET - {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Release-1.1.ActiveCfg = Release|.NET - {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Release-1.1.Build.0 = Release|.NET + {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Release-1.1.ActiveCfg = Release-1.1|.NET + {2E12AE3E-5690-46A5-9F89-80F1D3004ADB}.Release-1.1.Build.0 = Release-1.1|.NET {C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Debug.ActiveCfg = Debug|.NET {C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Debug.Build.0 = Debug|.NET {C17B27C2-4343-45BA-9A21-73C3CEC19BAD}.Debug-1.1.ActiveCfg = Debug|.NET diff --git a/Spring.Net.2005.sln b/Spring.Net.2005.sln index e6f4da04..28faa870 100644 --- a/Spring.Net.2005.sln +++ b/Spring.Net.2005.sln @@ -318,7 +318,6 @@ Global {130E1609-45A7-4F65-B112-105F2DD3E2CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {130E1609-45A7-4F65-B112-105F2DD3E2CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {130E1609-45A7-4F65-B112-105F2DD3E2CE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {130E1609-45A7-4F65-B112-105F2DD3E2CE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {130E1609-45A7-4F65-B112-105F2DD3E2CE}.Release|.NET.ActiveCfg = Release|Any CPU {130E1609-45A7-4F65-B112-105F2DD3E2CE}.Release|.NET.Build.0 = Release|Any CPU {130E1609-45A7-4F65-B112-105F2DD3E2CE}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -330,7 +329,6 @@ Global {4A07E150-ED90-407C-8CAD-4760444DDFD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4A07E150-ED90-407C-8CAD-4760444DDFD9}.Debug|Any CPU.Build.0 = Debug|Any CPU {4A07E150-ED90-407C-8CAD-4760444DDFD9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {4A07E150-ED90-407C-8CAD-4760444DDFD9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {4A07E150-ED90-407C-8CAD-4760444DDFD9}.Release|.NET.ActiveCfg = Release|Any CPU {4A07E150-ED90-407C-8CAD-4760444DDFD9}.Release|.NET.Build.0 = Release|Any CPU {4A07E150-ED90-407C-8CAD-4760444DDFD9}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -354,7 +352,6 @@ Global {94E4E1B4-D424-4EB9-BF34-2EE8CC3D7048}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {94E4E1B4-D424-4EB9-BF34-2EE8CC3D7048}.Debug|Any CPU.Build.0 = Debug|Any CPU {94E4E1B4-D424-4EB9-BF34-2EE8CC3D7048}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {94E4E1B4-D424-4EB9-BF34-2EE8CC3D7048}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {94E4E1B4-D424-4EB9-BF34-2EE8CC3D7048}.Release|.NET.ActiveCfg = Release|Any CPU {94E4E1B4-D424-4EB9-BF34-2EE8CC3D7048}.Release|.NET.Build.0 = Release|Any CPU {94E4E1B4-D424-4EB9-BF34-2EE8CC3D7048}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -397,7 +394,6 @@ Global {AEB1578C-9018-4D49-B440-789F38DD2F29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AEB1578C-9018-4D49-B440-789F38DD2F29}.Debug|Any CPU.Build.0 = Debug|Any CPU {AEB1578C-9018-4D49-B440-789F38DD2F29}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {AEB1578C-9018-4D49-B440-789F38DD2F29}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {AEB1578C-9018-4D49-B440-789F38DD2F29}.Release|.NET.ActiveCfg = Release|Any CPU {AEB1578C-9018-4D49-B440-789F38DD2F29}.Release|Any CPU.ActiveCfg = Release|Any CPU {AEB1578C-9018-4D49-B440-789F38DD2F29}.Release|Any CPU.Build.0 = Release|Any CPU @@ -407,7 +403,6 @@ Global {FA7A6931-7DBE-4A32-A312-51FAD2E80332}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FA7A6931-7DBE-4A32-A312-51FAD2E80332}.Debug|Any CPU.Build.0 = Debug|Any CPU {FA7A6931-7DBE-4A32-A312-51FAD2E80332}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {FA7A6931-7DBE-4A32-A312-51FAD2E80332}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {FA7A6931-7DBE-4A32-A312-51FAD2E80332}.Release|.NET.ActiveCfg = Release|Any CPU {FA7A6931-7DBE-4A32-A312-51FAD2E80332}.Release|Any CPU.ActiveCfg = Release|Any CPU {FA7A6931-7DBE-4A32-A312-51FAD2E80332}.Release|Any CPU.Build.0 = Release|Any CPU diff --git a/src/Spring/Spring.Core/Collections/CaseInsensitiveHashtable.cs b/src/Spring/Spring.Core/Collections/CaseInsensitiveHashtable.cs new file mode 100644 index 00000000..e838b3a8 --- /dev/null +++ b/src/Spring/Spring.Core/Collections/CaseInsensitiveHashtable.cs @@ -0,0 +1,87 @@ +using System.Collections; +using System.Globalization; +using Spring.Util; + +namespace Spring.Collections +{ + /// + /// Provides a performance improved hashtable with case-insensitive (string-only! based) key handling. + /// + /// Erich Eichinger + public class CaseInsensitiveHashtable : Hashtable + { + private readonly TextInfo _textInfo; + private readonly CompareInfo _compareInfo; + + /// + /// Creates a case-insensitive hashtable using . + /// + public CaseInsensitiveHashtable() + : this(null, CultureInfo.CurrentCulture) + {} + + /// + /// Creates a case-insensitive hashtable using the given . + /// + /// the to calculate the hashcode + public CaseInsensitiveHashtable(CultureInfo culture) + : this(null, culture) + {} + + /// + /// Creates a case-insensitive hashtable using the given , initially + /// populated with entries from another dictionary. + /// + /// the dictionary to copy entries from + /// the to calculate the hashcode + public CaseInsensitiveHashtable(IDictionary d, CultureInfo culture) + :this(d, culture.TextInfo, culture.CompareInfo) + {} + + /// + /// Creates a case-insensitive hashtable using the given , initially + /// populated with entries from another dictionary. + /// + protected CaseInsensitiveHashtable(IDictionary d, TextInfo textInfo, CompareInfo compareInfo) + { + AssertUtils.ArgumentNotNull(textInfo, "textInfo"); + _textInfo = textInfo; + _compareInfo = compareInfo; + + if (d != null) + { + IDictionaryEnumerator enumerator = d.GetEnumerator(); + while (enumerator.MoveNext()) + { + this.Add(enumerator.Key, enumerator.Value); + } + } + } + + /// + /// Calculate the hashcode of the given string key, using the configured culture. + /// + /// + /// + protected override int GetHash(object key) + { + return _textInfo.ToLower((string) key).GetHashCode(); + } + + /// + /// Compares two keys + /// + protected override bool KeyEquals(object item, object key) + { + return 0==_compareInfo.Compare((string) item, (string) key, CompareOptions.IgnoreCase); + } + + /// + /// Creates a shallow copy of the current instance. + /// + public override object Clone() + { + return new CaseInsensitiveHashtable(this, _textInfo, _compareInfo ); + } + } +} diff --git a/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs b/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs index c8ba2cc8..50e483c2 100644 --- a/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs +++ b/src/Spring/Spring.Core/Collections/SynchronizedHashtable.cs @@ -1,366 +1,397 @@ -#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 System.Collections; -using Spring.Util; - -namespace Spring.Collections -{ - /// - /// Synchronized that, unlike hashtable created - /// using method, synchronizes - /// reads from the underlying hashtable in addition to writes. - /// - /// - ///

- /// In addition to synchronizing reads, this implementation also fixes - /// IEnumerator/ICollection issue described at - /// http://msdn.microsoft.com/en-us/netframework/aa570326.aspx - /// (search for SynchronizedHashtable for issue description), by implementing - /// interface explicitly, and returns thread safe enumerator - /// implementations as well. - ///

- ///

- /// This class should be used whenever a truly synchronized - /// is needed. - ///

- ///
- /// Aleksandar Seovic - [Serializable] - public class SynchronizedHashtable : IDictionary, ICollection, IEnumerable, ICloneable - { - private readonly Hashtable _table; - - #region Constructors - - /// - /// Initializes a new instance of - /// - public SynchronizedHashtable() - { - this._table = new Hashtable(); - } - - /// - /// Initializes a new instance of , copying inital entries from . - /// - public SynchronizedHashtable(IDictionary dictionary) - { - AssertUtils.ArgumentNotNull(dictionary, "dictionary"); - this._table = new Hashtable(dictionary); - } - - #endregion - - #region Properties - - /// - ///Gets a value indicating whether the object is read-only. - /// - /// - ///true if the object is read-only; otherwise, false. - /// - public bool IsReadOnly - { - get - { - lock (SyncRoot) - { - return _table.IsReadOnly; - } - } - } - - /// - ///Gets a value indicating whether the object has a fixed size. - /// - /// - ///true if the object has a fixed size; otherwise, false. - /// - public bool IsFixedSize - { - get - { - lock (SyncRoot) - { - return _table.IsFixedSize; - } - } - } - - /// - ///Gets a value indicating whether access to the is synchronized (thread safe). - /// - /// - ///true if access to the is synchronized (thread safe); otherwise, false. - /// - public bool IsSynchronized - { - get { return true; } - } - - /// - ///Gets an object containing the keys of the object. - /// - /// - ///An object containing the keys of the object. - /// - public ICollection Keys - { - get - { - lock (SyncRoot) - { - return _table.Keys; - } - } - } - - /// - ///Gets an object containing the values in the object. - /// - /// - ///An object containing the values in the object. - /// - public ICollection Values - { - get - { - lock (SyncRoot) - { - return _table.Values; - } - } - } - - /// - ///Gets an object that can be used to synchronize access to the . - /// - /// - ///An object that can be used to synchronize access to the . - /// - public object SyncRoot - { - get { return _table.SyncRoot; } - } - - /// - ///Gets the number of elements contained in the . - /// - /// - ///The number of elements contained in the . - /// - public int Count - { - get - { - lock (SyncRoot) - { - return _table.Count; - } - } - } - - #endregion - - #region Methods - - /// - ///Adds an element with the provided key and value to the object. - /// - ///The to use as the value of the element to add. - ///The to use as the key of the element to add. - ///An element with the same key already exists in the object. - ///key is null. - ///The is read-only.-or- The has a fixed size. 2 - public void Add(object key, object value) - { - lock (SyncRoot) - { - _table.Add(key, value); - } - } - - /// - ///Removes all elements from the object. - /// - ///The object is read-only. 2 - public void Clear() - { - lock (SyncRoot) - { - _table.Clear(); - } - } - - /// - ///Creates a new object that is a copy of the current instance. - /// - /// - ///A new object that is a copy of this instance. - /// - public object Clone() - { - lock (SyncRoot) - { - return new SynchronizedHashtable(this); - } - } - - /// - ///Determines whether the object contains an element with the specified key. - /// - /// - ///true if the contains an element with the key; otherwise, false. - /// - ///The key to locate in the object. - ///key is null. 2 - public bool Contains(object key) - { - lock (SyncRoot) - { - return _table.Contains(key); - } - } - - /// - /// Returns, whether this contains an entry with the specified . - /// - ///The key to look for - ///, if this contains an entry with this - public bool ContainsKey(object key) - { - lock (SyncRoot) - { - return _table.ContainsKey(key); - } - } - - /// - /// Returns, whether this contains an entry with the specified . - /// - ///The valúe to look for - ///, if this contains an entry with this - public bool ContainsValue(object value) - { - lock (SyncRoot) - { - return _table.ContainsValue(value); - } - } - - /// - ///Copies the elements of the to an , starting at a particular index. - /// - ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - ///The zero-based index in array at which copying begins. - ///array is null. - ///The type of the source cannot be cast automatically to the type of the destination array. - ///index is less than zero. - ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. 2 - public void CopyTo(Array array, int index) - { - lock (SyncRoot) - { - _table.CopyTo(array, index); - } - } - - /// - ///Returns an object for the object. - /// - /// - ///An object for the object. - /// - public IDictionaryEnumerator GetEnumerator() - { - lock (SyncRoot) - { - return new SynchronizedDictionaryEnumerator(SyncRoot, _table.GetEnumerator()); - } - } - - /// - ///Removes the element with the specified key from the object. - /// - ///The key of the element to remove. - ///The object is read-only.-or- The has a fixed size. - ///key is null. 2 - public void Remove(object key) - { - lock (SyncRoot) - { - _table.Remove(key); - } - } - - #endregion - - #region IEnumerable implementation - - /// - ///Returns an enumerator that iterates through a collection. - /// - /// - ///An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - lock (SyncRoot) - { - return new SynchronizedEnumerator(SyncRoot, ((IEnumerable) _table).GetEnumerator()); - } - } - - #endregion - - #region Indexer - - /// - ///Gets or sets the element with the specified key. - /// - /// - ///The element with the specified key. - /// - ///The key of the element to get or set. - ///The property is set and the object is read-only.-or- The property is set, key does not exist in the collection, and the has a fixed size. - ///key is null. 2 - public object this[object key] - { - get - { - lock (SyncRoot) - { - return _table[key]; - } - } - set - { - lock (SyncRoot) - { - _table[key] = value; - } - } - } - - #endregion - } +#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 System.Collections; +using System.Collections.Specialized; +using Spring.Util; + +namespace Spring.Collections +{ + /// + /// Synchronized that, unlike hashtable created + /// using method, synchronizes + /// reads from the underlying hashtable in addition to writes. + /// + /// + ///

+ /// In addition to synchronizing reads, this implementation also fixes + /// IEnumerator/ICollection issue described at + /// http://msdn.microsoft.com/en-us/netframework/aa570326.aspx + /// (search for SynchronizedHashtable for issue description), by implementing + /// interface explicitly, and returns thread safe enumerator + /// implementations as well. + ///

+ ///

+ /// This class should be used whenever a truly synchronized + /// is needed. + ///

+ ///
+ /// Aleksandar Seovic + [Serializable] + public class SynchronizedHashtable : IDictionary, ICollection, IEnumerable, ICloneable + { + private readonly bool _ignoreCase; + private readonly Hashtable _table; + + #region Constructors + + /// + /// Initializes a new instance of + /// + public SynchronizedHashtable() + : this(new Hashtable(), false) + { } + + /// + /// Initializes a new instance of + /// + public SynchronizedHashtable(bool ignoreCase) + : this(new Hashtable(), ignoreCase) + { } + + /// + /// Initializes a new instance of , copying inital entries from + /// handling keys depending on . + /// + public SynchronizedHashtable(IDictionary dictionary, bool ignoreCase) + { + AssertUtils.ArgumentNotNull(dictionary, "dictionary"); + this._table = (ignoreCase) ? CollectionsUtil.CreateCaseInsensitiveHashtable(dictionary) : new Hashtable(dictionary); + this._ignoreCase = ignoreCase; + } + + /// + /// Creates a instance that + /// synchronizes access to the underlying . + /// + /// the hashtable to be synchronized + protected SynchronizedHashtable(Hashtable other) + { + AssertUtils.ArgumentNotNull(other, "other"); + this._table = other; + } + + /// + /// Creates a wrapper that synchronizes + /// access to the passed . + /// + /// the hashtable to be synchronized + public static SynchronizedHashtable Wrap(Hashtable other) + { + return new SynchronizedHashtable(other); + } + + #endregion + + #region Properties + + /// + ///Gets a value indicating whether the object is read-only. + /// + /// + ///true if the object is read-only; otherwise, false. + /// + public bool IsReadOnly + { + get + { + lock (SyncRoot) + { + return _table.IsReadOnly; + } + } + } + + /// + ///Gets a value indicating whether the object has a fixed size. + /// + /// + ///true if the object has a fixed size; otherwise, false. + /// + public bool IsFixedSize + { + get + { + lock (SyncRoot) + { + return _table.IsFixedSize; + } + } + } + + /// + ///Gets a value indicating whether access to the is synchronized (thread safe). + /// + /// + ///true if access to the is synchronized (thread safe); otherwise, false. + /// + public bool IsSynchronized + { + get { return true; } + } + + /// + ///Gets an object containing the keys of the object. + /// + /// + ///An object containing the keys of the object. + /// + public ICollection Keys + { + get + { + lock (SyncRoot) + { + return _table.Keys; + } + } + } + + /// + ///Gets an object containing the values in the object. + /// + /// + ///An object containing the values in the object. + /// + public ICollection Values + { + get + { + lock (SyncRoot) + { + return _table.Values; + } + } + } + + /// + ///Gets an object that can be used to synchronize access to the . + /// + /// + ///An object that can be used to synchronize access to the . + /// + public object SyncRoot + { + get { return _table.SyncRoot; } + } + + /// + ///Gets the number of elements contained in the . + /// + /// + ///The number of elements contained in the . + /// + public int Count + { + get + { + lock (SyncRoot) + { + return _table.Count; + } + } + } + + #endregion + + #region Methods + + /// + ///Adds an element with the provided key and value to the object. + /// + ///The to use as the value of the element to add. + ///The to use as the key of the element to add. + ///An element with the same key already exists in the object. + ///key is null. + ///The is read-only.-or- The has a fixed size. 2 + public void Add(object key, object value) + { + lock (SyncRoot) + { + _table.Add(key, value); + } + } + + /// + ///Removes all elements from the object. + /// + ///The object is read-only. 2 + public void Clear() + { + lock (SyncRoot) + { + _table.Clear(); + } + } + + /// + ///Creates a new object that is a copy of the current instance. + /// + /// + ///A new object that is a copy of this instance. + /// + public object Clone() + { + lock (SyncRoot) + { + return new SynchronizedHashtable(this, _ignoreCase); + } + } + + /// + ///Determines whether the object contains an element with the specified key. + /// + /// + ///true if the contains an element with the key; otherwise, false. + /// + ///The key to locate in the object. + ///key is null. 2 + public bool Contains(object key) + { + lock (SyncRoot) + { + return _table.Contains(key); + } + } + + /// + /// Returns, whether this contains an entry with the specified . + /// + ///The key to look for + ///, if this contains an entry with this + public bool ContainsKey(object key) + { + lock (SyncRoot) + { + return _table.ContainsKey(key); + } + } + + /// + /// Returns, whether this contains an entry with the specified . + /// + ///The valúe to look for + ///, if this contains an entry with this + public bool ContainsValue(object value) + { + lock (SyncRoot) + { + return _table.ContainsValue(value); + } + } + + /// + ///Copies the elements of the to an , starting at a particular index. + /// + ///The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + ///The zero-based index in array at which copying begins. + ///array is null. + ///The type of the source cannot be cast automatically to the type of the destination array. + ///index is less than zero. + ///array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source is greater than the available space from index to the end of the destination array. 2 + public void CopyTo(Array array, int index) + { + lock (SyncRoot) + { + _table.CopyTo(array, index); + } + } + + /// + ///Returns an object for the object. + /// + /// + ///An object for the object. + /// + public IDictionaryEnumerator GetEnumerator() + { + lock (SyncRoot) + { + return new SynchronizedDictionaryEnumerator(SyncRoot, _table.GetEnumerator()); + } + } + + /// + ///Removes the element with the specified key from the object. + /// + ///The key of the element to remove. + ///The object is read-only.-or- The has a fixed size. + ///key is null. 2 + public void Remove(object key) + { + lock (SyncRoot) + { + _table.Remove(key); + } + } + + #endregion + + #region IEnumerable implementation + + /// + ///Returns an enumerator that iterates through a collection. + /// + /// + ///An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + lock (SyncRoot) + { + return new SynchronizedEnumerator(SyncRoot, ((IEnumerable)_table).GetEnumerator()); + } + } + + #endregion + + #region Indexer + + /// + ///Gets or sets the element with the specified key. + /// + /// + ///The element with the specified key. + /// + ///The key of the element to get or set. + ///The property is set and the object is read-only.-or- The property is set, key does not exist in the collection, and the has a fixed size. + ///key is null. 2 + public object this[object key] + { + get + { + lock (SyncRoot) + { + return _table[key]; + } + } + set + { + lock (SyncRoot) + { + _table[key] = value; + } + } + } + + #endregion + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/ConstructorNode.cs b/src/Spring/Spring.Core/Expressions/ConstructorNode.cs index 7f57e604..2e70eaee 100644 --- a/src/Spring/Spring.Core/Expressions/ConstructorNode.cs +++ b/src/Spring/Spring.Core/Expressions/ConstructorNode.cs @@ -180,7 +180,7 @@ namespace Spring.Expressions private static ConstructorInfo[] GetCandidateConstructors(Type type, int argCount) { - ConstructorInfo[] ctors = type.GetConstructors(); + ConstructorInfo[] ctors = type.GetConstructors(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); ArrayList matches = new ArrayList(); foreach (ConstructorInfo ctor in ctors) diff --git a/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs b/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs index 1897bfb8..4dd9065f 100644 --- a/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs +++ b/src/Spring/Spring.Core/Objects/Factory/ObjectFactoryUtils.cs @@ -410,11 +410,12 @@ namespace Spring.Objects.Factory public static string TransformedObjectName(string name) { AssertUtils.ArgumentNotNull(name, "name", "Object name must not be null."); - string objectName = name; - if (ObjectFactoryUtils.IsFactoryDereference(objectName)) + if (!ObjectFactoryUtils.IsFactoryDereference(name)) { - objectName = objectName.Substring(ObjectFactoryUtils.FactoryObjectPrefix.Length); + return name; } + + string objectName = name.Substring(ObjectFactoryUtils.FactoryObjectPrefix.Length); return objectName; } @@ -459,8 +460,10 @@ namespace Spring.Objects.Factory public static bool IsFactoryDereference(string name) { return name != null + && name.Length > ObjectFactoryUtils.FactoryObjectPrefix.Length + && name[0] == ObjectFactoryUtils.FactoryObjectPrefix[0] && name.StartsWith(ObjectFactoryUtils.FactoryObjectPrefix) - && name.Length > ObjectFactoryUtils.FactoryObjectPrefix.Length; + ; } } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs index c8dcce93..932e30d7 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs @@ -1,5 +1,5 @@ -#region License - +#region License + /* * Copyright © 2002-2005 the original author or authors. * @@ -14,1964 +14,1978 @@ * 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 - -#region Imports - -using System; -using System.Collections; -using System.Collections.Specialized; -using System.ComponentModel; - -using Common.Logging; - -using Spring.Collections; -using Spring.Core; -using Spring.Core.TypeConversion; -using Spring.Objects.Factory.Config; -using Spring.Util; - -#endregion - -namespace Spring.Objects.Factory.Support -{ - /// - /// Abstract superclass for - /// implementations. - /// - /// - ///

- /// This class provides singleton / prototype determination, singleton caching, - /// object definition aliasing, - /// handling, and object definition merging for child object definitions. - ///

- ///
- /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - [Serializable] - public abstract class AbstractObjectFactory : IConfigurableObjectFactory - { - /// - /// Marker object to be temporarily registered in the singleton cache, - /// while instantiating an object (in order to be able to detect circular references). - /// - private static readonly object CURRENTLY_IN_CREATION = new Object(); - - /// - /// The instance for this class. - /// - private readonly ILog log = LogManager.GetLogger(typeof(AbstractObjectFactory)); - - /// - /// Used as value in hashtable that keeps track of singleton names currently in the - /// process of being created. Would not be necessary if we created a case insensitive implementation of - /// ISet. - /// - private static object emptyObject = new object(); - - - - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This constructor implicitly creates an - /// - /// that treats the names of objects in this factory in a case-sensitive fashion. - ///

- ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- protected AbstractObjectFactory() : this(true) - {} - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- /// - /// if the names of objects in this factory are to be treated in a - /// case-sensitive fashion. - /// - protected AbstractObjectFactory(bool caseSensitive) - { - this.log = LogManager.GetLogger(this.GetType()); - if (caseSensitive) - { - this.aliasMap = new SynchronizedHashtable(); - this.singletonCache = new Hashtable(); - this.singletonsInCreation = new Hashtable(); - } - else - { - this.aliasMap = new SynchronizedHashtable(CollectionsUtil.CreateCaseInsensitiveHashtable()); - this.singletonCache = CollectionsUtil.CreateCaseInsensitiveHashtable(); - this.singletonsInCreation = CollectionsUtil.CreateCaseInsensitiveHashtable(); - } - } - - /// - /// Creates a new instance of the - /// class. - /// - /// - ///

- /// This is an class, and as such exposes no public constructors. - ///

- ///
- /// - /// if the names of objects in this factory are to be treated in a - /// case-sensitive fashion. - /// - /// - /// Any parent object factory; may be . - /// - protected AbstractObjectFactory(bool caseSensitive, IObjectFactory parentFactory) : this(caseSensitive) - { - ParentObjectFactory = parentFactory; - } - - #endregion - - #region Properties - - /// - /// Gets the of - /// s - /// that will be applied to objects created by this factory. - /// - public IList ObjectPostProcessors - { - get { return objectPostProcessors; } - } - - /// - /// Gets the set of classes that will be ignored for autowiring. - /// - /// - ///

- /// The elements of this are - /// s. - ///

- ///
- public ISet IgnoredDependencyTypes - { - get { return ignoreDependencyTypes; } - } - - /// - /// Returns, whether this object factory instance contains objects. - /// - protected bool HasInstantiationAwareBeanPostProcessors - { - get { return hasInstantiationAwareBeanPostProcessors; } - } - - /// - /// Returns, whether this object factory instance contains objects. - /// - protected bool HasDestructionAwareBeanPostProcessors - { - get { return hasDestructionAwareBeanPostProcessors; } - } - - #endregion - - #region Methods - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// The name of the object to return. - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the object is not of the required type. - /// - /// - /// If the supplied is . - /// - /// - public object GetObject(string name, Type requiredType, object[] arguments) - { - string objectName = TransformedObjectName(name); - object instance = null; - // eagerly check singleton cache for manually registered singletons... - object sharedInstance = GetSingleton(objectName); - - if (sharedInstance != null) - { - #region Instrumentation - - if (IsSingletonCurrentlyInCreation(objectName)) + */ + +#endregion + +#region Imports + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.ComponentModel; + +using Common.Logging; + +using Spring.Collections; +using Spring.Core; +using Spring.Core.TypeConversion; +using Spring.Objects.Factory.Config; +using Spring.Util; + +#endregion + +namespace Spring.Objects.Factory.Support +{ + /// + /// Abstract superclass for + /// implementations. + /// + /// + ///

+ /// This class provides singleton / prototype determination, singleton caching, + /// object definition aliasing, + /// handling, and object definition merging for child object definitions. + ///

+ ///
+ /// Rod Johnson + /// Juergen Hoeller + /// Rick Evans (.NET) + [Serializable] + public abstract class AbstractObjectFactory : IConfigurableObjectFactory + { + /// + /// Marker object to be temporarily registered in the singleton cache, + /// while instantiating an object (in order to be able to detect circular references). + /// + private static readonly object CURRENTLY_IN_CREATION = new Object(); + + /// + /// The instance for this class. + /// + private readonly ILog log = LogManager.GetLogger(typeof(AbstractObjectFactory)); + + /// + /// Used as value in hashtable that keeps track of singleton names currently in the + /// process of being created. Would not be necessary if we created a case insensitive implementation of + /// ISet. + /// + private static object emptyObject = new object(); + + + + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This constructor implicitly creates an + /// + /// that treats the names of objects in this factory in a case-sensitive fashion. + ///

+ ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ protected AbstractObjectFactory() + : this(true) + { } + + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ /// + /// if the names of objects in this factory are to be treated in a + /// case-sensitive fashion. + /// + protected AbstractObjectFactory(bool caseSensitive) + { + this.log = LogManager.GetLogger(this.GetType()); + this.caseSensitive = caseSensitive; + if (caseSensitive) + { + this.aliasMap = new Hashtable(); + this.singletonCache = new Hashtable(); + this.singletonsInCreation = new Hashtable(); + } + else + { + this.aliasMap = new CaseInsensitiveHashtable(); + this.singletonCache = new CaseInsensitiveHashtable(); + this.singletonsInCreation = new CaseInsensitiveHashtable(); + } + } + + /// + /// Creates a new instance of the + /// class. + /// + /// + ///

+ /// This is an class, and as such exposes no public constructors. + ///

+ ///
+ /// + /// if the names of objects in this factory are to be treated in a + /// case-sensitive fashion. + /// + /// + /// Any parent object factory; may be . + /// + protected AbstractObjectFactory(bool caseSensitive, IObjectFactory parentFactory) + : this(caseSensitive) + { + ParentObjectFactory = parentFactory; + } + + #endregion + + #region Properties + + /// + /// Returns, whether this factory treats object names case sensitive or not. + /// + public bool IsCaseSensitive + { + get { return caseSensitive; } + } + + /// + /// Gets the of + /// s + /// that will be applied to objects created by this factory. + /// + public IList ObjectPostProcessors + { + get { return objectPostProcessors; } + } + + /// + /// Gets the set of classes that will be ignored for autowiring. + /// + /// + ///

+ /// The elements of this are + /// s. + ///

+ ///
+ public ISet IgnoredDependencyTypes + { + get { return ignoreDependencyTypes; } + } + + /// + /// Returns, whether this object factory instance contains objects. + /// + protected bool HasInstantiationAwareBeanPostProcessors + { + get { return hasInstantiationAwareBeanPostProcessors; } + } + + /// + /// Returns, whether this object factory instance contains objects. + /// + protected bool HasDestructionAwareBeanPostProcessors + { + get { return hasDestructionAwareBeanPostProcessors; } + } + + #endregion + + #region Methods + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// The name of the object to return. + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the object is not of the required type. + /// + /// + /// If the supplied is . + /// + /// + public object GetObject(string name, Type requiredType, object[] arguments) + { + string objectName = TransformedObjectName(name); + object instance = null; + // eagerly check singleton cache for manually registered singletons... + object sharedInstance = GetSingleton(objectName); + + if (sharedInstance != null) + { + #region Instrumentation + + if (IsSingletonCurrentlyInCreation(objectName)) + { + if (log.IsDebugEnabled) + { + log.Debug("Returning eagerly cached instance of singleton object '" + objectName + + "' that is not fully initialized yet - a consequence of a circular reference"); + } + } + else + { + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Returning cached instance of singleton object '{0}'.", objectName)); + } + } + + #endregion + + instance = GetObjectForInstance(name, sharedInstance); + } + else + { + // check if object definition exists + RootObjectDefinition mergedObjectDefinition = null; + mergedObjectDefinition = GetMergedObjectDefinition(objectName, false); + if (mergedObjectDefinition == null) + { + if (ParentObjectFactory != null) + { + return ParentObjectFactory.GetObject(name, requiredType, arguments); + } + throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]"); + } + + CheckMergedObjectDefinition(mergedObjectDefinition, objectName, requiredType, arguments); + + // return IObjectDefinition instance itself for an abstract object-definition + if (mergedObjectDefinition.IsAbstract) + { + instance = mergedObjectDefinition; + } + else if (mergedObjectDefinition.IsSingleton) + { + // create object instance... + sharedInstance = CreateAndCacheSingletonInstance(objectName, mergedObjectDefinition, arguments); + instance = GetObjectForInstance(name, sharedInstance); + } + else + { + // it's a prototype, so create a new instance... + instance = CreateObject(name, mergedObjectDefinition, arguments); + } + } + // check that any required type matches the type of the actual object instance... + if (requiredType != null && !requiredType.IsAssignableFrom(instance.GetType())) + { + throw new ObjectNotOfRequiredTypeException(name, requiredType, instance); + } + return instance; + } + + + + /// + /// Apply the property values of the object definition with the supplied + /// to the supplied . + /// + /// + ///

+ /// The object definition can either define a fully self-contained object, + /// reusing it's property values, or just property values meant to be used + /// for existing object instances. + ///

+ ///
+ /// + /// The existing object that the property values for the named object will + /// be applied to. + /// + /// + /// The name of the object definition associated with the property values that are + /// to be applied. + /// + /// + /// In case of errors. + /// + public virtual void ApplyObjectPropertyValues(object instance, string name) + { + // explicit no-op... + } + + /// + /// Initializes the given with the + /// custom s registered with + /// this factory. + /// + /// + /// The to initialise. + /// + protected void InitObjectWrapper(IObjectWrapper wrapper) + { + } + + /// + /// Create an object instance for the given object definition. + /// + /// + ///

+ /// The object definition will already have been merged with the parent + /// definition in case of a child definition. + ///

+ ///

+ /// All the other methods in this class invoke this method, although objects + /// may be cached after being instantiated by this method. All object + /// instantiation within this class is performed by this method. + ///

+ ///
+ /// The name of the object. + /// + /// The object definition for the object that is to be instantiated. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , + /// then match the argument values by type and call the object's constructor. + /// + /// + /// A new instance of the object. + /// + /// + /// In case of errors. + /// + protected abstract object CreateObject(string name, RootObjectDefinition definition, object[] arguments); + + /// + /// Destroy the target object. + /// + /// + ///

+ /// Must destroy objects that depend on the given object before the object itself, + /// nor throw an exception. + ///

+ ///
+ /// + /// The name of the object. + /// + /// + /// The target object instance to destroyed. + /// + protected abstract void DestroyObject(string name, object target); + + /// + /// Does this object factory contain an object definition with the + /// supplied ? + /// + /// + ///

+ /// Does not consider any hierarchy this factory may participate in. + /// Invoked by + /// + /// when no cached singleton instance is found. + ///

+ ///
+ /// + /// The name of the object to look for. + /// + /// + /// if this object factory contains an object + /// definition with the supplied . + /// + public abstract bool ContainsObjectDefinition(string name); + + /// + /// Adds the supplied (object) to this factory's + /// singleton cache. + /// + /// + ///

+ /// To be called for eager registration of singletons, e.g. to be able to + /// resolve circular references. + ///

+ /// + /// If a singleton has already been registered under the same name as + /// the supplied , then the old singleton will + /// be replaced. + /// + ///
+ /// The name of the object. + /// The singleton object. + /// + /// If the argument is + /// or consists wholly of whitespace characters; or if the + /// is . + /// + protected virtual void AddSingleton(string name, object singleton) + { + AssertUtils.ArgumentHasText(name, "The object name must not be empty."); + AssertUtils.ArgumentNotNull(singleton, "singleton"); + lock (singletonCache) + { + singletonCache[name] = singleton; + } + } + + /// + /// Return the object name, stripping out the factory dereference prefix if + /// necessary, and resolving aliases to canonical names. + /// + /// + /// The transformed name of the object. + /// + protected string TransformedObjectName(string name) + { + string objectName = ObjectFactoryUtils.TransformedObjectName(name); + // handle aliasing... + lock (aliasMap) + { + string canonicalName = (string)aliasMap[objectName]; + return canonicalName != null ? canonicalName : objectName; + } + } + + /// + /// Ensures, that the given name is prefixed with + /// if it incidentially already starts with this prefix. This avoids troubles when dereferencing + /// the object name during + /// + protected string OriginalObjectName(string name) + { + string objectName = TransformedObjectName(name); + if (name.StartsWith(ObjectFactoryUtils.FactoryObjectPrefix)) + { + objectName = ObjectFactoryUtils.FactoryObjectPrefix + objectName; + } + return objectName; + } + + /// + /// Determines whether the specified name is defined as an alias as opposed + /// to the name of an actual object definition. + /// + /// The object name to check. + /// + /// true if the specified name is alias; otherwise, false. + /// + protected bool IsAlias(string name) + { + lock (aliasMap) + { + return aliasMap.Contains(name); + } + } + + /// + /// Return a , + /// even by traversing parent if the parameter is a child definition. + /// + /// + /// The name of the object. + /// + /// + /// Are ancestors to be included in the merge? + /// + /// + ///

+ /// Will ask the parent object factory if not found in this instance. + ///

+ ///
+ /// + /// A merged + /// with overridden properties. + /// + public virtual RootObjectDefinition GetMergedObjectDefinition(string name, bool includingAncestors) + { + return GetMergedObjectDefinition(name, GetObjectDefinition(name, includingAncestors)); + } + + /// + /// Return a , + /// even by traversing parent if the parameter is a child definition. + /// + /// + /// A merged + /// with overridden properties. + /// + protected virtual RootObjectDefinition GetMergedObjectDefinition(string name, IObjectDefinition definition) + { + if (definition == null) + { + return null; + } + else if (definition is RootObjectDefinition) + { + return (RootObjectDefinition)definition; + } + else if (definition is ChildObjectDefinition) + { + ChildObjectDefinition childDefinition = (ChildObjectDefinition)definition; + RootObjectDefinition parentDefinition = null; + if (!name.Equals(childDefinition.ParentName)) + { + parentDefinition = + GetMergedObjectDefinition(TransformedObjectName(childDefinition.ParentName), true); + } + else + { + if (ParentObjectFactory is AbstractObjectFactory) + { + parentDefinition = + ((AbstractObjectFactory)ParentObjectFactory).GetMergedObjectDefinition( + childDefinition.ParentName, true); + } + } + if (parentDefinition == null) + { + throw new NoSuchObjectDefinitionException(childDefinition.ParentName, + string.Format( + "Parent name '{0}' is equal to object name '{1}' - " + + + "cannot be resolved without an AbstractObjectFactory parent.", + childDefinition.ParentName, name)); + } + + RootObjectDefinition rootDefinition = CreateRootObjectDefinition(parentDefinition); + rootDefinition.OverrideFrom(childDefinition); + return rootDefinition; + } + else + { + throw new ObjectDefinitionStoreException(definition.ResourceDescription, name, + "Definition is neither a RootObjectDefinition nor a ChildObjectDefinition."); + } + } + /* + /// + /// Merges the object definitions. + /// + /// Object definition name. + /// The parent definition. + /// The child definition. + /// Merged object definition. + protected virtual RootObjectDefinition MergeObjectDefinitions(string name, IObjectDefinition parentDefinition, + IObjectDefinition childDefinition) { - if (log.IsDebugEnabled) - { - log.Debug("Returning eagerly cached instance of singleton object '" + objectName + - "' that is not fully initialized yet - a consequence of a circular reference"); - } + RootObjectDefinition rootDefinition = CreateRootObjectDefinition(parentDefinition); + rootDefinition.OverrideFrom(childDefinition); + return rootDefinition; } - else - { - if (log.IsDebugEnabled) - { - log.Debug(string.Format("Returning cached instance of singleton object '{0}'.", objectName)); - } - } - - #endregion - - instance = GetObjectForInstance(name, sharedInstance); - } - else - { - // check if object definition exists - RootObjectDefinition mergedObjectDefinition = null; - mergedObjectDefinition = GetMergedObjectDefinition(objectName, false); - if (mergedObjectDefinition == null) - { - if (ParentObjectFactory != null) - { - return ParentObjectFactory.GetObject(name, requiredType, arguments); - } - throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]"); - } - - CheckMergedObjectDefinition(mergedObjectDefinition, objectName, requiredType, arguments); - - // return IObjectDefinition instance itself for an abstract object-definition - if (mergedObjectDefinition.IsAbstract) - { - instance = mergedObjectDefinition; - } - else if (mergedObjectDefinition.IsSingleton) - { - // create object instance... - sharedInstance = CreateAndCacheSingletonInstance(objectName, mergedObjectDefinition, arguments); - instance = GetObjectForInstance(name, sharedInstance); - } - else - { - // it's a prototype, so create a new instance... - instance = CreateObject(name, mergedObjectDefinition, arguments); - } - } - // check that any required type matches the type of the actual object instance... - if (requiredType != null && !requiredType.IsAssignableFrom(instance.GetType())) - { - throw new ObjectNotOfRequiredTypeException(name, requiredType, instance); - } - return instance; - } - - - - /// - /// Apply the property values of the object definition with the supplied - /// to the supplied . - /// - /// - ///

- /// The object definition can either define a fully self-contained object, - /// reusing it's property values, or just property values meant to be used - /// for existing object instances. - ///

- ///
- /// - /// The existing object that the property values for the named object will - /// be applied to. - /// - /// - /// The name of the object definition associated with the property values that are - /// to be applied. - /// - /// - /// In case of errors. - /// - public virtual void ApplyObjectPropertyValues(object instance, string name) - { - // explicit no-op... - } - - /// - /// Initializes the given with the - /// custom s registered with - /// this factory. - /// - /// - /// The to initialise. - /// - protected void InitObjectWrapper(IObjectWrapper wrapper) - { - } - - /// - /// Create an object instance for the given object definition. - /// - /// - ///

- /// The object definition will already have been merged with the parent - /// definition in case of a child definition. - ///

- ///

- /// All the other methods in this class invoke this method, although objects - /// may be cached after being instantiated by this method. All object - /// instantiation within this class is performed by this method. - ///

- ///
- /// The name of the object. - /// - /// The object definition for the object that is to be instantiated. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , - /// then match the argument values by type and call the object's constructor. - /// - /// - /// A new instance of the object. - /// - /// - /// In case of errors. - /// - protected abstract object CreateObject(string name, RootObjectDefinition definition, object[] arguments); - - /// - /// Destroy the target object. - /// - /// - ///

- /// Must destroy objects that depend on the given object before the object itself, - /// nor throw an exception. - ///

- ///
- /// - /// The name of the object. - /// - /// - /// The target object instance to destroyed. - /// - protected abstract void DestroyObject(string name, object target); - - /// - /// Does this object factory contain an object definition with the - /// supplied ? - /// - /// - ///

- /// Does not consider any hierarchy this factory may participate in. - /// Invoked by - /// - /// when no cached singleton instance is found. - ///

- ///
- /// - /// The name of the object to look for. - /// - /// - /// if this object factory contains an object - /// definition with the supplied . - /// - public abstract bool ContainsObjectDefinition(string name); - - /// - /// Adds the supplied (object) to this factory's - /// singleton cache. - /// - /// - ///

- /// To be called for eager registration of singletons, e.g. to be able to - /// resolve circular references. - ///

- /// - /// If a singleton has already been registered under the same name as - /// the supplied , then the old singleton will - /// be replaced. - /// - ///
- /// The name of the object. - /// The singleton object. - /// - /// If the argument is - /// or consists wholly of whitespace characters; or if the - /// is . - /// - protected virtual void AddSingleton(string name, object singleton) - { - AssertUtils.ArgumentHasText(name, "The object name must not be empty."); - AssertUtils.ArgumentNotNull(singleton, "singleton"); - lock (singletonCache) - { - singletonCache[name] = singleton; - } - } - - /// - /// Return the object name, stripping out the factory dereference prefix if - /// necessary, and resolving aliases to canonical names. - /// - /// - /// The transformed name of the object. - /// - protected string TransformedObjectName(string name) - { - string objectName = ObjectFactoryUtils.TransformedObjectName(name); - // handle aliasing... - lock (aliasMap) - { - string canonicalName = (string) aliasMap[objectName]; - return canonicalName != null ? canonicalName : objectName; - } - } - - /// - /// Ensures, that the given name is prefixed with - /// if it incidentially already starts with this prefix. This avoids troubles when dereferencing - /// the object name during - /// - protected string OriginalObjectName(string name) - { - string objectName = TransformedObjectName(name); - if (name.StartsWith(ObjectFactoryUtils.FactoryObjectPrefix)) - { - objectName = ObjectFactoryUtils.FactoryObjectPrefix + objectName; - } - return objectName; - } - - /// - /// Determines whether the specified name is defined as an alias as opposed - /// to the name of an actual object definition. - /// - /// The object name to check. - /// - /// true if the specified name is alias; otherwise, false. - /// - protected bool IsAlias(string name) - { - lock (aliasMap) - { - return aliasMap.Contains(name); - } - } - - /// - /// Return a , - /// even by traversing parent if the parameter is a child definition. - /// - /// - /// The name of the object. - /// - /// - /// Are ancestors to be included in the merge? - /// - /// - ///

- /// Will ask the parent object factory if not found in this instance. - ///

- ///
- /// - /// A merged - /// with overridden properties. - /// - public virtual RootObjectDefinition GetMergedObjectDefinition(string name, bool includingAncestors) - { - return GetMergedObjectDefinition(name, GetObjectDefinition(name, includingAncestors)); - } - - /// - /// Return a , - /// even by traversing parent if the parameter is a child definition. - /// - /// - /// A merged - /// with overridden properties. - /// - protected virtual RootObjectDefinition GetMergedObjectDefinition(string name, IObjectDefinition definition) - { - if (definition == null) - { - return null; - } - else if (definition is RootObjectDefinition) - { - return (RootObjectDefinition) definition; - } - else if (definition is ChildObjectDefinition) - { - ChildObjectDefinition childDefinition = (ChildObjectDefinition) definition; - RootObjectDefinition parentDefinition = null; - if (!name.Equals(childDefinition.ParentName)) - { - parentDefinition = - GetMergedObjectDefinition(TransformedObjectName(childDefinition.ParentName), true); - } - else - { - if (ParentObjectFactory is AbstractObjectFactory) - { - parentDefinition = - ((AbstractObjectFactory) ParentObjectFactory).GetMergedObjectDefinition( - childDefinition.ParentName, true); - } - } - if (parentDefinition == null) - { - throw new NoSuchObjectDefinitionException(childDefinition.ParentName, - string.Format( - "Parent name '{0}' is equal to object name '{1}' - " - + - "cannot be resolved without an AbstractObjectFactory parent.", - childDefinition.ParentName, name)); - } - - RootObjectDefinition rootDefinition = CreateRootObjectDefinition(parentDefinition); - rootDefinition.OverrideFrom(childDefinition); - return rootDefinition; - } - else - { - throw new ObjectDefinitionStoreException(definition.ResourceDescription, name, - "Definition is neither a RootObjectDefinition nor a ChildObjectDefinition."); - } - } -/* - /// - /// Merges the object definitions. - /// - /// Object definition name. - /// The parent definition. - /// The child definition. - /// Merged object definition. - protected virtual RootObjectDefinition MergeObjectDefinitions(string name, IObjectDefinition parentDefinition, - IObjectDefinition childDefinition) - { - RootObjectDefinition rootDefinition = CreateRootObjectDefinition(parentDefinition); - rootDefinition.OverrideFrom(childDefinition); - return rootDefinition; - } -*/ - /// - /// Creates the root object definition. - /// - /// The template definition to base root definition on. - /// Root object definition. - protected virtual RootObjectDefinition CreateRootObjectDefinition(IObjectDefinition templateDefinition) - { - return new RootObjectDefinition(templateDefinition); - } - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// - /// The registered - /// . - /// - /// - /// If there is no object with the given name. - /// - /// - /// In the case of errors. - /// - public abstract IObjectDefinition GetObjectDefinition(string name); - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// Whether to search parent object factories. - /// - /// The registered - /// . - /// - /// - /// If there is no object with the given name. - /// - /// - /// In the case of errors. - /// - public abstract IObjectDefinition GetObjectDefinition(string name, bool includeAncestors); - - /// - /// Gets the type for the given FactoryObject. - /// - /// The factory object instance to check. - /// the FactoryObject's object type - protected virtual Type GetTypeForFactoryObject(IFactoryObject factoryObject) - { - try - { - return factoryObject.ObjectType; - } - catch (Exception ex) - { - log.Warn("FactoryObject threw exception from ObjectType, despite the contract saying " + - "that it should return null if the type of its object cannot be determined yet", ex); - return null; - } - } - - /// - /// Gets the object type for the given FactoryObject definition, as far as possible. - /// Only called if there is no singleton instance registered for the target object already. - /// - /// - /// The default implementation creates the FactoryObject via GetObject - /// to call its ObjectType property. Subclasses are encouraged to optimize - /// this, typically by just instantiating the FactoryObject but not populating it yet, - /// trying whether its ObjectType property already returns a type. - /// If no type found, a full FactoryObject creation as performed by this implementation - /// should be used as fallback. - /// - /// Name of the object. - /// The merged object definition for the object. - /// The type for the object if determinable, or null otherwise - protected virtual Type GetTypeForFactoryObject(string objectName, RootObjectDefinition mod) - { - if (!mod.IsSingleton) - { - return null; - } - try - { - IFactoryObject factoryObject = GetFactoryObject(objectName); - return GetTypeForFactoryObject(factoryObject); - } catch (ObjectCreationException ex) - { - // Can only happen when getting a FactoryObject. - log.Debug("Ignoring object creation exception on FactoryObject type check", ex); - return null; - } - } - - /// - /// Predict the eventual object type (of the processed object instance) for the - /// specified object. - /// - /// - /// Does not need to handle FactoryObjects specifically, since it is only - /// supposed to operate on the raw object type. - /// This implementation is simplistic in that it is not able to - /// handle factory methods and InstantiationAwareBeanPostProcessors. - /// It only predicts the object type correctly for a standard object. - /// To be overridden in subclasses, applying more sophisticated type detection. - /// - /// Name of the object. - /// The merged object definition to determine the type for. - /// The type of the object, or null if not predictable - protected virtual Type PredictObjectType(string objectName, RootObjectDefinition mod) - { - if (StringUtils.HasText(mod.FactoryObjectName)) - { - return null; - } - return ResolveObjectType(mod, objectName); - } - - /// - /// Get the object for the given object instance, either the object - /// instance itself or its created object in case of an - /// . - /// - /// - /// The name that may include the factory dereference prefix. - /// - /// The object instance. - /// - /// The singleton instance of the object. - /// - protected virtual object GetObjectForInstance(string name, object instance) - { - //string objectName = TransformedObjectName(name); - - // don't let calling code try to dereference the - // object factory if the object isn't a factory - if (IsFactoryDereference(name) && !(instance is IFactoryObject)) - { - throw new ObjectIsNotAFactoryException(TransformedObjectName(name), instance); - } - - // now we have the object instance, which may be a normal object - // or an IFactoryObject. If it's an IFactoryObject, we use it to - // create an object instance, unless the caller actually wants - // a reference to the factory. - if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IFactoryObject), instance)) - { - if (!IsFactoryDereference(name)) - { - - // return object instance from factory... - IFactoryObject factory = (IFactoryObject) instance; - string objectName = TransformedObjectName(name); - - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug(string.Format("Object with name '{0}' is a factory object.", objectName)); - } - - #endregion - - RootObjectDefinition rod = - (ContainsObjectDefinition(objectName) ? GetMergedObjectDefinition(objectName,true) : null); - instance = GetObjectFromFactoryObject(factory, objectName, rod); - - if (instance == null) - { - throw new FactoryObjectNotInitializedException(TransformedObjectName(name), - "Factory object returned null object - " - + "possible cause: not fully initialized due to " - + "circular object reference."); - } - } - else - { - // the user wants the factory itself... - if (log.IsDebugEnabled) - { - log.Debug( - string.Format("Calling code asked for IFactoryObject instance for name '{0}'.", - TransformedObjectName(name))); - } - } - } - return instance; - } - - /// - /// Obtain an object to expose from the given IFactoryObject. - /// - /// The IFactoryObject instance. - /// Name of the object. - /// The merged object definition. - /// The object obtained from the IFactoryObject - /// If IFactoryObject object creation failed. - private object GetObjectFromFactoryObject(IFactoryObject factory, string objectName, RootObjectDefinition rod) - { - object instance; - - try - { - instance = factory.GetObject(); - } - catch (FactoryObjectNotInitializedException ex) - { - throw new ObjectCurrentlyInCreationException( - rod.ResourceDescription, objectName, ex); - } - catch (Exception ex) - { - throw new ObjectCreationException(rod.ResourceDescription, objectName, - "FactoryObject threw exception on object creation.", ex); - } - - // Do not accept a null value for a FactoryBean that's not fully - // initialized yet: Many FactoryBeans just return null then. - if (instance == null && IsSingletonCurrentlyInCreation(objectName)) { - throw new ObjectCurrentlyInCreationException(rod.ResourceDescription, objectName, - "FactoryObject which is currently in creation returned null from GetObject."); - } - - if (factory is IConfigurableFactoryObject) - { - IConfigurableFactoryObject configurableFactory = (IConfigurableFactoryObject)factory; - - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug(string.Format("Factory object with name '{0}' is configurable.", TransformedObjectName(objectName))); - } - - #endregion - - if (configurableFactory.ProductTemplate != null) - { - instance = ConfigureObject(instance, - String.Format("{0}.ProductTemplate", objectName), - configurableFactory.ProductTemplate); - } - } - - if (instance != null) - { - try - { - instance = PostProcessObjectFromFactoryObject(instance, objectName); - } - catch (Exception ex) { - throw new ObjectCreationException(rod.ResourceDescription, objectName, - "Post-processing of the FactoryObject's object failed.", ex); - } - } - - return instance; - } - - /// - /// Post-process the given object that has been obtained from the FactoryObject. - /// The resulting object will be exposed for object references. - /// - /// The default implementation simply returns the given object - /// as-is. Subclasses may override this, for example, to apply - /// post-processors. - /// The instance obtained from the IFactoryObject. - /// Name of the object. - /// The object instance to expose - /// if any post-processing failed. - protected virtual object PostProcessObjectFromFactoryObject(object instance, string objectName) - { - return instance; - } - - /// - /// Convenience method to pull an - /// from this factory. - /// - /// - /// The name of the factory object to be retrieved. If this name is not a valid - /// name, it will be converted - /// into one. - /// - /// - /// The associated with the - /// supplied . - /// - protected IFactoryObject GetFactoryObject(string objectName) - { - if (!ObjectFactoryUtils.IsFactoryDereference(objectName)) - { - objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); - } - return (IFactoryObject) GetObject(objectName); - } - - /// - /// Is the supplied a factory object dereference? - /// - protected bool IsFactoryDereference(string name) - { - return ObjectFactoryUtils.IsFactoryDereference(name); - } - - /// - /// Determines whether the type of the given object definition matches the - /// specified target type. - /// - /// Allows for lazy load of the actual object type, provided that the - /// type match can be determined otherwise. - /// The default implementation simply delegates to the standard - /// ResolveObjectType method. Subclasses may override this to use - /// a differnt strategy. - /// - /// Name of the object (for error handling purposes). - /// The merged object definition to determine the type for. - /// Type to match against (never null). - /// - /// true if object definition matches tye specified target type; otherwise, false. - /// - /// if we failed to load the type." - protected bool IsObjectTypeMatch(string objectName, RootObjectDefinition rod, Type targetType) - { - Type objectType = ResolveObjectType(rod, objectName); - return (objectType != null && targetType.IsAssignableFrom(objectType)); - } - - /// - /// Resolves the type of the object for the specified object definition resolving - /// an object type name to a Type (if necessary) and storing the resolved Type - /// in the object definition for further use. - /// - /// The merged object definition to dertermine the type for. - /// Name of the object (for error handling purposes). - /// - protected Type ResolveObjectType(RootObjectDefinition rod, string objectName) - { - try - { - if (rod.HasObjectType) - { - return rod.ObjectType; - } - return rod.ResolveObjectType(); - } catch (TypeLoadException e) - { - throw new CannotLoadObjectTypeException(rod.ResourceDescription, objectName, rod.ObjectTypeName, e); - } - } - - /// - /// Is the object (definition) with the supplied an - /// ? - /// - /// The name of the object to be checked. - /// - /// the object (definition) with the supplied - /// an ? - /// - protected bool IsFactoryObject(string name) - { - string objectName = TransformedObjectName(name); - object objectInstance = GetSingleton(objectName); - //TODO investigate - if (IsSingletonCurrentlyInCreation(name)) - { - throw new ObjectCurrentlyInCreationException(objectName); - } - - if (objectInstance != null) - { - return (objectInstance is IFactoryObject); - } - else - { - RootObjectDefinition definition = GetMergedObjectDefinition(objectName, false); - if (definition != null) - { - return (definition.HasObjectType && typeof(IFactoryObject).IsAssignableFrom(definition.ObjectType)); - } - else - { - if (parentObjectFactory != null) - { - return ((AbstractObjectFactory) parentObjectFactory).IsFactoryObject(name); - } - else - { - throw new NoSuchObjectDefinitionException(objectName, - "Cannot find definition for object [" + objectName - + "]"); - } - } - } - } - - /// - /// Remove the object identified by the supplied - /// from this factory's singleton cache. - /// - /// - /// The name of the object that is to be removed from the singleton - /// cache. - /// - /// - /// If the argument is or - /// consists wholly of whitespace characters. - /// - protected void RemoveSingleton(string name) - { - AssertUtils.ArgumentHasText(name, "name"); - lock (singletonCache) - { - this.singletonCache.Remove(name); - } - } - - /// - /// Return the names of objects in the singleton cache that match the given - /// object type (including subclasses). - /// - /// - /// The class or interface to match, or for all object names. - /// - /// - ///

- /// Will not consider s - /// as the type of their created objects is not known before instantiation. - ///

- ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// - /// The names of objects in the singleton cache that match the given - /// object type (including subclasses), or an empty array if none. - /// - public virtual string[] GetSingletonNames(Type type) - { - lock (singletonCache) - { - ArrayList matches = new ArrayList(); - foreach (string name in singletonCache.Keys) - { - object singletonObject = singletonCache[name]; - if (singletonObject != null && type.IsAssignableFrom(singletonObject.GetType()) - && !matches.Contains(name)) - { - matches.Add(name); - } - } - return (string[]) matches.ToArray(typeof(string)); - } - } - - /// - /// Determines whether the object with the given name matches the specified type. - /// - /// More specifically, check whether a GetObject call for the given name - /// would return an object that is assignable to the specified target type. - /// Translates aliases back to the corresponding canonical bean name. - /// Will ask the parent factory if the bean cannot be found in this factory instance. - /// - /// The name of the object to query. - /// Type of the target to match against. - /// - /// true if the object type matches; otherwise, false - /// if it doesn't match or cannot be determined yet. - /// - /// Ff there is no object with the given name - /// - public bool IsTypeMatch(string name, Type targetType) - { - string objectName = TransformedObjectName(name); - Type typeToMatch = (targetType != null ? targetType : typeof (object)); - - //Check manually registered singletons. - object objectInstance = GetSingleton(objectName); - if (objectInstance != null) - { - if (objectInstance is IFactoryObject) - { - if (!IsFactoryDereference(name)) - { - Type type = GetTypeForFactoryObject((IFactoryObject)objectInstance); - return (type != null && typeToMatch.IsAssignableFrom(type)); - } - else - { - return typeToMatch.IsAssignableFrom(objectInstance.GetType()); - } - } - else - { - return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectInstance.GetType()); - } - } - else - { - // No singleton instance found -> check object definition - IObjectFactory parentFactory = ParentObjectFactory; - if (parentFactory != null && !ContainsObjectDefinition(name)) - { - // No object definition found in this factory -> delegate to parent - return parentFactory.IsTypeMatch(OriginalObjectName(name), targetType); - } - - RootObjectDefinition mod = GetMergedObjectDefinition(objectName, false); - Type objectType = PredictObjectType(objectName, mod); - - if (objectType == null) - { - return false; - } - - // Check object class whether we're dealing with a FactoryObject - if (typeof(IFactoryObject).IsAssignableFrom(objectType)) - { - if (!IsFactoryDereference(name)) - { - // If it's a FactoryObject, we want to look at what it creates, not the factory class. - Type type = GetTypeForFactoryObject(objectName, mod); - return (type != null && typeToMatch.IsAssignableFrom(type)); - } - else - { - return typeToMatch.IsAssignableFrom(objectType); - } - } - else - { - return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectType); - } - } - } - - /// - /// Determines the of the object with the - /// supplied . - /// - /// - ///

- /// More specifically, checks the of object that - /// would return. - /// For an , returns the - /// of object that the - /// creates. - ///

- ///

- /// Please note that (prototype) objects created via a factory method or - /// objects are handled - /// slightly differently, in that we don't want to needlessly create - /// instances of such objects just to determine the - /// of object that they create. - ///

- ///
- /// The name of the object to query. - /// - /// The of the object or - /// if not determinable. - /// - public virtual Type GetType(string name) - { - string objectName = TransformedObjectName(name); - - // check manually registered singletons... - object objectInstance = GetSingleton(objectName); - - if (objectInstance != null) - { - IFactoryObject factoryObject = objectInstance as IFactoryObject; - if (factoryObject != null & !IsFactoryDereference(objectName)) - { - return GetTypeForFactoryObject(factoryObject); - } - else - { - return objectInstance.GetType(); - } - } - else - { - // No singleton instance found -> check bean definition. - IObjectFactory parentFactory = ParentObjectFactory; - if (parentFactory != null && !ContainsObjectDefinition(objectName)) - { - // No bean definition found in this factory -> delegate to parent. - return parentFactory.GetType(this.OriginalObjectName(name)); - } - - RootObjectDefinition mod = this.GetMergedObjectDefinition(objectName, false); - Type objectType = PredictObjectType(objectName, mod); - - if (objectType != null && typeof (IFactoryObject).IsAssignableFrom(objectType)) - { - if (!IsFactoryDereference(name)) - { - // If it's a FactoryBean, we want to look at what it creates, not the factory class. - return GetTypeForFactoryObject(objectName, mod); - } - else - { - return objectType; - } - } - else - { - return (!IsFactoryDereference(name) ? objectType : null); - } - } - } - - /// - /// Determines the of the object defined - /// by the supplied object . - /// - /// - ///

- /// This, the default, implementation returns - /// to indicate that the type cannot be determined. Subclasses are - /// encouraged to try to determine the actual return - /// here, matching their strategy of resolving - /// factory methods in the - /// - /// implementation. - ///

- ///
- /// - /// The name associated with the supplied object . - /// - /// - /// The - /// that the is to be determined for. - /// - /// - /// The of the object defined by the supplied - /// object ; or if the - /// cannot be determined. - /// - protected virtual Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition) - { - return null; - } - - /// - /// Returns the names of the objects in the singleton cache. - /// - /// - ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// The names of the objects in the singleton cache. - public virtual string[] GetSingletonNames() - { - lock (singletonCache) - { - return (string[]) new ArrayList(singletonCache.Keys).ToArray(typeof(string)); - } - } - - /// - /// Returns the number of objects in the singleton cache. - /// - /// - ///

- /// Does not consider any hierarchy this factory may participate in. - ///

- ///
- /// The number of objects in the singleton cache. - public virtual int GetSingletonCount() - { - lock (singletonCache) - { - return singletonCache.Count; - } - } - - /// - /// Destroys the named singleton object. - /// - /// - ///

- /// Delegates to - /// - /// if a corresponding singleton instance is found. - ///

- ///
- /// - /// The name of the singleton object that is to be destroyed. - /// - /// - protected virtual void DestroySingleton(string name) - { - lock (singletonCache) - { - object tempObject = singletonCache[name]; - singletonCache.Remove(name); - - object singletonInstance = tempObject; - if (singletonInstance != null) - { - DestroyObject(name, singletonInstance); - } - } - } - - /// - /// Check the supplied merged object definition for any possible - /// validation errors. - /// - /// - /// The object definition to be checked for validation errors. - /// - /// - /// The name of the object associated with the supplied object definition. - /// - /// - /// The the object may match. Can be an interface or - /// superclass of the actual class. For example, if the value is the - /// class, this method will succeed whatever the - /// class of the returned instance. - /// - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a factory method. If there is no factory method and the - /// supplied array is not , then - /// match the argument values by type and call the object's constructor. - /// - /// - /// In the case of object validation errors. - /// - protected void CheckMergedObjectDefinition(RootObjectDefinition mergedObjectDefinition, String objectName, - Type requiredType, params object[] arguments) - { - // check if required type can match according to the object definition; - // this is only possible at this early stage for conventional objects! - if (mergedObjectDefinition.HasObjectType) - { - Type objectType = mergedObjectDefinition.ObjectType; - if (requiredType != null && StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName) - && !typeof(IFactoryObject).IsAssignableFrom(objectType) - && !requiredType.IsAssignableFrom(objectType)) - { - throw new ObjectNotOfRequiredTypeException(objectName, requiredType, objectType); - } - } - // check validity of the usage of the args parameter; this can - // only be used for prototypes constructed via a factory method... - if (arguments != null && arguments.Length > 0) - { - if (mergedObjectDefinition.IsSingleton) - { - throw new ObjectDefinitionStoreException("Cannot specify arguments in the GetObject () method when " - + "referring to a singleton object definition."); - } - //MLP lets skip this check for now. + */ + /// + /// Creates the root object definition. + /// + /// The template definition to base root definition on. + /// Root object definition. + protected virtual RootObjectDefinition CreateRootObjectDefinition(IObjectDefinition templateDefinition) + { + return new RootObjectDefinition(templateDefinition); + } + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// + /// The registered + /// . + /// + /// + /// If there is no object with the given name. + /// + /// + /// In the case of errors. + /// + public abstract IObjectDefinition GetObjectDefinition(string name); + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// Whether to search parent object factories. + /// + /// The registered + /// . + /// + /// + /// If there is no object with the given name. + /// + /// + /// In the case of errors. + /// + public abstract IObjectDefinition GetObjectDefinition(string name, bool includeAncestors); + + /// + /// Gets the type for the given FactoryObject. + /// + /// The factory object instance to check. + /// the FactoryObject's object type + protected virtual Type GetTypeForFactoryObject(IFactoryObject factoryObject) + { + try + { + return factoryObject.ObjectType; + } + catch (Exception ex) + { + log.Warn("FactoryObject threw exception from ObjectType, despite the contract saying " + + "that it should return null if the type of its object cannot be determined yet", ex); + return null; + } + } + + /// + /// Gets the object type for the given FactoryObject definition, as far as possible. + /// Only called if there is no singleton instance registered for the target object already. + /// + /// + /// The default implementation creates the FactoryObject via GetObject + /// to call its ObjectType property. Subclasses are encouraged to optimize + /// this, typically by just instantiating the FactoryObject but not populating it yet, + /// trying whether its ObjectType property already returns a type. + /// If no type found, a full FactoryObject creation as performed by this implementation + /// should be used as fallback. + /// + /// Name of the object. + /// The merged object definition for the object. + /// The type for the object if determinable, or null otherwise + protected virtual Type GetTypeForFactoryObject(string objectName, RootObjectDefinition mod) + { + if (!mod.IsSingleton) + { + return null; + } + try + { + IFactoryObject factoryObject = GetFactoryObject(objectName); + return GetTypeForFactoryObject(factoryObject); + } + catch (ObjectCreationException ex) + { + // Can only happen when getting a FactoryObject. + log.Debug("Ignoring object creation exception on FactoryObject type check", ex); + return null; + } + } + + /// + /// Predict the eventual object type (of the processed object instance) for the + /// specified object. + /// + /// + /// Does not need to handle FactoryObjects specifically, since it is only + /// supposed to operate on the raw object type. + /// This implementation is simplistic in that it is not able to + /// handle factory methods and InstantiationAwareBeanPostProcessors. + /// It only predicts the object type correctly for a standard object. + /// To be overridden in subclasses, applying more sophisticated type detection. + /// + /// Name of the object. + /// The merged object definition to determine the type for. + /// The type of the object, or null if not predictable + protected virtual Type PredictObjectType(string objectName, RootObjectDefinition mod) + { + if (StringUtils.HasText(mod.FactoryObjectName)) + { + return null; + } + return ResolveObjectType(mod, objectName); + } + + /// + /// Get the object for the given object instance, either the object + /// instance itself or its created object in case of an + /// . + /// + /// + /// The name that may include the factory dereference prefix. + /// + /// The object instance. + /// + /// The singleton instance of the object. + /// + protected virtual object GetObjectForInstance(string name, object instance) + { + //string objectName = TransformedObjectName(name); + + // don't let calling code try to dereference the + // object factory if the object isn't a factory + if (IsFactoryDereference(name) && !(instance is IFactoryObject)) + { + throw new ObjectIsNotAFactoryException(TransformedObjectName(name), instance); + } + + // now we have the object instance, which may be a normal object + // or an IFactoryObject. If it's an IFactoryObject, we use it to + // create an object instance, unless the caller actually wants + // a reference to the factory. + if (ObjectUtils.IsAssignableAndNotTransparentProxy(typeof(IFactoryObject), instance)) + { + if (!IsFactoryDereference(name)) + { + + // return object instance from factory... + IFactoryObject factory = (IFactoryObject)instance; + string objectName = TransformedObjectName(name); + + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Object with name '{0}' is a factory object.", objectName)); + } + + #endregion + + RootObjectDefinition rod = + (ContainsObjectDefinition(objectName) ? GetMergedObjectDefinition(objectName, true) : null); + instance = GetObjectFromFactoryObject(factory, objectName, rod); + + if (instance == null) + { + throw new FactoryObjectNotInitializedException(TransformedObjectName(name), + "Factory object returned null object - " + + "possible cause: not fully initialized due to " + + "circular object reference."); + } + } + else + { + // the user wants the factory itself... + if (log.IsDebugEnabled) + { + log.Debug( + string.Format("Calling code asked for IFactoryObject instance for name '{0}'.", + TransformedObjectName(name))); + } + } + } + return instance; + } + + /// + /// Obtain an object to expose from the given IFactoryObject. + /// + /// The IFactoryObject instance. + /// Name of the object. + /// The merged object definition. + /// The object obtained from the IFactoryObject + /// If IFactoryObject object creation failed. + private object GetObjectFromFactoryObject(IFactoryObject factory, string objectName, RootObjectDefinition rod) + { + object instance; + + try + { + instance = factory.GetObject(); + } + catch (FactoryObjectNotInitializedException ex) + { + throw new ObjectCurrentlyInCreationException( + rod.ResourceDescription, objectName, ex); + } + catch (Exception ex) + { + throw new ObjectCreationException(rod.ResourceDescription, objectName, + "FactoryObject threw exception on object creation.", ex); + } + + // Do not accept a null value for a FactoryBean that's not fully + // initialized yet: Many FactoryBeans just return null then. + if (instance == null && IsSingletonCurrentlyInCreation(objectName)) + { + throw new ObjectCurrentlyInCreationException(rod.ResourceDescription, objectName, + "FactoryObject which is currently in creation returned null from GetObject."); + } + + if (factory is IConfigurableFactoryObject) + { + IConfigurableFactoryObject configurableFactory = (IConfigurableFactoryObject)factory; + + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Factory object with name '{0}' is configurable.", TransformedObjectName(objectName))); + } + + #endregion + + if (configurableFactory.ProductTemplate != null) + { + instance = ConfigureObject(instance, + String.Format("{0}.ProductTemplate", objectName), + configurableFactory.ProductTemplate); + } + } + + if (instance != null) + { + try + { + instance = PostProcessObjectFromFactoryObject(instance, objectName); + } + catch (Exception ex) + { + throw new ObjectCreationException(rod.ResourceDescription, objectName, + "Post-processing of the FactoryObject's object failed.", ex); + } + } + + return instance; + } + + /// + /// Post-process the given object that has been obtained from the FactoryObject. + /// The resulting object will be exposed for object references. + /// + /// The default implementation simply returns the given object + /// as-is. Subclasses may override this, for example, to apply + /// post-processors. + /// The instance obtained from the IFactoryObject. + /// Name of the object. + /// The object instance to expose + /// if any post-processing failed. + protected virtual object PostProcessObjectFromFactoryObject(object instance, string objectName) + { + return instance; + } + + /// + /// Convenience method to pull an + /// from this factory. + /// + /// + /// The name of the factory object to be retrieved. If this name is not a valid + /// name, it will be converted + /// into one. + /// + /// + /// The associated with the + /// supplied . + /// + protected IFactoryObject GetFactoryObject(string objectName) + { + if (!ObjectFactoryUtils.IsFactoryDereference(objectName)) + { + objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); + } + return (IFactoryObject)GetObject(objectName); + } + + /// + /// Is the supplied a factory object dereference? + /// + protected bool IsFactoryDereference(string name) + { + return ObjectFactoryUtils.IsFactoryDereference(name); + } + + /// + /// Determines whether the type of the given object definition matches the + /// specified target type. + /// + /// Allows for lazy load of the actual object type, provided that the + /// type match can be determined otherwise. + /// The default implementation simply delegates to the standard + /// ResolveObjectType method. Subclasses may override this to use + /// a differnt strategy. + /// + /// Name of the object (for error handling purposes). + /// The merged object definition to determine the type for. + /// Type to match against (never null). + /// + /// true if object definition matches tye specified target type; otherwise, false. + /// + /// if we failed to load the type." + protected bool IsObjectTypeMatch(string objectName, RootObjectDefinition rod, Type targetType) + { + Type objectType = ResolveObjectType(rod, objectName); + return (objectType != null && targetType.IsAssignableFrom(objectType)); + } + + /// + /// Resolves the type of the object for the specified object definition resolving + /// an object type name to a Type (if necessary) and storing the resolved Type + /// in the object definition for further use. + /// + /// The merged object definition to dertermine the type for. + /// Name of the object (for error handling purposes). + /// + protected Type ResolveObjectType(RootObjectDefinition rod, string objectName) + { + try + { + if (rod.HasObjectType) + { + return rod.ObjectType; + } + return rod.ResolveObjectType(); + } + catch (TypeLoadException e) + { + throw new CannotLoadObjectTypeException(rod.ResourceDescription, objectName, rod.ObjectTypeName, e); + } + } + + /// + /// Is the object (definition) with the supplied an + /// ? + /// + /// The name of the object to be checked. + /// + /// the object (definition) with the supplied + /// an ? + /// + protected bool IsFactoryObject(string name) + { + string objectName = TransformedObjectName(name); + object objectInstance = GetSingleton(objectName); + //TODO investigate + if (IsSingletonCurrentlyInCreation(name)) + { + throw new ObjectCurrentlyInCreationException(objectName); + } + + if (objectInstance != null) + { + return (objectInstance is IFactoryObject); + } + else + { + RootObjectDefinition definition = GetMergedObjectDefinition(objectName, false); + if (definition != null) + { + return (definition.HasObjectType && typeof(IFactoryObject).IsAssignableFrom(definition.ObjectType)); + } + else + { + if (parentObjectFactory != null) + { + return ((AbstractObjectFactory)parentObjectFactory).IsFactoryObject(name); + } + else + { + throw new NoSuchObjectDefinitionException(objectName, + "Cannot find definition for object [" + objectName + + "]"); + } + } + } + } + + /// + /// Remove the object identified by the supplied + /// from this factory's singleton cache. + /// + /// + /// The name of the object that is to be removed from the singleton + /// cache. + /// + /// + /// If the argument is or + /// consists wholly of whitespace characters. + /// + protected void RemoveSingleton(string name) + { + AssertUtils.ArgumentHasText(name, "name"); + lock (singletonCache) + { + this.singletonCache.Remove(name); + } + } + + /// + /// Return the names of objects in the singleton cache that match the given + /// object type (including subclasses). + /// + /// + /// The class or interface to match, or for all object names. + /// + /// + ///

+ /// Will not consider s + /// as the type of their created objects is not known before instantiation. + ///

+ ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// + /// The names of objects in the singleton cache that match the given + /// object type (including subclasses), or an empty array if none. + /// + public virtual string[] GetSingletonNames(Type type) + { + lock (singletonCache) + { + ArrayList matches = new ArrayList(); + foreach (string name in singletonCache.Keys) + { + object singletonObject = singletonCache[name]; + if (singletonObject != null && type.IsAssignableFrom(singletonObject.GetType()) + && !matches.Contains(name)) + { + matches.Add(name); + } + } + return (string[])matches.ToArray(typeof(string)); + } + } + + /// + /// Determines whether the object with the given name matches the specified type. + /// + /// More specifically, check whether a GetObject call for the given name + /// would return an object that is assignable to the specified target type. + /// Translates aliases back to the corresponding canonical bean name. + /// Will ask the parent factory if the bean cannot be found in this factory instance. + /// + /// The name of the object to query. + /// Type of the target to match against. + /// + /// true if the object type matches; otherwise, false + /// if it doesn't match or cannot be determined yet. + /// + /// Ff there is no object with the given name + /// + public bool IsTypeMatch(string name, Type targetType) + { + string objectName = TransformedObjectName(name); + Type typeToMatch = (targetType != null ? targetType : typeof(object)); + + //Check manually registered singletons. + object objectInstance = GetSingleton(objectName); + if (objectInstance != null) + { + if (objectInstance is IFactoryObject) + { + if (!IsFactoryDereference(name)) + { + Type type = GetTypeForFactoryObject((IFactoryObject)objectInstance); + return (type != null && typeToMatch.IsAssignableFrom(type)); + } + else + { + return typeToMatch.IsAssignableFrom(objectInstance.GetType()); + } + } + else + { + return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectInstance.GetType()); + } + } + else + { + // No singleton instance found -> check object definition + IObjectFactory parentFactory = ParentObjectFactory; + if (parentFactory != null && !ContainsObjectDefinition(name)) + { + // No object definition found in this factory -> delegate to parent + return parentFactory.IsTypeMatch(OriginalObjectName(name), targetType); + } + + RootObjectDefinition mod = GetMergedObjectDefinition(objectName, false); + Type objectType = PredictObjectType(objectName, mod); + + if (objectType == null) + { + return false; + } + + // Check object class whether we're dealing with a FactoryObject + if (typeof(IFactoryObject).IsAssignableFrom(objectType)) + { + if (!IsFactoryDereference(name)) + { + // If it's a FactoryObject, we want to look at what it creates, not the factory class. + Type type = GetTypeForFactoryObject(objectName, mod); + return (type != null && typeToMatch.IsAssignableFrom(type)); + } + else + { + return typeToMatch.IsAssignableFrom(objectType); + } + } + else + { + return !IsFactoryDereference(name) && typeToMatch.IsAssignableFrom(objectType); + } + } + } + + /// + /// Determines the of the object with the + /// supplied . + /// + /// + ///

+ /// More specifically, checks the of object that + /// would return. + /// For an , returns the + /// of object that the + /// creates. + ///

+ ///

+ /// Please note that (prototype) objects created via a factory method or + /// objects are handled + /// slightly differently, in that we don't want to needlessly create + /// instances of such objects just to determine the + /// of object that they create. + ///

+ ///
+ /// The name of the object to query. + /// + /// The of the object or + /// if not determinable. + /// + public virtual Type GetType(string name) + { + string objectName = TransformedObjectName(name); + + // check manually registered singletons... + object objectInstance = GetSingleton(objectName); + + if (objectInstance != null) + { + IFactoryObject factoryObject = objectInstance as IFactoryObject; + if (factoryObject != null & !IsFactoryDereference(objectName)) + { + return GetTypeForFactoryObject(factoryObject); + } + else + { + return objectInstance.GetType(); + } + } + else + { + // No singleton instance found -> check bean definition. + IObjectFactory parentFactory = ParentObjectFactory; + if (parentFactory != null && !ContainsObjectDefinition(objectName)) + { + // No bean definition found in this factory -> delegate to parent. + return parentFactory.GetType(this.OriginalObjectName(name)); + } + + RootObjectDefinition mod = this.GetMergedObjectDefinition(objectName, false); + Type objectType = PredictObjectType(objectName, mod); + + if (objectType != null && typeof(IFactoryObject).IsAssignableFrom(objectType)) + { + if (!IsFactoryDereference(name)) + { + // If it's a FactoryBean, we want to look at what it creates, not the factory class. + return GetTypeForFactoryObject(objectName, mod); + } + else + { + return objectType; + } + } + else + { + return (!IsFactoryDereference(name) ? objectType : null); + } + } + } + + /// + /// Determines the of the object defined + /// by the supplied object . + /// + /// + ///

+ /// This, the default, implementation returns + /// to indicate that the type cannot be determined. Subclasses are + /// encouraged to try to determine the actual return + /// here, matching their strategy of resolving + /// factory methods in the + /// + /// implementation. + ///

+ ///
+ /// + /// The name associated with the supplied object . + /// + /// + /// The + /// that the is to be determined for. + /// + /// + /// The of the object defined by the supplied + /// object ; or if the + /// cannot be determined. + /// + protected virtual Type GetTypeForFactoryMethod(string objectName, RootObjectDefinition definition) + { + return null; + } + + /// + /// Returns the names of the objects in the singleton cache. + /// + /// + ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// The names of the objects in the singleton cache. + public virtual string[] GetSingletonNames() + { + lock (singletonCache) + { + return (string[])new ArrayList(singletonCache.Keys).ToArray(typeof(string)); + } + } + + /// + /// Returns the number of objects in the singleton cache. + /// + /// + ///

+ /// Does not consider any hierarchy this factory may participate in. + ///

+ ///
+ /// The number of objects in the singleton cache. + public virtual int GetSingletonCount() + { + lock (singletonCache) + { + return singletonCache.Count; + } + } + + /// + /// Destroys the named singleton object. + /// + /// + ///

+ /// Delegates to + /// + /// if a corresponding singleton instance is found. + ///

+ ///
+ /// + /// The name of the singleton object that is to be destroyed. + /// + /// + protected virtual void DestroySingleton(string name) + { + lock (singletonCache) + { + object tempObject = singletonCache[name]; + singletonCache.Remove(name); + + object singletonInstance = tempObject; + if (singletonInstance != null) + { + DestroyObject(name, singletonInstance); + } + } + } + + /// + /// Check the supplied merged object definition for any possible + /// validation errors. + /// + /// + /// The object definition to be checked for validation errors. + /// + /// + /// The name of the object associated with the supplied object definition. + /// + /// + /// The the object may match. Can be an interface or + /// superclass of the actual class. For example, if the value is the + /// class, this method will succeed whatever the + /// class of the returned instance. + /// + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a factory method. If there is no factory method and the + /// supplied array is not , then + /// match the argument values by type and call the object's constructor. + /// + /// + /// In the case of object validation errors. + /// + protected void CheckMergedObjectDefinition(RootObjectDefinition mergedObjectDefinition, String objectName, + Type requiredType, params object[] arguments) + { + // check if required type can match according to the object definition; + // this is only possible at this early stage for conventional objects! + if (mergedObjectDefinition.HasObjectType) + { + Type objectType = mergedObjectDefinition.ObjectType; + if (requiredType != null && StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName) + && !typeof(IFactoryObject).IsAssignableFrom(objectType) + && !requiredType.IsAssignableFrom(objectType)) + { + throw new ObjectNotOfRequiredTypeException(objectName, requiredType, objectType); + } + } + // check validity of the usage of the args parameter; this can + // only be used for prototypes constructed via a factory method... + if (arguments != null && arguments.Length > 0) + { + if (mergedObjectDefinition.IsSingleton) + { + throw new ObjectDefinitionStoreException("Cannot specify arguments in the GetObject () method when " + + "referring to a singleton object definition."); + } + //MLP lets skip this check for now. /* - else if (StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName)) - { - throw new ObjectDefinitionStoreException( - "Can only specify arguments in the GetObject () method in " + - "conjunction with a factory method."); - } - */ - } - } - - /// - /// Gets the temporary object that is placed - /// into the singleton cache during object resolution. - /// - protected object TemporarySingletonPlaceHolder - { - get { return CURRENTLY_IN_CREATION; } - } - - #endregion - - #region Fields - - /// - /// Parent object factory, for object inheritance support - /// - private IObjectFactory parentObjectFactory; - - /// - /// Dependency types to ignore on dependency check and autowire, as Set of - /// Type objects: for example, string. Default is none. - /// - private ISet ignoreDependencyTypes = new HybridSet(); - - - /// - /// ObjectPostProcessors to apply in CreateObject - /// - private IList objectPostProcessors = new ArrayList(); - - /// - /// Indicates whether any IInstantiationAwareBeanPostProcessors have been registered - /// - private bool hasInstantiationAwareBeanPostProcessors; - - /// - /// Indicates whether any IDestructionAwareBeanPostProcessors have been registered - /// - private bool hasDestructionAwareBeanPostProcessors; - - private IDictionary aliasMap; - private IDictionary singletonCache; - private IDictionary singletonsInCreation; - - #endregion - - #region IHierarchicalObjectFactory Members - - /// - /// The parent object factory, or if there is none. - /// - /// - /// The parent object factory, or if there is none. - /// - public IObjectFactory ParentObjectFactory - { - get { return parentObjectFactory; } - set { parentObjectFactory = value; } - } - - #endregion - - #region IObjectFactory Members - - /// - /// Is this object a singleton? - /// - /// - public bool IsSingleton(string name) - { - string objectName = TransformedObjectName(name); - object objectInstance = this.GetSingleton(objectName); - if (objectInstance != null) - { - IFactoryObject factoryObject = objectInstance as IFactoryObject; - if (factoryObject != null) - { - return IsFactoryDereference(name) || factoryObject.IsSingleton; - } - else - { - return !IsFactoryDereference(name); - } - } - else - { - // No singleton instance found -> check object definition - IObjectFactory pof = ParentObjectFactory; - if (pof != null && !ContainsObjectDefinition(objectName)) - { - // No object definition found in this factory -> delegate to parent - return pof.IsSingleton(OriginalObjectName(name)); - } - RootObjectDefinition od = GetMergedObjectDefinition(objectName, false); - - // In case of IFactoryObject, return singleton status of created object if not a dereference - if (od.IsSingleton) - { - if (IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))) - { - if (IsFactoryDereference(name)) - { - return true; - } - IFactoryObject factoryObject = - (IFactoryObject) GetObject(ObjectFactoryUtils.BuildFactoryObjectName(objectName)); - return factoryObject.IsSingleton; - } - else - { - return !IsFactoryDereference(name); - } - } - else - { - return false; - } - } - } - - /// - /// Determines whether the specified object name is prototype. That is, will GetObject - /// always return independent instances? - /// - /// The name of the object to query - /// - /// true if the specified object name will always deliver independent instances; otherwise, false. - /// - /// This method returning false does not clearly indicate a singleton object. - /// It indicated non-independent instances, which may correspond to a scoped object as - /// well. use the IsSingleton property to explicitly check for a shared - /// singleton instance. - /// Translates aliases back to the corresponding canonical object name. Will ask the - /// parent factory if the object can not be found in this factory instance. - /// - /// - /// if there is no object with the given name. - public bool IsPrototype(string name) - { - string objectName = TransformedObjectName(name); - IObjectFactory parentFactory = ParentObjectFactory; - if (parentFactory != null && !this.ContainsObjectDefinition(objectName)) - { - // No object definition found in this factory -> delegate to parent - return parentFactory.IsPrototype(OriginalObjectName(name)); - } - - RootObjectDefinition od = GetMergedObjectDefinition(objectName, false); - - // In case of FactoryObject, return singleton status of created object if not a dereference - if (od.IsPrototype) - { - return (!IsFactoryDereference(name) || IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))); - } - else - { - // not a prototype, however factory object may still produce a prototype object - if (IsFactoryDereference(name) && IsObjectTypeMatch(objectName, od, typeof (IFactoryObject))) - { - IFactoryObject factoryObject = GetFactoryObject(objectName); - return (!factoryObject.IsSingleton); - } - else - { - return false; - } - } - } - - /// - /// Does this object factory contain an object with the given name? - /// - /// - /// This method does not (and it should not) check if the specified - /// object exists in one of the parent object factories. If it did, - /// message sources and event registries within application context - /// hierarchy would have circular references, which would cause stack - /// overflows during message lookup, for example. (A. Seovic) - /// - /// . - public bool ContainsObject(string name) - { - string objectName = TransformedObjectName(name); - lock (singletonCache) - { - if (singletonCache.Contains(objectName)) - { - return true; - } - } - if (ContainsObjectDefinition(objectName)) - { - return true; - } - else - { - return false; - } - } - - /// - /// Return the aliases for the given object name, if defined. - /// - /// . - public string[] GetAliases(string name) - { - string objectName = TransformedObjectName(name); - // check if object actually exists in this object factory... - bool isInSingletonCache = false; - lock(singletonCache) - { - isInSingletonCache = singletonCache.Contains(objectName); - } - if (isInSingletonCache || ContainsObjectDefinition(objectName)) - { - // if found, gather aliases... - ArrayList matches = new ArrayList(); - lock (aliasMap) - { - foreach (DictionaryEntry aliasEntry in aliasMap) - { - if (aliasEntry.Value.Equals(objectName)) - { - matches.Add(aliasEntry.Key); - } - } - } - return (string[]) matches.ToArray(typeof(string)); - } - else - { - // not found, so check parent... - if (ParentObjectFactory != null) - { - return ParentObjectFactory.GetAliases(objectName); - } - throw new NoSuchObjectDefinitionException(objectName, ToString()); - } - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// . - public object this[string name] - { - get { return GetObject(name); } - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// . - public object GetObject(string name) - { - return GetObject(name, typeof(object), ObjectUtils.EmptyObjects); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - ///

- /// This method allows an object factory to be used as a replacement for the - /// Singleton or Prototype design pattern. - ///

- ///

- /// Note that callers should retain references to returned objects. There is no - /// guarantee that this method will be implemented to be efficient. For example, - /// it may be synchronized, or may need to run an RDBMS query. - ///

- ///

- /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - ///

- ///
- /// The name of the object to return. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - /// - /// If the supplied is . - /// - public object GetObject(string name, object[] arguments) - { - object instance = null; - string objectName = TransformedObjectName(name); - - // check if object definition exists - RootObjectDefinition mergedObjectDefinition = null; - mergedObjectDefinition = GetMergedObjectDefinition(objectName, false); - if (mergedObjectDefinition == null) - { - if (ParentObjectFactory != null) - { - return ParentObjectFactory.GetObject(name, arguments); - } - throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]"); - } - - // Override constructor values and configure as a prototype - RootObjectDefinition tmpObjectDefinition = new RootObjectDefinition(mergedObjectDefinition); - tmpObjectDefinition.ConstructorArgumentValues = null; - tmpObjectDefinition.IsSingleton = false; - - // create a new instance... - instance = CreateObject(name, tmpObjectDefinition, arguments); - - return GetObjectForInstance(name, instance); - } - - /// - /// Tries to find a cached object for the specified name. - /// - /// Teh object name to look for. - /// The cached object if found, otherwise. - protected virtual object GetSingleton(string objectName) - { - lock (singletonCache) - { - return singletonCache[objectName]; - } - } - - /// - /// Creates a singleton instance for the specified object name and definition. - /// - /// - /// The object name (will be used as the key in the singleton cache key). - /// - /// The object definition. - /// - /// The arguments to use if creating a prototype using explicit arguments to - /// a static factory method. If there is no factory method and the - /// arguments are not null, then match the argument values by type and - /// call the object's constructor. - /// - /// The created object instance. - protected virtual object CreateAndCacheSingletonInstance(string objectName, - RootObjectDefinition objectDefinition, - object[] arguments) - { - lock (singletonCache) - { - object sharedInstance = singletonCache[objectName]; - if (sharedInstance == null) - { - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug("Creating shared instance of singleton object '" + objectName + "'"); - } - - #endregion - - BeforeSingletonCreation(objectName); - try - { - sharedInstance = CreateObject(objectName, objectDefinition, arguments); - } - finally - { - AfterSingletonCreation(objectName); - } - AddSingleton(objectName, sharedInstance); - } - return sharedInstance; - } - } - - private void AfterSingletonCreation(string name) - { - if (!singletonsInCreation.Contains(name)) - { - throw new InvalidOperationException("Singleton " + name + " isn't currently in creation."); - } - singletonsInCreation.Remove(name); - } - - private void BeforeSingletonCreation(string name) - { - if (this.singletonsInCreation.Contains(name)) - { - throw new ObjectCurrentlyInCreationException(name); - } - singletonsInCreation.Add(name, emptyObject); - } - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - public object GetObject(string name, Type requiredType) - { - return GetObject(name, requiredType, ObjectUtils.EmptyObjects); - } - - /// - /// Injects dependencies into the supplied instance - /// using the named object definition. - /// - /// - public abstract object ConfigureObject(object target, string name); - - /// - /// Injects dependencies into the supplied instance - /// using the supplied . - /// - /// - public abstract object ConfigureObject(object target, string name, IObjectDefinition definition); - - #endregion - - #region IConfigurableObjectFactory Members - - /// - /// Destroy all cached singletons in this factory. - /// - public virtual void Dispose() - { - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug(string.Format("Destroying singletons in factory [{0}].", this)); - } - - #endregion - - lock (singletonCache) - { - // copy the keys into a new set, 'cos we are going to modifying the - // original collection (_singletonCache) as we destroy each singleton. - ISet keys = new HashedSet(singletonCache.Keys); - foreach (string name in keys) - { - DestroySingleton(name); - } - } - } - - /// - /// Ignore the given dependency type for autowiring - /// - /// . - public void IgnoreDependencyType(Type type) - { - IgnoredDependencyTypes.Add(type); - } - - /// - /// Determines whether the specified object name is currently in creation.. - /// - /// Name of the object. - /// - /// true if the specified object name is currently in creation; otherwise, false. - /// - public bool IsCurrentlyInCreation(string objectName) - { - return IsSingletonCurrentlyInCreation(objectName) || IsPrototypeCurrentlyInCreation(objectName); - } - - private bool IsPrototypeCurrentlyInCreation(string name) - { - //TODO - return false; - } - - private bool IsSingletonCurrentlyInCreation(string name) - { - if (this.singletonsInCreation.Contains(name)) - { - return true; - } - else - { - return false; - } - } - - /// - /// Add a new - /// that will get applied to objects created by this factory. - /// - /// - /// The - /// to register. - /// - /// . - public void AddObjectPostProcessor(IObjectPostProcessor objectPostProcessor) - { - // ensure the same instance doesn't get registered twice - if (!ObjectPostProcessors.Contains(objectPostProcessor)) - { - ObjectPostProcessors.Add(objectPostProcessor); - } - if (typeof (IInstantiationAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor)) - { - hasInstantiationAwareBeanPostProcessors = true; - } - if (typeof (IDestructionAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor)) - { - hasDestructionAwareBeanPostProcessors = true; - } - } - - /// - /// Returns the current number of registered - /// s. - /// - /// - /// The current number of registered - /// s. - /// - /// . - public int ObjectPostProcessorCount - { - get { return ObjectPostProcessors.Count; } - } - - /// - /// Given an object name, create an alias. - /// - /// . - public void RegisterAlias(string name, string alias) - { - #region Sanity Checks - - AssertUtils.ArgumentHasText(name, "The object name must not be empty."); - AssertUtils.ArgumentHasText(alias, "The alias must not be empty."); - - #endregion - - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug(string.Format("Registering alias '{0}' for object with name '{1}'.", alias, name)); - } - - #endregion - - lock (aliasMap) - { - object registeredName = aliasMap[alias]; - if (registeredName != null) + else if (StringUtils.IsNullOrEmpty(mergedObjectDefinition.FactoryMethodName)) { throw new ObjectDefinitionStoreException( - string.Format( - "Cannot register alias '{0}' for object with name '{1}': it's already registered for object name '{2}'.", - alias, name, registeredName)); + "Can only specify arguments in the GetObject () method in " + + "conjunction with a factory method."); } - aliasMap[alias] = name; - } - } - - /// - /// Register the given existing object as singleton in the object factory, - /// under the given object name. - /// - /// . - public void RegisterSingleton(string name, object singletonObject) - { - AssertUtils.ArgumentHasText(name, "name", "The singleton object cannot be registered under an empty name."); - lock (singletonCache) - { - object oldObject = singletonCache[name]; - if (oldObject != null) - { - throw new ObjectDefinitionStoreException( - string.Format( - "Could not register object [{0}] under object name '{1}': there's already object [{2}] bound.", - singletonObject, name, oldObject)); - } - AddSingleton(name, singletonObject); - } - } - - /// - /// Register the given custom - /// for all properties of the given . - /// - /// . - public void RegisterCustomConverter(Type requiredType, TypeConverter converter) - { - AssertUtils.ArgumentNotNull(requiredType, "requiredType"); - TypeConverterRegistry.RegisterConverter(requiredType, converter); - } - - /// - /// Does this object factory contains a singleton instance with the - /// supplied ? - /// - /// - public bool ContainsSingleton(string name) - { - AssertUtils.ArgumentHasText(name, "name"); - lock (singletonCache) - { - return singletonCache.Contains(name); - } - } - - #endregion - } + */ + } + } + + /// + /// Gets the temporary object that is placed + /// into the singleton cache during object resolution. + /// + protected object TemporarySingletonPlaceHolder + { + get { return CURRENTLY_IN_CREATION; } + } + + #endregion + + #region Fields + + /// + /// Parent object factory, for object inheritance support + /// + private IObjectFactory parentObjectFactory; + + /// + /// Dependency types to ignore on dependency check and autowire, as Set of + /// Type objects: for example, string. Default is none. + /// + private ISet ignoreDependencyTypes = new HybridSet(); + + + /// + /// ObjectPostProcessors to apply in CreateObject + /// + private IList objectPostProcessors = new ArrayList(); + + /// + /// Indicates whether any IInstantiationAwareBeanPostProcessors have been registered + /// + private bool hasInstantiationAwareBeanPostProcessors; + + /// + /// Indicates whether any IDestructionAwareBeanPostProcessors have been registered + /// + private bool hasDestructionAwareBeanPostProcessors; + + private bool caseSensitive; + private IDictionary aliasMap; + private IDictionary singletonCache; + private IDictionary singletonsInCreation; + + #endregion + + #region IHierarchicalObjectFactory Members + + /// + /// The parent object factory, or if there is none. + /// + /// + /// The parent object factory, or if there is none. + /// + public IObjectFactory ParentObjectFactory + { + get { return parentObjectFactory; } + set { parentObjectFactory = value; } + } + + #endregion + + #region IObjectFactory Members + + /// + /// Is this object a singleton? + /// + /// + public bool IsSingleton(string name) + { + string objectName = TransformedObjectName(name); + object objectInstance = this.GetSingleton(objectName); + if (objectInstance != null) + { + IFactoryObject factoryObject = objectInstance as IFactoryObject; + if (factoryObject != null) + { + return IsFactoryDereference(name) || factoryObject.IsSingleton; + } + else + { + return !IsFactoryDereference(name); + } + } + else + { + // No singleton instance found -> check object definition + IObjectFactory pof = ParentObjectFactory; + if (pof != null && !ContainsObjectDefinition(objectName)) + { + // No object definition found in this factory -> delegate to parent + return pof.IsSingleton(OriginalObjectName(name)); + } + RootObjectDefinition od = GetMergedObjectDefinition(objectName, false); + + // In case of IFactoryObject, return singleton status of created object if not a dereference + if (od.IsSingleton) + { + if (IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))) + { + if (IsFactoryDereference(name)) + { + return true; + } + IFactoryObject factoryObject = + (IFactoryObject)GetObject(ObjectFactoryUtils.BuildFactoryObjectName(objectName)); + return factoryObject.IsSingleton; + } + else + { + return !IsFactoryDereference(name); + } + } + else + { + return false; + } + } + } + + /// + /// Determines whether the specified object name is prototype. That is, will GetObject + /// always return independent instances? + /// + /// The name of the object to query + /// + /// true if the specified object name will always deliver independent instances; otherwise, false. + /// + /// This method returning false does not clearly indicate a singleton object. + /// It indicated non-independent instances, which may correspond to a scoped object as + /// well. use the IsSingleton property to explicitly check for a shared + /// singleton instance. + /// Translates aliases back to the corresponding canonical object name. Will ask the + /// parent factory if the object can not be found in this factory instance. + /// + /// + /// if there is no object with the given name. + public bool IsPrototype(string name) + { + string objectName = TransformedObjectName(name); + IObjectFactory parentFactory = ParentObjectFactory; + if (parentFactory != null && !this.ContainsObjectDefinition(objectName)) + { + // No object definition found in this factory -> delegate to parent + return parentFactory.IsPrototype(OriginalObjectName(name)); + } + + RootObjectDefinition od = GetMergedObjectDefinition(objectName, false); + + // In case of FactoryObject, return singleton status of created object if not a dereference + if (od.IsPrototype) + { + return (!IsFactoryDereference(name) || IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))); + } + else + { + // not a prototype, however factory object may still produce a prototype object + if (IsFactoryDereference(name) && IsObjectTypeMatch(objectName, od, typeof(IFactoryObject))) + { + IFactoryObject factoryObject = GetFactoryObject(objectName); + return (!factoryObject.IsSingleton); + } + else + { + return false; + } + } + } + + /// + /// Does this object factory contain an object with the given name? + /// + /// + /// This method does not (and it should not) check if the specified + /// object exists in one of the parent object factories. If it did, + /// message sources and event registries within application context + /// hierarchy would have circular references, which would cause stack + /// overflows during message lookup, for example. (A. Seovic) + /// + /// . + public bool ContainsObject(string name) + { + string objectName = TransformedObjectName(name); + lock (singletonCache) + { + if (singletonCache.Contains(objectName)) + { + return true; + } + } + if (ContainsObjectDefinition(objectName)) + { + return true; + } + else + { + return false; + } + } + + /// + /// Return the aliases for the given object name, if defined. + /// + /// . + public string[] GetAliases(string name) + { + string objectName = TransformedObjectName(name); + // check if object actually exists in this object factory... + bool isInSingletonCache = false; + lock (singletonCache) + { + isInSingletonCache = singletonCache.Contains(objectName); + } + if (isInSingletonCache || ContainsObjectDefinition(objectName)) + { + // if found, gather aliases... + ArrayList matches = new ArrayList(); + lock (aliasMap) + { + foreach (DictionaryEntry aliasEntry in aliasMap) + { + if (0 == string.Compare((string)aliasEntry.Value, objectName, !this.IsCaseSensitive)) + { + matches.Add(aliasEntry.Key); + } + } + } + return (string[])matches.ToArray(typeof(string)); + } + + // not found, so check parent... + if (ParentObjectFactory != null) + { + return ParentObjectFactory.GetAliases(objectName); + } + throw new NoSuchObjectDefinitionException(objectName, ToString()); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// . + public object this[string name] + { + get { return GetObject(name); } + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// . + public object GetObject(string name) + { + return GetObject(name, typeof(object), ObjectUtils.EmptyObjects); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + ///

+ /// This method allows an object factory to be used as a replacement for the + /// Singleton or Prototype design pattern. + ///

+ ///

+ /// Note that callers should retain references to returned objects. There is no + /// guarantee that this method will be implemented to be efficient. For example, + /// it may be synchronized, or may need to run an RDBMS query. + ///

+ ///

+ /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + ///

+ ///
+ /// The name of the object to return. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + /// + /// If the supplied is . + /// + public object GetObject(string name, object[] arguments) + { + object instance = null; + string objectName = TransformedObjectName(name); + + // check if object definition exists + RootObjectDefinition mergedObjectDefinition = null; + mergedObjectDefinition = GetMergedObjectDefinition(objectName, false); + if (mergedObjectDefinition == null) + { + if (ParentObjectFactory != null) + { + return ParentObjectFactory.GetObject(name, arguments); + } + throw new NoSuchObjectDefinitionException(name, "Cannot find definition for object [" + name + "]"); + } + + // Override constructor values and configure as a prototype + RootObjectDefinition tmpObjectDefinition = new RootObjectDefinition(mergedObjectDefinition); + tmpObjectDefinition.ConstructorArgumentValues = null; + tmpObjectDefinition.IsSingleton = false; + + // create a new instance... + instance = CreateObject(name, tmpObjectDefinition, arguments); + + return GetObjectForInstance(name, instance); + } + + /// + /// Tries to find a cached object for the specified name. + /// + /// Teh object name to look for. + /// The cached object if found, otherwise. + protected virtual object GetSingleton(string objectName) + { + lock (singletonCache) + { + return singletonCache[objectName]; + } + } + + /// + /// Creates a singleton instance for the specified object name and definition. + /// + /// + /// The object name (will be used as the key in the singleton cache key). + /// + /// The object definition. + /// + /// The arguments to use if creating a prototype using explicit arguments to + /// a static factory method. If there is no factory method and the + /// arguments are not null, then match the argument values by type and + /// call the object's constructor. + /// + /// The created object instance. + protected virtual object CreateAndCacheSingletonInstance(string objectName, + RootObjectDefinition objectDefinition, + object[] arguments) + { + lock (singletonCache) + { + object sharedInstance = singletonCache[objectName]; + if (sharedInstance == null) + { + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug("Creating shared instance of singleton object '" + objectName + "'"); + } + + #endregion + + BeforeSingletonCreation(objectName); + try + { + sharedInstance = CreateObject(objectName, objectDefinition, arguments); + } + finally + { + AfterSingletonCreation(objectName); + } + AddSingleton(objectName, sharedInstance); + } + return sharedInstance; + } + } + + private void AfterSingletonCreation(string name) + { + if (!singletonsInCreation.Contains(name)) + { + throw new InvalidOperationException("Singleton " + name + " isn't currently in creation."); + } + singletonsInCreation.Remove(name); + } + + private void BeforeSingletonCreation(string name) + { + if (this.singletonsInCreation.Contains(name)) + { + throw new ObjectCurrentlyInCreationException(name); + } + singletonsInCreation.Add(name, emptyObject); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + public object GetObject(string name, Type requiredType) + { + return GetObject(name, requiredType, ObjectUtils.EmptyObjects); + } + + /// + /// Injects dependencies into the supplied instance + /// using the named object definition. + /// + /// + public abstract object ConfigureObject(object target, string name); + + /// + /// Injects dependencies into the supplied instance + /// using the supplied . + /// + /// + public abstract object ConfigureObject(object target, string name, IObjectDefinition definition); + + #endregion + + #region IConfigurableObjectFactory Members + + /// + /// Destroy all cached singletons in this factory. + /// + public virtual void Dispose() + { + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Destroying singletons in factory [{0}].", this)); + } + + #endregion + + lock (singletonCache) + { + // copy the keys into a new set, 'cos we are going to modifying the + // original collection (_singletonCache) as we destroy each singleton. + ISet keys = new HashedSet(singletonCache.Keys); + foreach (string name in keys) + { + DestroySingleton(name); + } + } + } + + /// + /// Ignore the given dependency type for autowiring + /// + /// . + public void IgnoreDependencyType(Type type) + { + IgnoredDependencyTypes.Add(type); + } + + /// + /// Determines whether the specified object name is currently in creation.. + /// + /// Name of the object. + /// + /// true if the specified object name is currently in creation; otherwise, false. + /// + public bool IsCurrentlyInCreation(string objectName) + { + return IsSingletonCurrentlyInCreation(objectName) || IsPrototypeCurrentlyInCreation(objectName); + } + + private bool IsPrototypeCurrentlyInCreation(string name) + { + //TODO + return false; + } + + private bool IsSingletonCurrentlyInCreation(string name) + { + if (this.singletonsInCreation.Contains(name)) + { + return true; + } + else + { + return false; + } + } + + /// + /// Add a new + /// that will get applied to objects created by this factory. + /// + /// + /// The + /// to register. + /// + /// . + public void AddObjectPostProcessor(IObjectPostProcessor objectPostProcessor) + { + // ensure the same instance doesn't get registered twice + if (!ObjectPostProcessors.Contains(objectPostProcessor)) + { + ObjectPostProcessors.Add(objectPostProcessor); + } + if (typeof(IInstantiationAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor)) + { + hasInstantiationAwareBeanPostProcessors = true; + } + if (typeof(IDestructionAwareObjectPostProcessor).IsInstanceOfType(objectPostProcessor)) + { + hasDestructionAwareBeanPostProcessors = true; + } + } + + /// + /// Returns the current number of registered + /// s. + /// + /// + /// The current number of registered + /// s. + /// + /// . + public int ObjectPostProcessorCount + { + get { return ObjectPostProcessors.Count; } + } + + /// + /// Given an object name, create an alias. + /// + /// . + public void RegisterAlias(string name, string alias) + { + #region Sanity Checks + + AssertUtils.ArgumentHasText(name, "The object name must not be empty."); + AssertUtils.ArgumentHasText(alias, "The alias must not be empty."); + + #endregion + + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Registering alias '{0}' for object with name '{1}'.", alias, name)); + } + + #endregion + + lock (aliasMap) + { + object registeredName = aliasMap[alias]; + if (registeredName != null) + { + throw new ObjectDefinitionStoreException( + string.Format( + "Cannot register alias '{0}' for object with name '{1}': it's already registered for object name '{2}'.", + alias, name, registeredName)); + } + aliasMap[alias] = name; + } + } + + /// + /// Register the given existing object as singleton in the object factory, + /// under the given object name. + /// + /// . + public void RegisterSingleton(string name, object singletonObject) + { + AssertUtils.ArgumentHasText(name, "name", "The singleton object cannot be registered under an empty name."); + lock (singletonCache) + { + object oldObject = singletonCache[name]; + if (oldObject != null) + { + throw new ObjectDefinitionStoreException( + string.Format( + "Could not register object [{0}] under object name '{1}': there's already object [{2}] bound.", + singletonObject, name, oldObject)); + } + AddSingleton(name, singletonObject); + } + } + + /// + /// Register the given custom + /// for all properties of the given . + /// + /// . + public void RegisterCustomConverter(Type requiredType, TypeConverter converter) + { + AssertUtils.ArgumentNotNull(requiredType, "requiredType"); + TypeConverterRegistry.RegisterConverter(requiredType, converter); + } + + /// + /// Does this object factory contains a singleton instance with the + /// supplied ? + /// + /// + public bool ContainsSingleton(string name) + { + AssertUtils.ArgumentHasText(name, "name"); + lock (singletonCache) + { + return singletonCache.Contains(name); + } + } + + #endregion + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs index 0dac1009..8cee057f 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/DefaultListableObjectFactory.cs @@ -1,892 +1,893 @@ -#region License - -/* - * Copyright © 2002-2005 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 - -#region Imports - -using System; -using System.Collections; -using System.Collections.Specialized; -using System.Globalization; -using Common.Logging; -using Spring.Core; -using Spring.Objects.Factory; -using Spring.Objects.Factory.Config; -using Spring.Util; - -#endregion - -namespace Spring.Objects.Factory.Support -{ - /// - /// Concrete implementation of the - /// and - /// - /// interfaces. - /// - /// - ///

- /// This class is a full-fledged object factory based on object definitions - /// that is usable straight out of the box. - ///

- ///

- /// Can be used as an object factory in and of itself, or as a superclass - /// for custom object factory implementations. Note that readers for - /// specific object definition formats are typically implemented separately - /// rather than as object factory subclasses. - ///

- ///

- /// For an alternative implementation of the - /// interface, - /// have a look at the - /// - /// class, which manages existing object instances rather than creating new - /// ones based on object definitions. - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - /// - [Serializable] - public class DefaultListableObjectFactory : - AbstractAutowireCapableObjectFactory, - IConfigurableListableObjectFactory, - IObjectDefinitionRegistry - { - #region Constructor (s) / Destructor - - /// - /// Creates a new instance of the - /// class. - /// - public DefaultListableObjectFactory() : this(true, null) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// Flag specifying whether to make this object factory case sensitive or not. - public DefaultListableObjectFactory(bool caseSensitive) : this(caseSensitive, null) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// The parent object factory. - public DefaultListableObjectFactory(IObjectFactory parentFactory) - : this(true, parentFactory) - { - } - - /// - /// Creates a new instance of the - /// class. - /// - /// Flag specifying whether to make this object factory case sensitive or not. - /// The parent object factory. - public DefaultListableObjectFactory(bool caseSensitive, IObjectFactory parentFactory) - : base(caseSensitive, parentFactory) - { - if (caseSensitive) - { - objectDefinitionMap = new Hashtable(); - } - else - { - objectDefinitionMap = CollectionsUtil.CreateCaseInsensitiveHashtable(); - } - } - - #endregion - - #region Properties - - /// - /// Should object definitions registered under the same name as an - /// existing object definition be allowed? - /// - /// - ///

- /// If , then the new object definition will - /// replace (override) the existing object definition. If - /// , an exception will be thrown when - /// an attempt is made to register an object definition under the same - /// name as an already existing object definition. - ///

- ///

- /// The default is . - ///

- ///
- /// - /// is the registration of an object definition - /// under the same name as an existing object definition is allowed. - /// - public bool AllowObjectDefinitionOverriding - { - get { return allowObjectDefinitionOverriding; } - set { allowObjectDefinitionOverriding = value; } - } - - #endregion - - #region Methods - - /// - /// Find object instances that match the . - /// - /// - ///

- /// Called by autowiring. If a subclass cannot obtain information about object - /// names by , a corresponding exception should be thrown. - ///

- ///
- /// - /// The type of the objects to look up. - /// - /// - /// An of object names and object - /// instances that match the , or - /// if none is found. - /// - /// - /// In case of errors. - /// - protected override IDictionary FindMatchingObjects(Type requiredType) - { - return ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors( - this, requiredType, true, true); - } - - /// - /// Return the names of the objects that depend on the given object. - /// - /// - ///

- /// Called by the - /// - /// so that dependant objects are able to be disposed of first. - ///

- ///
- /// - /// The name of the object to find depending objects for. - /// - /// - /// The array of names of depending objects, or the empty string array if none. - /// - /// - /// In case of errors. - /// - protected override string[] GetDependingObjectNames(string objectName) - { - ArrayList dependingObjectNames = new ArrayList(); - string[] allObjectDefinitionNames = GetObjectDefinitionNames(); - foreach (string name in allObjectDefinitionNames) - { - if (ContainsObjectDefinition(name)) - { - RootObjectDefinition rod - = GetMergedObjectDefinition(name, false); - if (rod.DependsOn != null) - { - IList dependsOn = new ArrayList(rod.DependsOn); - if (dependsOn.Contains(objectName)) - { - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug(string.Format( - CultureInfo.InvariantCulture, - "Found depending object '{0}' for object '{1}'.", - name, objectName)); - } - - #endregion - - dependingObjectNames.Add(name); - } - } - } - } - return (string[]) dependingObjectNames.ToArray(typeof(string)); - } - - /// - /// Check whether the specified object matches the supplied . - /// - /// The name of the object to check. - /// - /// The to check for. - /// - /// - /// if the object matches the supplied , - /// or if the supplied is . - /// - private bool IsObjectTypeMatch(string objectName, Type type) - { - if (type == null) - { - return true; - } - Type objectType = GetType(objectName); - return (objectType != null && type.IsAssignableFrom(objectType)); - } - - private bool IsObjectDefinitionTypeMatch(string name, Type checkedType) - { - if (checkedType == null) - { - return true; - } - RootObjectDefinition rod = GetMergedObjectDefinition(name, false); - return (rod.HasObjectType && checkedType.IsAssignableFrom(rod.ObjectType)); - } -/* - /// - /// Merges the object definitions. - /// - /// Object definition name. - /// The parent definition. - /// The child definition. - /// Merged object definition. - protected override RootObjectDefinition MergeObjectDefinitions(string name, IObjectDefinition parentDefinition, - IObjectDefinition childDefinition) - { - RootObjectDefinition rootDefinition = base.MergeObjectDefinitions(name, parentDefinition, childDefinition); - RegisterObjectDefinition(name, rootDefinition); - return rootDefinition; - } -*/ - #endregion - - #region Fields - - /// - /// The instance for this class. - /// - private readonly ILog log = LogManager.GetLogger(typeof(DefaultListableObjectFactory)); - - /// - /// Whether to allow re-registration of a different definition with the - /// same name. - /// - private bool allowObjectDefinitionOverriding = true; - - /// - /// The mapping of object definition objects, keyed by object name. - /// - private readonly IDictionary objectDefinitionMap; - - /// - /// List of object definition names, in registration order. - /// - private readonly IList objectDefinitionNames = new ArrayList(); - - #endregion - - #region IObjectDefinitionRegistry Members - - /// - /// Return the number of objects defined in this registry. - /// - /// - /// The number of objects defined in this registry. - /// - /// - public int ObjectDefinitionCount - { - get { return objectDefinitionMap.Count; } - } - - /// - /// Check if this registry contains a object definition with the given - /// name. - /// - /// - /// The name of the object to look for. - /// - /// - /// if this object factory contains an object - /// definition with the given name. - /// - /// - public override bool ContainsObjectDefinition(string name) - { - return objectDefinitionMap.Contains(name); - } - - /// - /// Register a new object definition with this registry. - /// - /// - /// The name of the object instance to register. - /// - /// - /// The definition of the object instance to register. - /// - /// - /// If the object definition is invalid. - /// - /// - public void RegisterObjectDefinition( - string name, IObjectDefinition objectDefinition) - { - if (objectDefinition is AbstractObjectDefinition) - { - try - { - ((AbstractObjectDefinition) objectDefinition).Validate(); - } - catch (ObjectDefinitionValidationException ex) - { - throw new ObjectDefinitionStoreException( - objectDefinition.ResourceDescription, - name, - "Validation of object definition failed.", - ex); - } - } - object oldObjectDefinition = objectDefinitionMap[name]; - if (oldObjectDefinition != null) - { - if (!AllowObjectDefinitionOverriding) - { - throw new ObjectDefinitionStoreException( - string.Format( - "Cannot register object definition [{0}] for object '{1}': there's already [{2}] bound.", - objectDefinition, name, oldObjectDefinition)); - } - else - { - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug( - string.Format( - "Overriding object definition for object '{0}': replacing [{1}] with [{2}].", - name, oldObjectDefinition, objectDefinition)); - } - - #endregion - } - } - else - { - objectDefinitionNames.Add(name); - } - objectDefinitionMap[name] = objectDefinition; - } - - #endregion - - #region IConfigurableListableObjectFactory Members - - /// - /// Ensure that all non-lazy-init singletons are instantiated, also - /// considering s. - /// - /// - /// If one of the singleton objects could not be created. - /// - /// - public void PreInstantiateSingletons() - { - #region Instrumentation - - if (log.IsDebugEnabled) - { - log.Debug("Pre-instantiating singletons in factory [" + this + "]"); - } - - #endregion - - try - { - int definitionCount = objectDefinitionNames.Count; - for (int i = 0; i < definitionCount; i++) - { - string name = (string) objectDefinitionNames[i]; - if (!ContainsSingleton(name) && ContainsObjectDefinition(name)) - { - RootObjectDefinition definition - = GetMergedObjectDefinition(name, false); - if (!definition.IsAbstract - && definition.IsSingleton - && !definition.IsLazyInit) - { - Type objectType = ResolveObjectType(definition, name); - if (objectType != null - && typeof(IFactoryObject).IsAssignableFrom(definition.ObjectType)) - { - IFactoryObject factoryObject = (IFactoryObject) GetObject( - ObjectFactoryUtils. - BuildFactoryObjectName(name)); - if (factoryObject.IsSingleton) - { - GetObject(name); - } - } - else - { - GetObject(name); - } - } - } - } - } - catch (ObjectsException) - { - // destroy already created singletons to avoid dangling resources... - try - { - Dispose(); - } - catch (Exception ex) - { - log.Error( - "PreInstantiateSingletons failed but couldn't destroy any already-created singletons.", - ex); - } - throw; - } - } - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// - /// The registered , - /// or null, if specified object definitions does not exist. - /// - /// - /// If is null or empty string. - /// - /// - public override IObjectDefinition GetObjectDefinition(string name) - { - return GetObjectDefinition(name, false); - } - - /// - /// Return the registered - /// for the - /// given object, allowing access to its property values and constructor - /// argument values. - /// - /// The name of the object. - /// Whether to search parent object factories. - /// - /// The registered , - /// or null, if specified object definitions does not exist. - /// - /// - /// If is null or empty string. - /// - /// - public override IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) - { - if (StringUtils.IsNullOrEmpty(name)) - { - throw new ArgumentException( - "Cannot get an object definition with a null or zero length object name string."); - } - - name = TransformedObjectName(name); - IObjectDefinition definition = (IObjectDefinition) objectDefinitionMap[name]; - if (definition == null) - { - if (!includeAncestors || ParentObjectFactory == null) - { - return null; - } - else if (ParentObjectFactory is AbstractObjectFactory) - { - definition = - ((AbstractObjectFactory) ParentObjectFactory).GetObjectDefinition(name, includeAncestors); - } - } - return definition; - } - - #endregion - - #region IListableObjectFactory Members - - /// - /// Return the names of all objects defined in this factory. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public string[] GetObjectDefinitionNames() - { - return (string[]) ((ArrayList) objectDefinitionNames).ToArray(typeof(string)); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public string[] GetObjectDefinitionNames(Type type) - { - ArrayList matches = new ArrayList(); - foreach (string name in objectDefinitionNames) - { - if (IsObjectDefinitionTypeMatch(name, type)) - { - matches.Add(name); - } - } - return (string[]) matches.ToArray(typeof(string)); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public string[] GetObjectNamesForType(Type type) - { - return GetObjectNamesForType(type, true, true); - } - - /// - /// Return the names of objects matching the given - /// (including subclasses), judging from the object definitions. - /// - /// - /// The (class or interface) to match, or - /// for all object names. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// The names of all objects defined in this factory, or an empty array if none - /// are defined. - /// - /// - public string[] GetObjectNamesForType( - Type type, bool includePrototypes, bool includeFactoryObjects) - { - IList objectNames = DoGetObjectNamesForType(type, includePrototypes, includeFactoryObjects); - return (string[]) ArrayList.Adapter(objectNames).ToArray(typeof(string)); - } - - /// - /// Return the object instances that match the given object - /// (including subclasses), judging from either object - /// definitions or the value of - /// in the case of - /// s. - /// - /// - /// The (class or interface) to match. - /// - /// - /// A of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If the objects could not be created. - /// - /// - public IDictionary GetObjectsOfType(Type type) - { - return GetObjectsOfType(type, true, true); - } - - /// - /// Return the object instances that match the given object - /// (including subclasses). - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// An of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If any of the objects could not be created. - /// - /// - public IDictionary GetObjectsOfType( - Type type, bool includePrototypes, bool includeFactoryObjects) - { - IDictionary result = new Hashtable(); - IList objectNames = DoGetObjectNamesForType(type, includePrototypes, includeFactoryObjects); - foreach (string objectName in objectNames) - { - try - { - result.Add(objectName, GetObject(objectName)); - } - catch (ObjectCreationException ex) - { - if (ex.InnerException != null - && ex.GetBaseException().GetType().Equals(typeof(ObjectCurrentlyInCreationException))) - { - // ignoring this is ok... it indicates a circular reference when autowiring - // constructors; we want to find matches other than the currently - // created object itself... - if (log.IsDebugEnabled) - { - log.Debug(string.Format( - CultureInfo.InvariantCulture, - "Ignoring match to currently created object '{0}'.", - objectName), ex); - } - } - else - { - throw; - } - } - } - return result; - } - - // TODO: (ee) What's this method for? It's never used. -/* - protected IList DoGetObjectNamesForTypeNew(Type type, bool includePrototypes, bool includeFactoryObjects) - { - IList result = new ArrayList(); - string[] objectNames = GetObjectDefinitionNames(); - foreach (string objectNam in objectNames) - { - string objectName = objectNam; - if (!IsAlias(objectName)) - { - RootObjectDefinition mod = GetMergedObjectDefinition(objectName, false); - // Only check object definition if it is complete - if (!mod.IsAbstract && - (mod.HasObjectType || !mod.IsLazyInit)) - { - // In case of FactoryObject, match object created by FactoryObject - } - try - { - bool isFactoryObject = IsObjectTypeMatch(objectName, mod, typeof(IFactoryObject)); - bool matchFound = (includePrototypes || mod.IsSingleton) && IsTypeMatch(objectName, type); - if (!matchFound && isFactoryObject) - { - objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); - matchFound = (includePrototypes || mod.IsSingleton) && IsTypeMatch(objectName, type); - } - if (matchFound) - { - result.Add(objectName); - } - } - catch (CannotLoadObjectTypeException ex) - { - // Probably contains a placeholder; lets ignore it for type matching purposes. - if (log.IsDebugEnabled) - { - log.Debug("Ignoring object class loading failure for object '" + objectName + "'", ex); - } - } - } - } - // check singletons too, to catch manually registered singletons... - string[] singletonNames = GetSingletonNames(); - foreach (string objectNam in singletonNames) - { - string objectName = objectNam; - // only check if manually registered... - if (!ContainsObjectDefinition(objectName)) - { - // in the case of an IFactoryObject, match the object created by the IFactoryObject... - if (IsFactoryObject(objectName)) - { - if ((includePrototypes || IsSingleton(objectName)) && IsTypeMatch(objectName, type)) - { - result.Add(objectName); - continue; - } - objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); - } - if (IsTypeMatch(objectName, type)) - { - result.Add(objectName); - } - } - } - return result; - } -*/ - - /// - /// Return the object instances that match the given object - /// (including subclasses). - /// - /// - /// The (class or interface) to match. - /// - /// - /// Whether to include prototype objects too or just singletons (also applies to - /// s). - /// - /// - /// Whether to include s too - /// or just normal objects. - /// - /// - /// An of the matching objects, - /// containing the object names as keys and the corresponding object instances - /// as values. - /// - /// - /// If any of the objects could not be created. - /// - /// - protected IList DoGetObjectNamesForType( - Type type, bool includePrototypes, bool includeFactoryObjects) - { - bool isFactoryType = (type != null && typeof(IFactoryObject).IsAssignableFrom(type)); - IList result = new ArrayList(); - if (type != null) - { - string[] objectNames = GetObjectDefinitionNames(); - foreach (string objectName in objectNames) - { - RootObjectDefinition rod = GetMergedObjectDefinition(objectName, false); - // only check complete object definitions... - if (!rod.IsAbstract && rod.HasObjectType) - { - // return the return type of an object created via a factory method... - if (StringUtils.HasText(rod.FactoryMethodName)) - { - Type methodType = GetTypeForFactoryMethod(objectName, rod); - if (methodType != null - && type.IsAssignableFrom(methodType)) - { - result.Add(objectName); - } - } - // in the case of an IFactoryObject, match the object created by the IFactoryObject... - else if (typeof(IFactoryObject).IsAssignableFrom(rod.ObjectType) && !isFactoryType) - { - if (includeFactoryObjects && (includePrototypes || IsSingleton(objectName)) && - IsObjectTypeMatch(objectName, type)) - { - result.Add(objectName); - } - } - else - { - string factoryObjectName = objectName; - // if type to match is an IFactoryObject, match the IFactoryObject itself; - // else, match the object instance... - if (isFactoryType) - { - factoryObjectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); - } - if ((includePrototypes || rod.IsSingleton) && //MLP - (type.IsAssignableFrom(rod.ObjectType))) - { - result.Add(factoryObjectName); - } - } - } - } - - // check singletons too, to catch manually registered singletons... - string[] singletonNames = GetSingletonNames(); - foreach (string objectName in singletonNames) - { - // only check if manually registered... - if (!ContainsObjectDefinition(objectName)) - { - // in the case of an IFactoryObject, match the object created by the IFactoryObject... - if (IsFactoryObject(objectName) && !isFactoryType) - { - if (includeFactoryObjects && (includePrototypes || IsSingleton(objectName)) && - IsObjectTypeMatch(objectName, type)) - { - result.Add(objectName); - } - } - else - { - string factoryObjectName = objectName; - // if type to match is an IFactoryObject, match the IFactoryObject itself... - // else, match the object instance... - if (isFactoryType) - { - factoryObjectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); - } - if (IsObjectTypeMatch(factoryObjectName, type)) - { - result.Add(factoryObjectName); - } - } - } - } - } - return result; - } - - #endregion - } -} \ No newline at end of file +#region License + +/* + * Copyright © 2002-2005 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 + +#region Imports + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Globalization; +using Common.Logging; +using Spring.Collections; +using Spring.Core; +using Spring.Objects.Factory; +using Spring.Objects.Factory.Config; +using Spring.Util; + +#endregion + +namespace Spring.Objects.Factory.Support +{ + /// + /// Concrete implementation of the + /// and + /// + /// interfaces. + /// + /// + ///

+ /// This class is a full-fledged object factory based on object definitions + /// that is usable straight out of the box. + ///

+ ///

+ /// Can be used as an object factory in and of itself, or as a superclass + /// for custom object factory implementations. Note that readers for + /// specific object definition formats are typically implemented separately + /// rather than as object factory subclasses. + ///

+ ///

+ /// For an alternative implementation of the + /// interface, + /// have a look at the + /// + /// class, which manages existing object instances rather than creating new + /// ones based on object definitions. + ///

+ ///
+ /// Juergen Hoeller + /// Rick Evans (.NET) + /// + [Serializable] + public class DefaultListableObjectFactory : + AbstractAutowireCapableObjectFactory, + IConfigurableListableObjectFactory, + IObjectDefinitionRegistry + { + #region Constructor (s) / Destructor + + /// + /// Creates a new instance of the + /// class. + /// + public DefaultListableObjectFactory() : this(true, null) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// Flag specifying whether to make this object factory case sensitive or not. + public DefaultListableObjectFactory(bool caseSensitive) : this(caseSensitive, null) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// The parent object factory. + public DefaultListableObjectFactory(IObjectFactory parentFactory) + : this(true, parentFactory) + { + } + + /// + /// Creates a new instance of the + /// class. + /// + /// Flag specifying whether to make this object factory case sensitive or not. + /// The parent object factory. + public DefaultListableObjectFactory(bool caseSensitive, IObjectFactory parentFactory) + : base(caseSensitive, parentFactory) + { + if (caseSensitive) + { + objectDefinitionMap = new Hashtable(); + } + else + { + objectDefinitionMap = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); + } + } + + #endregion + + #region Properties + + /// + /// Should object definitions registered under the same name as an + /// existing object definition be allowed? + /// + /// + ///

+ /// If , then the new object definition will + /// replace (override) the existing object definition. If + /// , an exception will be thrown when + /// an attempt is made to register an object definition under the same + /// name as an already existing object definition. + ///

+ ///

+ /// The default is . + ///

+ ///
+ /// + /// is the registration of an object definition + /// under the same name as an existing object definition is allowed. + /// + public bool AllowObjectDefinitionOverriding + { + get { return allowObjectDefinitionOverriding; } + set { allowObjectDefinitionOverriding = value; } + } + + #endregion + + #region Methods + + /// + /// Find object instances that match the . + /// + /// + ///

+ /// Called by autowiring. If a subclass cannot obtain information about object + /// names by , a corresponding exception should be thrown. + ///

+ ///
+ /// + /// The type of the objects to look up. + /// + /// + /// An of object names and object + /// instances that match the , or + /// if none is found. + /// + /// + /// In case of errors. + /// + protected override IDictionary FindMatchingObjects(Type requiredType) + { + return ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors( + this, requiredType, true, true); + } + + /// + /// Return the names of the objects that depend on the given object. + /// + /// + ///

+ /// Called by the + /// + /// so that dependant objects are able to be disposed of first. + ///

+ ///
+ /// + /// The name of the object to find depending objects for. + /// + /// + /// The array of names of depending objects, or the empty string array if none. + /// + /// + /// In case of errors. + /// + protected override string[] GetDependingObjectNames(string objectName) + { + ArrayList dependingObjectNames = new ArrayList(); + string[] allObjectDefinitionNames = GetObjectDefinitionNames(); + foreach (string name in allObjectDefinitionNames) + { + if (ContainsObjectDefinition(name)) + { + RootObjectDefinition rod + = GetMergedObjectDefinition(name, false); + if (rod.DependsOn != null) + { + IList dependsOn = new ArrayList(rod.DependsOn); + if (dependsOn.Contains(objectName)) + { + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug(string.Format( + CultureInfo.InvariantCulture, + "Found depending object '{0}' for object '{1}'.", + name, objectName)); + } + + #endregion + + dependingObjectNames.Add(name); + } + } + } + } + return (string[]) dependingObjectNames.ToArray(typeof(string)); + } + + /// + /// Check whether the specified object matches the supplied . + /// + /// The name of the object to check. + /// + /// The to check for. + /// + /// + /// if the object matches the supplied , + /// or if the supplied is . + /// + private bool IsObjectTypeMatch(string objectName, Type type) + { + if (type == null) + { + return true; + } + Type objectType = GetType(objectName); + return (objectType != null && type.IsAssignableFrom(objectType)); + } + + private bool IsObjectDefinitionTypeMatch(string name, Type checkedType) + { + if (checkedType == null) + { + return true; + } + RootObjectDefinition rod = GetMergedObjectDefinition(name, false); + return (rod.HasObjectType && checkedType.IsAssignableFrom(rod.ObjectType)); + } +/* + /// + /// Merges the object definitions. + /// + /// Object definition name. + /// The parent definition. + /// The child definition. + /// Merged object definition. + protected override RootObjectDefinition MergeObjectDefinitions(string name, IObjectDefinition parentDefinition, + IObjectDefinition childDefinition) + { + RootObjectDefinition rootDefinition = base.MergeObjectDefinitions(name, parentDefinition, childDefinition); + RegisterObjectDefinition(name, rootDefinition); + return rootDefinition; + } +*/ + #endregion + + #region Fields + + /// + /// The instance for this class. + /// + private readonly ILog log = LogManager.GetLogger(typeof(DefaultListableObjectFactory)); + + /// + /// Whether to allow re-registration of a different definition with the + /// same name. + /// + private bool allowObjectDefinitionOverriding = true; + + /// + /// The mapping of object definition objects, keyed by object name. + /// + private readonly IDictionary objectDefinitionMap; + + /// + /// List of object definition names, in registration order. + /// + private readonly IList objectDefinitionNames = new ArrayList(); + + #endregion + + #region IObjectDefinitionRegistry Members + + /// + /// Return the number of objects defined in this registry. + /// + /// + /// The number of objects defined in this registry. + /// + /// + public int ObjectDefinitionCount + { + get { return objectDefinitionMap.Count; } + } + + /// + /// Check if this registry contains a object definition with the given + /// name. + /// + /// + /// The name of the object to look for. + /// + /// + /// if this object factory contains an object + /// definition with the given name. + /// + /// + public override bool ContainsObjectDefinition(string name) + { + return objectDefinitionMap.Contains(name); + } + + /// + /// Register a new object definition with this registry. + /// + /// + /// The name of the object instance to register. + /// + /// + /// The definition of the object instance to register. + /// + /// + /// If the object definition is invalid. + /// + /// + public void RegisterObjectDefinition( + string name, IObjectDefinition objectDefinition) + { + if (objectDefinition is AbstractObjectDefinition) + { + try + { + ((AbstractObjectDefinition) objectDefinition).Validate(); + } + catch (ObjectDefinitionValidationException ex) + { + throw new ObjectDefinitionStoreException( + objectDefinition.ResourceDescription, + name, + "Validation of object definition failed.", + ex); + } + } + object oldObjectDefinition = objectDefinitionMap[name]; + if (oldObjectDefinition != null) + { + if (!AllowObjectDefinitionOverriding) + { + throw new ObjectDefinitionStoreException( + string.Format( + "Cannot register object definition [{0}] for object '{1}': there's already [{2}] bound.", + objectDefinition, name, oldObjectDefinition)); + } + else + { + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug( + string.Format( + "Overriding object definition for object '{0}': replacing [{1}] with [{2}].", + name, oldObjectDefinition, objectDefinition)); + } + + #endregion + } + } + else + { + objectDefinitionNames.Add(name); + } + objectDefinitionMap[name] = objectDefinition; + } + + #endregion + + #region IConfigurableListableObjectFactory Members + + /// + /// Ensure that all non-lazy-init singletons are instantiated, also + /// considering s. + /// + /// + /// If one of the singleton objects could not be created. + /// + /// + public void PreInstantiateSingletons() + { + #region Instrumentation + + if (log.IsDebugEnabled) + { + log.Debug("Pre-instantiating singletons in factory [" + this + "]"); + } + + #endregion + + try + { + int definitionCount = objectDefinitionNames.Count; + for (int i = 0; i < definitionCount; i++) + { + string name = (string) objectDefinitionNames[i]; + if (!ContainsSingleton(name) && ContainsObjectDefinition(name)) + { + RootObjectDefinition definition + = GetMergedObjectDefinition(name, false); + if (!definition.IsAbstract + && definition.IsSingleton + && !definition.IsLazyInit) + { + Type objectType = ResolveObjectType(definition, name); + if (objectType != null + && typeof(IFactoryObject).IsAssignableFrom(definition.ObjectType)) + { + IFactoryObject factoryObject = (IFactoryObject) GetObject( + ObjectFactoryUtils. + BuildFactoryObjectName(name)); + if (factoryObject.IsSingleton) + { + GetObject(name); + } + } + else + { + GetObject(name); + } + } + } + } + } + catch (ObjectsException) + { + // destroy already created singletons to avoid dangling resources... + try + { + Dispose(); + } + catch (Exception ex) + { + log.Error( + "PreInstantiateSingletons failed but couldn't destroy any already-created singletons.", + ex); + } + throw; + } + } + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// + /// The registered , + /// or null, if specified object definitions does not exist. + /// + /// + /// If is null or empty string. + /// + /// + public override IObjectDefinition GetObjectDefinition(string name) + { + return GetObjectDefinition(name, false); + } + + /// + /// Return the registered + /// for the + /// given object, allowing access to its property values and constructor + /// argument values. + /// + /// The name of the object. + /// Whether to search parent object factories. + /// + /// The registered , + /// or null, if specified object definitions does not exist. + /// + /// + /// If is null or empty string. + /// + /// + public override IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) + { + if (StringUtils.IsNullOrEmpty(name)) + { + throw new ArgumentException( + "Cannot get an object definition with a null or zero length object name string."); + } + + name = TransformedObjectName(name); + IObjectDefinition definition = (IObjectDefinition) objectDefinitionMap[name]; + if (definition == null) + { + if (!includeAncestors || ParentObjectFactory == null) + { + return null; + } + else if (ParentObjectFactory is AbstractObjectFactory) + { + definition = + ((AbstractObjectFactory) ParentObjectFactory).GetObjectDefinition(name, includeAncestors); + } + } + return definition; + } + + #endregion + + #region IListableObjectFactory Members + + /// + /// Return the names of all objects defined in this factory. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public string[] GetObjectDefinitionNames() + { + return (string[]) ((ArrayList) objectDefinitionNames).ToArray(typeof(string)); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public string[] GetObjectDefinitionNames(Type type) + { + ArrayList matches = new ArrayList(); + foreach (string name in objectDefinitionNames) + { + if (IsObjectDefinitionTypeMatch(name, type)) + { + matches.Add(name); + } + } + return (string[]) matches.ToArray(typeof(string)); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public string[] GetObjectNamesForType(Type type) + { + return GetObjectNamesForType(type, true, true); + } + + /// + /// Return the names of objects matching the given + /// (including subclasses), judging from the object definitions. + /// + /// + /// The (class or interface) to match, or + /// for all object names. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// The names of all objects defined in this factory, or an empty array if none + /// are defined. + /// + /// + public string[] GetObjectNamesForType( + Type type, bool includePrototypes, bool includeFactoryObjects) + { + IList objectNames = DoGetObjectNamesForType(type, includePrototypes, includeFactoryObjects); + return (string[]) ArrayList.Adapter(objectNames).ToArray(typeof(string)); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses), judging from either object + /// definitions or the value of + /// in the case of + /// s. + /// + /// + /// The (class or interface) to match. + /// + /// + /// A of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If the objects could not be created. + /// + /// + public IDictionary GetObjectsOfType(Type type) + { + return GetObjectsOfType(type, true, true); + } + + /// + /// Return the object instances that match the given object + /// (including subclasses). + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// An of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If any of the objects could not be created. + /// + /// + public IDictionary GetObjectsOfType( + Type type, bool includePrototypes, bool includeFactoryObjects) + { + IDictionary result = new Hashtable(); + IList objectNames = DoGetObjectNamesForType(type, includePrototypes, includeFactoryObjects); + foreach (string objectName in objectNames) + { + try + { + result.Add(objectName, GetObject(objectName)); + } + catch (ObjectCreationException ex) + { + if (ex.InnerException != null + && ex.GetBaseException().GetType().Equals(typeof(ObjectCurrentlyInCreationException))) + { + // ignoring this is ok... it indicates a circular reference when autowiring + // constructors; we want to find matches other than the currently + // created object itself... + if (log.IsDebugEnabled) + { + log.Debug(string.Format( + CultureInfo.InvariantCulture, + "Ignoring match to currently created object '{0}'.", + objectName), ex); + } + } + else + { + throw; + } + } + } + return result; + } + + // TODO: (ee) What's this method for? It's never used. +/* + protected IList DoGetObjectNamesForTypeNew(Type type, bool includePrototypes, bool includeFactoryObjects) + { + IList result = new ArrayList(); + string[] objectNames = GetObjectDefinitionNames(); + foreach (string objectNam in objectNames) + { + string objectName = objectNam; + if (!IsAlias(objectName)) + { + RootObjectDefinition mod = GetMergedObjectDefinition(objectName, false); + // Only check object definition if it is complete + if (!mod.IsAbstract && + (mod.HasObjectType || !mod.IsLazyInit)) + { + // In case of FactoryObject, match object created by FactoryObject + } + try + { + bool isFactoryObject = IsObjectTypeMatch(objectName, mod, typeof(IFactoryObject)); + bool matchFound = (includePrototypes || mod.IsSingleton) && IsTypeMatch(objectName, type); + if (!matchFound && isFactoryObject) + { + objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); + matchFound = (includePrototypes || mod.IsSingleton) && IsTypeMatch(objectName, type); + } + if (matchFound) + { + result.Add(objectName); + } + } + catch (CannotLoadObjectTypeException ex) + { + // Probably contains a placeholder; lets ignore it for type matching purposes. + if (log.IsDebugEnabled) + { + log.Debug("Ignoring object class loading failure for object '" + objectName + "'", ex); + } + } + } + } + // check singletons too, to catch manually registered singletons... + string[] singletonNames = GetSingletonNames(); + foreach (string objectNam in singletonNames) + { + string objectName = objectNam; + // only check if manually registered... + if (!ContainsObjectDefinition(objectName)) + { + // in the case of an IFactoryObject, match the object created by the IFactoryObject... + if (IsFactoryObject(objectName)) + { + if ((includePrototypes || IsSingleton(objectName)) && IsTypeMatch(objectName, type)) + { + result.Add(objectName); + continue; + } + objectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); + } + if (IsTypeMatch(objectName, type)) + { + result.Add(objectName); + } + } + } + return result; + } +*/ + + /// + /// Return the object instances that match the given object + /// (including subclasses). + /// + /// + /// The (class or interface) to match. + /// + /// + /// Whether to include prototype objects too or just singletons (also applies to + /// s). + /// + /// + /// Whether to include s too + /// or just normal objects. + /// + /// + /// An of the matching objects, + /// containing the object names as keys and the corresponding object instances + /// as values. + /// + /// + /// If any of the objects could not be created. + /// + /// + protected IList DoGetObjectNamesForType( + Type type, bool includePrototypes, bool includeFactoryObjects) + { + bool isFactoryType = (type != null && typeof(IFactoryObject).IsAssignableFrom(type)); + IList result = new ArrayList(); + if (type != null) + { + string[] objectNames = GetObjectDefinitionNames(); + foreach (string objectName in objectNames) + { + RootObjectDefinition rod = GetMergedObjectDefinition(objectName, false); + // only check complete object definitions... + if (!rod.IsAbstract && rod.HasObjectType) + { + // return the return type of an object created via a factory method... + if (StringUtils.HasText(rod.FactoryMethodName)) + { + Type methodType = GetTypeForFactoryMethod(objectName, rod); + if (methodType != null + && type.IsAssignableFrom(methodType)) + { + result.Add(objectName); + } + } + // in the case of an IFactoryObject, match the object created by the IFactoryObject... + else if (typeof(IFactoryObject).IsAssignableFrom(rod.ObjectType) && !isFactoryType) + { + if (includeFactoryObjects && (includePrototypes || IsSingleton(objectName)) && + IsObjectTypeMatch(objectName, type)) + { + result.Add(objectName); + } + } + else + { + string factoryObjectName = objectName; + // if type to match is an IFactoryObject, match the IFactoryObject itself; + // else, match the object instance... + if (isFactoryType) + { + factoryObjectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); + } + if ((includePrototypes || rod.IsSingleton) && //MLP + (type.IsAssignableFrom(rod.ObjectType))) + { + result.Add(factoryObjectName); + } + } + } + } + + // check singletons too, to catch manually registered singletons... + string[] singletonNames = GetSingletonNames(); + foreach (string objectName in singletonNames) + { + // only check if manually registered... + if (!ContainsObjectDefinition(objectName)) + { + // in the case of an IFactoryObject, match the object created by the IFactoryObject... + if (IsFactoryObject(objectName) && !isFactoryType) + { + if (includeFactoryObjects && (includePrototypes || IsSingleton(objectName)) && + IsObjectTypeMatch(objectName, type)) + { + result.Add(objectName); + } + } + else + { + string factoryObjectName = objectName; + // if type to match is an IFactoryObject, match the IFactoryObject itself... + // else, match the object instance... + if (isFactoryType) + { + factoryObjectName = ObjectFactoryUtils.BuildFactoryObjectName(objectName); + } + if (IsObjectTypeMatch(factoryObjectName, type)) + { + result.Add(factoryObjectName); + } + } + } + } + } + return result; + } + + #endregion + } +} diff --git a/src/Spring/Spring.Core/Spring.Core.2003.csproj b/src/Spring/Spring.Core/Spring.Core.2003.csproj index ed343a7d..050dc9b6 100644 --- a/src/Spring/Spring.Core/Spring.Core.2003.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2003.csproj @@ -162,6 +162,11 @@ SubType = "Code" BuildAction = "Compile" /> + Code + Code diff --git a/src/Spring/Spring.Core/Util/DynamicCodeManager.cs b/src/Spring/Spring.Core/Util/DynamicCodeManager.cs index ac0873eb..6ed6aac9 100644 --- a/src/Spring/Spring.Core/Util/DynamicCodeManager.cs +++ b/src/Spring/Spring.Core/Util/DynamicCodeManager.cs @@ -1,143 +1,144 @@ -#region License - -/* - * Copyright © 2002-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 - -#region Imports - -using System; -using System.Collections; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Reflection; -using System.Reflection.Emit; - -#endregion - -namespace Spring.Util -{ - /// - /// Use this class for obtaining instances for dynamic code generation. - /// - /// - ///

- /// The purpose of this class is to provide a simple abstraction for creating and managing dynamic assemblies. - ///

- /// - /// Using this factory you can't define several modules within a single dynamic assembly - only a simple one2one relation between assembly/module is used. - /// - ///
- /// - ///

The following excerpt from demonstrates usage:

- /// - /// public class DynamicProxyManager - /// { - /// public const string PROXY_ASSEMBLY_NAME = "Spring.Proxy"; - /// - /// public static TypeBuilder CreateTypeBuilder(string name, Type baseType) - /// { - /// // Generates type name - /// string typeName = String.Format("{0}.{1}_{2}", PROXY_ASSEMBLY_NAME, name, Guid.NewGuid().ToString("N")); - /// ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(PROXY_ASSEMBLY_NAME); - /// return module.DefineType(typeName, PROXY_TYPE_ATTRIBUTES); - /// } - /// } - /// - ///
- /// Erich Eichinger - /// - /// - /// - public sealed class DynamicCodeManager - { - private static readonly Hashtable s_moduleCache = CollectionsUtil.CreateCaseInsensitiveHashtable(); - - /// - /// prevent instantiation - /// - private DynamicCodeManager() - { - throw new InvalidOperationException(); - } - - /// - /// Returns the for the dynamic module within the specified assembly. - /// - /// - /// If the assembly does not exist yet, it will be created.
- /// This factory caches any dynamic assembly it creates - calling GetModule() twice with - /// the same name will *not* create 2 distinct modules! - ///
- /// The assembly-name of the module to be returned - /// the that can be used to define new types within the specified assembly - public static ModuleBuilder GetModuleBuilder( string assemblyName ) - { - lock(s_moduleCache.SyncRoot) - { - ModuleBuilder module = (ModuleBuilder) s_moduleCache[assemblyName]; - if (module == null) - { - AssemblyName an = new AssemblyName(); - an.Name = assemblyName; - - AssemblyBuilder assembly; -#if DEBUG_DYNAMIC - assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, null, null, null, null,null, true ); - module = assembly.DefineDynamicModule(an.Name, an.Name + ".dll", true); -#else - assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run, null, null, null, null,null, true ); -#if DEBUG - module = assembly.DefineDynamicModule(an.Name, true); -#else - module = assembly.DefineDynamicModule(an.Name, false); -#endif -#endif - s_moduleCache[assemblyName] = module; - } - return module; - } - } - - /// - /// Persists the specified dynamic assembly to the file-system - /// - /// the name of the dynamic assembly to persist - /// - /// Can only be called in DEBUG_DYNAMIC mode, per ConditionalAttribute rules. - /// - [Conditional("DEBUG_DYNAMIC")] - public static void SaveAssembly( string assemblyName ) - { - AssertUtils.ArgumentHasText(assemblyName, "assemblyName"); - - ModuleBuilder module = null; - lock(s_moduleCache.SyncRoot) - { - module = (ModuleBuilder) s_moduleCache[assemblyName]; - } - - if(module == null) - { - throw new ArgumentException(string.Format("'{0}' is not a valid dynamic assembly name", assemblyName), "assemblyName"); - } - - AssemblyBuilder assembly = (AssemblyBuilder) module.Assembly; - assembly.Save(assembly.GetName().Name + ".dll"); - } - } +#region License + +/* + * Copyright © 2002-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 + +#region Imports + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Diagnostics; +using System.Reflection; +using System.Reflection.Emit; +using Spring.Collections; + +#endregion + +namespace Spring.Util +{ + /// + /// Use this class for obtaining instances for dynamic code generation. + /// + /// + ///

+ /// The purpose of this class is to provide a simple abstraction for creating and managing dynamic assemblies. + ///

+ /// + /// Using this factory you can't define several modules within a single dynamic assembly - only a simple one2one relation between assembly/module is used. + /// + ///
+ /// + ///

The following excerpt from demonstrates usage:

+ /// + /// public class DynamicProxyManager + /// { + /// public const string PROXY_ASSEMBLY_NAME = "Spring.Proxy"; + /// + /// public static TypeBuilder CreateTypeBuilder(string name, Type baseType) + /// { + /// // Generates type name + /// string typeName = String.Format("{0}.{1}_{2}", PROXY_ASSEMBLY_NAME, name, Guid.NewGuid().ToString("N")); + /// ModuleBuilder module = DynamicCodeManager.GetModuleBuilder(PROXY_ASSEMBLY_NAME); + /// return module.DefineType(typeName, PROXY_TYPE_ATTRIBUTES); + /// } + /// } + /// + ///
+ /// Erich Eichinger + /// + /// + /// + public sealed class DynamicCodeManager + { + private static readonly Hashtable s_moduleCache = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); + + /// + /// prevent instantiation + /// + private DynamicCodeManager() + { + throw new InvalidOperationException(); + } + + /// + /// Returns the for the dynamic module within the specified assembly. + /// + /// + /// If the assembly does not exist yet, it will be created.
+ /// This factory caches any dynamic assembly it creates - calling GetModule() twice with + /// the same name will *not* create 2 distinct modules! + ///
+ /// The assembly-name of the module to be returned + /// the that can be used to define new types within the specified assembly + public static ModuleBuilder GetModuleBuilder( string assemblyName ) + { + lock(s_moduleCache.SyncRoot) + { + ModuleBuilder module = (ModuleBuilder) s_moduleCache[assemblyName]; + if (module == null) + { + AssemblyName an = new AssemblyName(); + an.Name = assemblyName; + + AssemblyBuilder assembly; +#if DEBUG_DYNAMIC + assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave, null, null, null, null,null, true ); + module = assembly.DefineDynamicModule(an.Name, an.Name + ".dll", true); +#else + assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run, null, null, null, null,null, true ); +#if DEBUG + module = assembly.DefineDynamicModule(an.Name, true); +#else + module = assembly.DefineDynamicModule(an.Name, false); +#endif +#endif + s_moduleCache[assemblyName] = module; + } + return module; + } + } + + /// + /// Persists the specified dynamic assembly to the file-system + /// + /// the name of the dynamic assembly to persist + /// + /// Can only be called in DEBUG_DYNAMIC mode, per ConditionalAttribute rules. + /// + [Conditional("DEBUG_DYNAMIC")] + public static void SaveAssembly( string assemblyName ) + { + AssertUtils.ArgumentHasText(assemblyName, "assemblyName"); + + ModuleBuilder module = null; + lock(s_moduleCache.SyncRoot) + { + module = (ModuleBuilder) s_moduleCache[assemblyName]; + } + + if(module == null) + { + throw new ArgumentException(string.Format("'{0}' is not a valid dynamic assembly name", assemblyName), "assemblyName"); + } + + AssemblyBuilder assembly = (AssemblyBuilder) module.Assembly; + assembly.Save(assembly.GetName().Name + ".dll"); + } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Data/Spring.Data.2003.csproj b/src/Spring/Spring.Data/Spring.Data.2003.csproj index 368c5db1..375af481 100644 --- a/src/Spring/Spring.Data/Spring.Data.2003.csproj +++ b/src/Spring/Spring.Data/Spring.Data.2003.csproj @@ -506,6 +506,11 @@ SubType = "Code" BuildAction = "Compile" /> + + + + + - private static readonly Hashtable s_webContextCache = CollectionsUtil.CreateCaseInsensitiveHashtable(); + private static readonly Hashtable s_webContextCache = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); static WebApplicationContext() { diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs index 9e09a065..d3ca6dd5 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs @@ -27,6 +27,7 @@ using System.Web; using System.Web.Caching; using System.Web.SessionState; using Common.Logging; +using Spring.Collections; using Spring.Context.Support; using Spring.Objects.Factory.Config; using Spring.Util; @@ -50,6 +51,7 @@ namespace Spring.Objects.Factory.Support { private readonly static ILog log = LogManager.GetLogger(typeof(WebObjectFactory)); + private static bool s_eventHandlersRegistered = false; private readonly static string OBJECTTABLEKEY = "spring.objects"; private delegate IDictionary ObjectDictionaryCreationHandler(); @@ -68,7 +70,7 @@ namespace Spring.Objects.Factory.Support static WebObjectFactory() { - EnsureEventHandlersRegistered(); + //EnsureEventHandlersRegistered(); } /// @@ -77,9 +79,19 @@ namespace Spring.Objects.Factory.Support /// private static void EnsureEventHandlersRegistered() { - if (log.IsDebugEnabled) log.Debug("hooking up event handlers"); - VirtualEnvironment.EndRequest += new VirtualEnvironment.RequestEventHandler(OnEndRequest); - VirtualEnvironment.EndSession += new VirtualEnvironment.SessionEventHandler(OnEndSession); + if (!s_eventHandlersRegistered) + { + lock(typeof(WebObjectFactory)) + { + if (s_eventHandlersRegistered) return; + + if (log.IsDebugEnabled) log.Debug("hooking up event handlers"); + VirtualEnvironment.EndRequest += new VirtualEnvironment.RequestEventHandler(OnEndRequest); + VirtualEnvironment.EndSession += new VirtualEnvironment.SessionEventHandler(OnEndSession); + + s_eventHandlersRegistered = true; + } + } } /// @@ -303,6 +315,8 @@ namespace Spring.Objects.Factory.Support object instance; lock (scopedSingletonCache.SyncRoot) { + EnsureEventHandlersRegistered(); + instance = scopedSingletonCache[objectName]; if (instance == TemporarySingletonPlaceHolder) { @@ -397,23 +411,26 @@ namespace Spring.Objects.Factory.Support } /// - /// Injects dependencies into the supplied instance - /// using the named object definition. + /// Configures object instance by injecting dependencies, satisfying Spring lifecycle + /// interfaces and applying object post-processors. /// - /// - /// The object instance that is to be so configured. - /// /// /// The name of the object definition expressing the dependencies that are to /// be injected into the supplied instance. /// + /// + /// An object definition that should be used to configure object. + /// + /// + /// A wrapped object instance that is to be so configured. + /// /// - public override object ConfigureObject(object target, string name) + protected override object ConfigureObject(string name, RootObjectDefinition definition, IObjectWrapper wrapper) { // always configure object relative to contextPath using (new HttpContextSwitch(contextPath)) { - return base.ConfigureObject(target, name); + return base.ConfigureObject(name, definition, wrapper); } } @@ -482,7 +499,7 @@ namespace Spring.Objects.Factory.Support /// private static IDictionary CreateCaseInsensitiveDictionary() { - return CollectionsUtil.CreateCaseInsensitiveHashtable(); + return new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); } /// diff --git a/src/Spring/Spring.Web/Spring.Web.2003.csproj b/src/Spring/Spring.Web/Spring.Web.2003.csproj index fb6e4f56..1c814e1a 100644 --- a/src/Spring/Spring.Web/Spring.Web.2003.csproj +++ b/src/Spring/Spring.Web/Spring.Web.2003.csproj @@ -275,6 +275,11 @@ SubType = "Code" BuildAction = "Compile" /> + Code + diff --git a/src/Spring/Spring.Web/Util/ISessionState.cs b/src/Spring/Spring.Web/Util/ISessionState.cs new file mode 100644 index 00000000..0f2498a9 --- /dev/null +++ b/src/Spring/Spring.Web/Util/ISessionState.cs @@ -0,0 +1,48 @@ +using System.Collections; +using System.Web; +using System.Web.SessionState; + +namespace Spring.Util +{ + /// + /// Abstracts HttpSession + /// + public interface ISessionState : IDictionary + { + /// + /// + /// + void Abandon(); + /// + /// + /// + bool IsCookieless { get; } + /// + /// + /// + bool IsNewSession { get; } + /// + /// + /// + int LCID { get; set; } + /// + /// + /// + SessionStateMode Mode { get; } + /// + /// + /// + string SessionID { get; } + /// + /// + /// + int CodePage { get; set; } + +#if NET_2_0 + /// + /// + /// + HttpCookieMode CookieMode { get; } +#endif + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Util/IVirtualEnvironment.cs b/src/Spring/Spring.Web/Util/IVirtualEnvironment.cs index 1ef9331f..cafa3aa3 100644 --- a/src/Spring/Spring.Web/Util/IVirtualEnvironment.cs +++ b/src/Spring/Spring.Web/Util/IVirtualEnvironment.cs @@ -21,6 +21,7 @@ #region Imports using System; +using System.Collections; using System.Globalization; using System.Reflection; using System.Web; @@ -66,5 +67,14 @@ namespace Spring.Util /// Maps a virtual path to it's physical location /// string MapPath( string virtualPath ); + /// + /// Returns the current Session's variable dictionary + /// + ISessionState Session { get; } + /// + /// Returns the current Request's variable dictionary + /// + IDictionary RequestVariables { get; } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Util/VirtualEnvironment.cs b/src/Spring/Spring.Web/Util/VirtualEnvironment.cs index 9b0e5513..b7be76af 100644 --- a/src/Spring/Spring.Web/Util/VirtualEnvironment.cs +++ b/src/Spring/Spring.Web/Util/VirtualEnvironment.cs @@ -21,6 +21,7 @@ #region Imports using System; +using System.Collections; using System.IO; using System.Web; using System.Web.Caching; @@ -71,16 +72,167 @@ namespace Spring.Util return prevEnvironment; } - #region default IVirtualEnvironment Adapter for HttpRuntime + #region default IVirtualEnvironment Adapter for HttpRuntime /// /// Implementation for running within HttpRuntime /// private class HttpRuntimeEnvironment : IVirtualEnvironment { + #region HttpSessionState Adapter + + private class SessionDictionaryAdapter : ISessionState + { + private readonly HttpSessionState _sessionState; + + public SessionDictionaryAdapter(HttpSessionState sessionState) + { + _sessionState = sessionState; + } + + + public bool Contains(object key) + { + ICollection keys = _sessionState.Keys; + foreach (string sessionKey in keys) + { + if (object.Equals(sessionKey, (string)key)) return true; + } + return false; + } + + public void Add(object key, object value) + { + _sessionState.Add((string)key, value); + } + + public void Clear() + { + _sessionState.Clear(); + } + + public IDictionaryEnumerator GetEnumerator() + { + Hashtable tableCopy = new Hashtable(); + ICollection keys = _sessionState.Keys; + foreach (string sessionKey in keys) + { + tableCopy.Add(sessionKey, _sessionState[sessionKey]); + } + return tableCopy.GetEnumerator(); + } + + public void Remove(object key) + { + _sessionState.Remove((string) key); + } + + public object this[object key] + { + get { return _sessionState[(string)key]; } + set { _sessionState[(string)key] = value; } + } + + public ICollection Keys + { + get { return _sessionState.Keys; } + } + + public ICollection Values + { + get + { + object[] values = new object[_sessionState.Count]; + _sessionState.CopyTo(values, 0); + return values; + } + } + + public bool IsReadOnly + { + get { return _sessionState.IsReadOnly; } + } + + public bool IsFixedSize + { + get { return false; } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void CopyTo(Array array, int index) + { + _sessionState.CopyTo(array, index); + } + + public int Count + { + get { return _sessionState.Count; } + } + + public object SyncRoot + { + get { return _sessionState.SyncRoot; } + } + + public bool IsSynchronized + { + get { return _sessionState.IsSynchronized; } + } + + public void Abandon() + { + _sessionState.Abandon(); + } + + public bool IsCookieless + { + get { return _sessionState.IsCookieless; } + } + + public bool IsNewSession + { + get { return _sessionState.IsNewSession; } + } + + public int LCID + { + get { return _sessionState.LCID; } + set { _sessionState.LCID = value; } + } + + public SessionStateMode Mode + { + get { return _sessionState.Mode; } + } + + public string SessionID + { + get { return _sessionState.SessionID; } + } + + public int CodePage + { + get { return _sessionState.CodePage; } + set { _sessionState.CodePage = value; } + } +#if NET_2_0 + public HttpCookieMode CookieMode + { + get { return _sessionState.CookieMode; } + } +#endif + } + + #endregion //HttpSessionState Adapter + public string ApplicationVirtualPath { - get { + get + { string appPath = HttpRuntime.AppDomainAppVirtualPath; if (!appPath.EndsWith("/")) appPath = appPath + "/"; return appPath; @@ -124,6 +276,16 @@ namespace Spring.Util #endif throw new ArgumentException("can't map context relative path outside a context"); } + + public ISessionState Session + { + get { return new SessionDictionaryAdapter(HttpContext.Current.Session); } + } + + public IDictionary RequestVariables + { + get { return HttpContext.Current.Items; } + } } #endregion diff --git a/src/Spring/Spring.Web/Web/Support/AbstractProcessHandler.cs b/src/Spring/Spring.Web/Web/Support/AbstractProcessHandler.cs index 96588e88..4937a6d9 100644 --- a/src/Spring/Spring.Web/Web/Support/AbstractProcessHandler.cs +++ b/src/Spring/Spring.Web/Web/Support/AbstractProcessHandler.cs @@ -25,6 +25,7 @@ using System.Collections; using System.Collections.Specialized; using System.Web; using System.Web.SessionState; +using Spring.Collections; using Spring.Context; using Spring.Util; using Spring.Web.Process; @@ -52,7 +53,7 @@ namespace Spring.Web.Support private object controller; private string defaultView; private string currentView; - private IDictionary views = CollectionsUtil.CreateCaseInsensitiveHashtable(); + private IDictionary views = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); private IDictionary sharedState; private IApplicationContext applicationContext; private string processUrl; diff --git a/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs index 02527e19..dfda7610 100644 --- a/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs @@ -70,7 +70,7 @@ namespace Spring.Web.Support { private readonly ILog Log = LogManager.GetLogger(typeof(PageHandlerFactory)); - private readonly IDictionary pageHandlerWrappers = CollectionsUtil.CreateCaseInsensitiveHashtable(); + private readonly IDictionary pageHandlerWrappers = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); /// /// Retrieves instance of the configured page from Spring web application context, diff --git a/test/Spring/Spring.Core.Tests/Collections/CaseInsensitiveHashtableTests.cs b/test/Spring/Spring.Core.Tests/Collections/CaseInsensitiveHashtableTests.cs new file mode 100644 index 00000000..e371b458 --- /dev/null +++ b/test/Spring/Spring.Core.Tests/Collections/CaseInsensitiveHashtableTests.cs @@ -0,0 +1,116 @@ +#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 + +#region Imports + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Globalization; +using NUnit.Framework; + +#endregion + +namespace Spring.Collections +{ + /// + /// + /// + /// Erich Eichinger + [TestFixture] + public class CaseInsensitiveHashtableTests + { + [Test] + public void IgnoresCase() + { + CaseInsensitiveHashtable st = new CaseInsensitiveHashtable(); + st.Add("key", "value"); + Assert.AreEqual("value", st["KEY"]); + st["KeY"] = "value2"; + Assert.AreEqual(1, st.Count); + Assert.AreEqual("value2", st["key"]); + + try + { + st.Add("KEY", "value2"); + Assert.Fail(); + } + catch (ArgumentException) + {} + + Hashtable ht = new Hashtable(); + ht.Add("key","value"); + ht.Add("KEY","value"); + try + { + st = new CaseInsensitiveHashtable(ht, CultureInfo.InvariantCulture); + Assert.Fail(); + } + catch (ArgumentException) + {} + } + + [Test] + public void InitializeFromOtherCopiesValues() + { + Hashtable ht = new Hashtable(); + ht["key"] = "value"; + ht["key2"] = "value2"; + + CaseInsensitiveHashtable st = new CaseInsensitiveHashtable(ht, CultureInfo.InvariantCulture); + Assert.AreEqual(2, st.Count); + ht.Remove("key"); + Assert.AreEqual(1, ht.Count); + Assert.AreEqual(2, st.Count); + } + + /// + /// On my NB gives + /// Duration: 00:00:11.0937500 + /// Duration: 00:00:05.3593750 + /// + [Test, Explicit] + public void ComparePerformance() + { + const int runs = 30000000; + StopWatch watch = new StopWatch(); + + Hashtable ht = CollectionsUtil.CreateCaseInsensitiveHashtable(); + for(int i=0;i<1000000;i++) ht.Add(Guid.NewGuid().ToString(), "val"); // gen. higher number of elements results in OOM exception???? + CaseInsensitiveHashtable ciht = new CaseInsensitiveHashtable(ht, CultureInfo.InvariantCulture); + + using (watch.Start("Duration: {0}")) + { + for (int i = 0; i < runs; i++) + { + object v = ht["somekey"]; + } + } + + using (watch.Start("Duration: {0}")) + { + for (int i = 0; i < runs; i++) + { + object v = ciht["somekey"]; + } + } + } + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Collections/SynchronizedHashtableTests.cs b/test/Spring/Spring.Core.Tests/Collections/SynchronizedHashtableTests.cs index 423e5a3e..a3113c20 100644 --- a/test/Spring/Spring.Core.Tests/Collections/SynchronizedHashtableTests.cs +++ b/test/Spring/Spring.Core.Tests/Collections/SynchronizedHashtableTests.cs @@ -37,10 +37,100 @@ namespace Spring.Collections [TestFixture] public class SynchronizedHashtableTests { + [Test] + public void BehavesLikeHashtable() + { + SynchronizedHashtable st = new SynchronizedHashtable(); + st.Add("key", "value"); + Assert.AreEqual("value", st["key"]); + st["key"] = "value2"; + Assert.AreEqual("value2", st["key"]); + st["key2"] = "value3"; + Assert.AreEqual("value3", st["key2"]); + + try + { + st.Add("key", "value4"); + Assert.Fail(); + } + catch(ArgumentException) + {} + + Assert.AreEqual(2, st.Count); + } + + [Test] + public void InitializeFromOtherCopiesValues() + { + Hashtable ht = new Hashtable(); + ht["key"] = "value"; + ht["key2"] = "value2"; + + SynchronizedHashtable st = new SynchronizedHashtable(ht, false); + Assert.AreEqual(2, st.Count); + ht.Remove("key"); + Assert.AreEqual(1, ht.Count); + Assert.AreEqual(2, st.Count); + } + + [Test] + public void DefaultsToCaseSensitive() + { + SynchronizedHashtable st = new SynchronizedHashtable(); + st.Add("key","value"); + st.Add("KEY","value"); + Assert.AreEqual(2, st.Count); + } + + [Test] + public void IgnoreCaseIgnoresCase() + { + SynchronizedHashtable st = new SynchronizedHashtable(true); + st.Add("key", "value"); + Assert.AreEqual("value", st["KEY"]); + st["KeY"] = "value2"; + Assert.AreEqual(1, st.Count); + Assert.AreEqual("value2", st["key"]); + + try + { + st.Add("KEY", "value2"); + Assert.Fail(); + } + catch (ArgumentException) + {} + + Hashtable ht = new Hashtable(); + ht.Add("key","value"); + ht.Add("KEY","value"); + try + { + st = new SynchronizedHashtable(ht, true); + Assert.Fail(); + } + catch (ArgumentException) + {} + } + + [Test] + public void WrapKeepsOriginalHashtableReference() + { + Hashtable ht = new Hashtable(); + ht["key"] = "value"; + ht["key2"] = "value2"; + + SynchronizedHashtable st = SynchronizedHashtable.Wrap(ht); + Assert.AreEqual(2, st.Count); + ht.Remove("key"); + Assert.AreEqual(1, ht.Count); + Assert.AreEqual(1, st.Count); + } + /// /// On my Notebook gives - /// Normal Hashtable: 00:00:01.5937500 - /// Synced Hashtable: 00:00:02.8593750 + /// Normal Hashtable: 00:00:00.0937500 + /// Synced Hashtable: 00:00:00.9375000 + /// =locking *has* a peformance impact. /// [Test, Explicit] public void TestLockingPerformanceImpact() diff --git a/test/Spring/Spring.Core.Tests/Expressions/ConstructorNodeTests.cs b/test/Spring/Spring.Core.Tests/Expressions/ConstructorNodeTests.cs new file mode 100644 index 00000000..41094963 --- /dev/null +++ b/test/Spring/Spring.Core.Tests/Expressions/ConstructorNodeTests.cs @@ -0,0 +1,112 @@ +#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 + +#region Imports + +using System; +using NUnit.Framework; + +#endregion + +namespace Spring.Expressions +{ + /// + /// + /// + /// Erich Eichinger + [TestFixture] + public class ConstructorNodeTests + { + #region Test Classes + + public class PublicTestClass + { + public string _s; + public int _i; + + public PublicTestClass(string s) + :this(s, -1) + {} + + protected PublicTestClass(string s, int i) + { + _s = s; _i=i; + } + } + + private class PrivateTestClass : PublicTestClass + { + private PrivateTestClass(string s, int i) + :base(s,i) + { + } + } + + #endregion Test Classes + + [Test] + public void CanCreatePublicInstance() + { + ConstructorNode ctorNode = new ConstructorNode(); + ctorNode.Text=typeof(PublicTestClass).FullName; + StringLiteralNode sNode = new StringLiteralNode(); + sNode.Text = "theValue"; + ctorNode.addChild(sNode); + + PublicTestClass instance = (PublicTestClass) ((IExpression)ctorNode).GetValue(); + Assert.AreEqual( sNode.Text, instance._s ); + Assert.AreEqual( -1, instance._i ); + } + + [Test] + public void CanCreatePublicInstanceWithNonPublicConstructor() + { + ConstructorNode ctorNode = new ConstructorNode(); + ctorNode.Text=typeof(PublicTestClass).FullName; + StringLiteralNode sNode = new StringLiteralNode(); + sNode.Text = "theValue2"; + ctorNode.addChild(sNode); + IntLiteralNode iNode = new IntLiteralNode(); + iNode.Text="2"; + ctorNode.addChild(iNode); + + PublicTestClass instance = (PublicTestClass) ((IExpression)ctorNode).GetValue(); + Assert.AreEqual( sNode.Text, instance._s ); + Assert.AreEqual( 2, instance._i ); + } + + [Test] + public void CanCreateNonPublicInstanceWithNonPublicConstructor() + { + ConstructorNode ctorNode = new ConstructorNode(); + ctorNode.Text=typeof(PrivateTestClass).FullName; + StringLiteralNode sNode = new StringLiteralNode(); + sNode.Text = "theValue3"; + ctorNode.addChild(sNode); + IntLiteralNode iNode = new IntLiteralNode(); + iNode.Text="3"; + ctorNode.addChild(iNode); + + PublicTestClass instance = (PublicTestClass) ((IExpression)ctorNode).GetValue(); + Assert.AreEqual( sNode.Text, instance._s ); + Assert.AreEqual( 3, instance._i ); + } + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs index df71117a..3c487562 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs @@ -22,12 +22,51 @@ using System; using NUnit.Framework; +using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; #endregion namespace Spring.Objects.Factory { + public class TestAbstractObjectFactory : AbstractObjectFactory + { + protected override object CreateObject(string name, RootObjectDefinition definition, object[] arguments) + { + throw new System.NotImplementedException(); + } + + protected override void DestroyObject(string name, object target) + { + throw new System.NotImplementedException(); + } + + public override bool ContainsObjectDefinition(string name) + { + throw new System.NotImplementedException(); + } + + public override IObjectDefinition GetObjectDefinition(string name) + { + throw new System.NotImplementedException(); + } + + public override IObjectDefinition GetObjectDefinition(string name, bool includeAncestors) + { + throw new System.NotImplementedException(); + } + + public override object ConfigureObject(object target, string name) + { + throw new System.NotImplementedException(); + } + + public override object ConfigureObject(object target, string name, IObjectDefinition definition) + { + throw new System.NotImplementedException(); + } + } + /// /// Subclasses must override SetUp () to initialize the object factory /// and any other variables they need. @@ -38,13 +77,43 @@ namespace Spring.Objects.Factory { #region Properties - protected internal abstract IObjectFactory ObjectFactory { get; } + protected internal abstract AbstractObjectFactory CreateObjectFactory(bool caseSensitive); - #endregion + protected AbstractObjectFactory ObjectFactory { get { return CreateObjectFactory(true); } } + + #endregion - #region Tests + #region Case Insensitive Tests - /// + [Test] + public void RespectsCaseInsensitiveNamesAndAliases() + { + AbstractObjectFactory of = CreateObjectFactory(false); + + object testObject = new object(); + of.RegisterSingleton("name", testObject); + of.RegisterAlias("NAME", "alias"); + + try + { + of.RegisterAlias("NaMe", "AlIaS"); + Assert.Fail(); + } + catch (ObjectDefinitionStoreException ex) + { + Assert.IsTrue( -1 /// Roderick objects inherits from rod, overriding name only. /// [Test] diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs index 15d4ebea..a2ff36bd 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Xml/XmlListableObjectFactoryTests.cs @@ -69,9 +69,11 @@ namespace Spring.Objects.Factory.Xml #endregion - protected internal override IObjectFactory ObjectFactory + protected internal override AbstractObjectFactory CreateObjectFactory(bool caseSensitive) { - get { return factory; } + return (caseSensitive) + ? factory + : new DefaultListableObjectFactory(caseSensitive); } private DefaultListableObjectFactory parent; diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2003.csproj b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2003.csproj index 8d232e5c..532ab9f5 100644 --- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2003.csproj +++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2003.csproj @@ -252,6 +252,11 @@ SubType = "Code" BuildAction = "Compile" /> + Code + Code @@ -270,6 +271,7 @@ Code + Code diff --git a/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2003.csproj b/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2003.csproj index 50782b0a..f6cc51f9 100644 --- a/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2003.csproj +++ b/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2003.csproj @@ -140,6 +140,11 @@ HintPath = "..\..\..\lib\Net\1.1\nunit.core.interfaces.dll" Private = "False" /> + @@ -172,11 +177,24 @@ RelPath = "Context\Support\HttpApplicationConfigurerTests.xml" BuildAction = "EmbeddedResource" /> + + + + Code + ASPXCodeBehind diff --git a/test/Spring/Spring.Web.Tests/TestSupport/SessionMock.cs b/test/Spring/Spring.Web.Tests/TestSupport/SessionMock.cs new file mode 100644 index 00000000..8a0b3168 --- /dev/null +++ b/test/Spring/Spring.Web.Tests/TestSupport/SessionMock.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections; +using System.Web; +using System.Web.SessionState; +using Spring.Util; + +namespace Spring.TestSupport +{ + /// + /// Test Session implementation + /// + public class SessionMock : Hashtable, ISessionState + { + private bool _isCookieless; + private bool _isNewSession; + private int _lcid; + private SessionStateMode _mode; + private string _sessionID; + private int _codePage; +#if NET_2_0 + private HttpCookieMode _cookieMode; +#endif + public SessionMock() : base(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default) + { + Reset(); + } + + protected virtual void Reset() + { + _sessionID = Guid.NewGuid().ToString(); + _isNewSession = false; + _isCookieless = false; + _mode = SessionStateMode.InProc; + _codePage = -1; +#if NET_2_0 + _cookieMode = HttpCookieMode.AutoDetect; +#endif + } + + public void Abandon() + { + Reset(); + } + + public bool IsCookieless + { + get { return _isCookieless; } + set { _isCookieless = value; } + } + + public bool IsNewSession + { + get { return _isNewSession; } + set { _isNewSession = value; } + } + + public int LCID + { + get { return _lcid; } + set { _lcid = value; } + } + + public SessionStateMode Mode + { + get { return _mode; } + set { _mode = value; } + } + + public string SessionID + { + get { return _sessionID; } + set { _sessionID = value; } + } + + public int CodePage + { + get { return _codePage; } + set { _codePage = value; } + } + +#if NET_2_0 + public HttpCookieMode CookieMode + { + get { return _cookieMode; } + set { _cookieMode = value; } + } +#endif + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Web.Tests/TestSupport/TestPage.cs b/test/Spring/Spring.Web.Tests/TestSupport/TestPage.cs index ff9e781a..f0bc6ccd 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/TestPage.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/TestPage.cs @@ -5,6 +5,7 @@ using System.IO; using System.Reflection; using System.Web; using System.Web.UI; +using Spring.Collections; using Page=Spring.Web.UI.Page; namespace Spring.TestSupport @@ -13,7 +14,7 @@ namespace Spring.TestSupport { public TestPage() { - this.SharedState = CollectionsUtil.CreateCaseInsensitiveHashtable(); + this.SharedState = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); } public TestPage( HttpContext context ) diff --git a/test/Spring/Spring.Web.Tests/TestSupport/TestWebContext.cs b/test/Spring/Spring.Web.Tests/TestSupport/TestWebContext.cs index 62d5c1fa..50a1ff34 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/TestWebContext.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/TestWebContext.cs @@ -21,11 +21,16 @@ #region Imports using System; +using System.Collections; using System.Collections.Specialized; using System.IO; +using System.Reflection; using System.Threading; using System.Web; using System.Web.Hosting; +using Spring.Collections; +using Spring.Expressions; +using Spring.Reflection.Dynamic; #endregion @@ -35,7 +40,8 @@ namespace Spring.TestSupport { private readonly TextWriter _out; private readonly HttpWorkerRequest _wr; - [ThreadStatic] private static TestWebContext _wc; + [ThreadStatic] + private static TestWebContext _wc; public static void Create(string virtualPath, string page) { @@ -54,24 +60,34 @@ namespace Spring.TestSupport { _out = new StringWriter(); HttpWorkerRequest wr; - object appPath = Thread.GetDomain().GetData(".appPath"); + AppDomain domain = Thread.GetDomain(); + + // are we running within a valid AspNet AppDomain? + string appPath = (string) domain.GetData(".appPath"); if (appPath != null) { wr = new SimpleWorkerRequest(page, string.Empty, _out); } else { - string physDir = AppDomain.CurrentDomain.BaseDirectory + "\\"; - wr = new SimpleWorkerRequest(virtualPath, physDir, page, string.Empty, _out); + appPath = domain.BaseDirectory + "\\"; + wr = new SimpleWorkerRequest(virtualPath, appPath, page, string.Empty, _out); } HttpContext ctx = new HttpContext(wr); HttpContext.Current = ctx; HttpBrowserCapabilities browser = new HttpBrowserCapabilities(); #if NET_2_0 - browser.Capabilities = CollectionsUtil.CreateCaseInsensitiveHashtable(); + browser.Capabilities = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); browser.Capabilities[string.Empty] = "Test User Agent"; // string.Empty is the key for "user agent" + + // avoids NullReferenceException when accessing HttpRequest.FilePath + object virtualPathObject = ExpressionEvaluator.GetValue(null, "T(System.Web.VirtualPath).Create('/')"); + object cachedPathData = ExpressionEvaluator.GetValue(null, "T(System.Web.CachedPathData).GetRootWebPathData()"); + ExpressionEvaluator.SetValue(cachedPathData, "_virtualPath", virtualPathObject); + ExpressionEvaluator.SetValue(cachedPathData, "_physicalPath", appPath); #endif ctx.Request.Browser = browser; + string filePath = ctx.Request.FilePath; _wr = wr; } diff --git a/test/Spring/Spring.Web.Tests/TestSupport/VirtualEnvironmentMock.cs b/test/Spring/Spring.Web.Tests/TestSupport/VirtualEnvironmentMock.cs index d1abb1cf..f3ecb342 100644 --- a/test/Spring/Spring.Web.Tests/TestSupport/VirtualEnvironmentMock.cs +++ b/test/Spring/Spring.Web.Tests/TestSupport/VirtualEnvironmentMock.cs @@ -1,5 +1,8 @@ using System; +using System.Collections; +using System.Collections.Specialized; using System.IO; +using Spring.Collections; using Spring.Util; namespace Spring.TestSupport @@ -8,7 +11,7 @@ namespace Spring.TestSupport /// Test environment implementation. /// /// Erich Eichinger - internal class VirtualEnvironmentMock : IVirtualEnvironment, IDisposable + public class VirtualEnvironmentMock : IVirtualEnvironment, IDisposable { private readonly IVirtualEnvironment _prevEnvironment; @@ -16,6 +19,8 @@ namespace Spring.TestSupport private readonly string _pathInfo; private string _currentExecutionFilePath; private readonly string _applicationVirtualPath; + private ISessionState _session = new SessionMock(); + private IDictionary _requestVariables = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); public VirtualEnvironmentMock(string currentVirtualFilePath, string pathInfo, string applicationVirtualPath, bool autoInitialize) { @@ -63,6 +68,18 @@ namespace Spring.TestSupport return resultPath; } + public ISessionState Session + { + get { return _session; } + set { _session = value; } + } + + public IDictionary RequestVariables + { + get { return _requestVariables; } + set { _requestVariables = value; } + } + public void Dispose() { VirtualEnvironment.SetInstance(_prevEnvironment); diff --git a/test/Spring/Spring.Web.Tests/Util/WebDIPerformanceTests.cs b/test/Spring/Spring.Web.Tests/Util/WebDIPerformanceTests.cs index 313a6c5d..d57b015d 100644 --- a/test/Spring/Spring.Web.Tests/Util/WebDIPerformanceTests.cs +++ b/test/Spring/Spring.Web.Tests/Util/WebDIPerformanceTests.cs @@ -21,11 +21,15 @@ #region Imports using System; +using System.Collections.Specialized; using System.Data; using System.Web.UI.WebControls; +using Common.Logging; +using Common.Logging.Simple; using NUnit.Framework; using Spring.Context; using Spring.Context.Support; +using Spring.Objects.Factory.Support; using Spring.TestSupport; #if NET_2_0 @@ -86,20 +90,36 @@ namespace Spring.Util [Test, Explicit] public void RunTestWithDI() { +// LogManager.Adapter = new Common.Logging.Simple.TraceLoggerFactoryAdapter(); + DataView dv = CreateDataSource(); - IApplicationContext ctx = new StaticApplicationContext(); - - int runs = 1000; - - StopWatch watch = new StopWatch(); - using (watch.Start("Duration: {0}")) + using (TestWebContext wctx = new TestWebContext("/testpath", "testpage.aspx")) { - for (int i = 0; i < runs; i++) + IApplicationContext ctx = new WebApplicationContext(); + + int runs = 1000; + + StopWatch watch = new StopWatch(); + using (watch.Start("Duration: {0}")) { - DataGrid grid = new DataGrid(); - Spring.Web.Support.WebDependencyInjectionUtils.InjectDependenciesRecursive(ctx, grid); - grid.DataSource = dv; - grid.DataBind(); + for (int i = 0; i < runs; i++) + { + DataGrid grid = new DataGrid(); + Spring.Web.Support.WebDependencyInjectionUtils.InjectDependenciesRecursive(ctx, grid); + grid.DataSource = dv; + grid.DataBind(); + } + } + + using (watch.Start("Duration: {0}")) + { + for (int i = 0; i < runs; i++) + { + DataGrid grid = new DataGrid(); + grid.DataSource = dv; + grid.DataBind(); + Spring.Web.Support.WebDependencyInjectionUtils.InjectDependenciesRecursive(ctx, grid); + } } } } @@ -112,7 +132,7 @@ namespace Spring.Util Hashtable ht = new Hashtable(); Dictionary dict = new Dictionary(); - for(int i = 0; i < 100000; i++) + for (int i = 0; i < 100000; i++) { ht.Add(i, new object()); dict.Add(new object(), new object());