diff --git a/BreakingChanges-1.2.txt b/BreakingChanges-1.2.txt index 0a22cca6..b8c6713c 100644 --- a/BreakingChanges-1.2.txt +++ b/BreakingChanges-1.2.txt @@ -1,4 +1,4 @@ -Changes (1.1.2 to 1.2 M1) +Changes (1.1.2 to 1.2 RC1) Spring.Core ----------- @@ -21,4 +21,14 @@ Spring.Data Spring.Services --------------- 1. Removed WebServiceProxyFactory.ClientProtocolType property (obsolete) + 2. WebServiceExporter generates WebServiceBinding attribute with WSI basic profile 1.1 by default. + +Spring.Web +---------- + +1. Moved Spring.Web.Support.ISharedStateAware to Spring.Objects.ISharedStateAware + +2. Dropped IProcess support + +3. IHttpHandler instance dependencies won't be injected until PreRequestHandlerExecute stage (to support "session"-scoped deps) diff --git a/src/Spring/Spring.Core/Collections/DictionarySet.cs b/src/Spring/Spring.Core/Collections/DictionarySet.cs index 1e06dcd1..36a50bd1 100644 --- a/src/Spring/Spring.Core/Collections/DictionarySet.cs +++ b/src/Spring/Spring.Core/Collections/DictionarySet.cs @@ -1,393 +1,391 @@ -/* Copyright © 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */ - -#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; - -#endregion - -namespace Spring.Collections -{ - /// - /// is an - /// class that supports the creation of new - /// types where the underlying data - /// store is an instance. - /// - /// - ///

- /// You can use any object that implements the - /// interface to hold set - /// data. You can define your own, or you can use one of the objects - /// provided in the framework. The type of - /// you - /// choose will affect both the performance and the behavior of the - /// using it. - ///

- ///

- /// This object overrides the method, - /// but not the method, because - /// the class is mutable. - /// Therefore, it is not safe to use as a key value in a dictionary. - ///

- ///

- /// To make a typed based on your - /// own , simply derive a new - /// class with a constructor that takes no parameters. Some - /// implmentations cannot be defined - /// with a default constructor. If this is the case for your class, you - /// will need to override clone as well. - ///

- ///

- /// It is also standard practice that at least one of your constructors - /// takes an or an - /// as an argument. - ///

- ///
- /// - [Serializable] - public abstract class DictionarySet : Set - { - private IDictionary _internalDictionary; - - private static readonly object PlaceholderObject = new object(); - private static readonly object NullPlaceHolderKey = new object(); - - /// - /// Provides the storage for elements in the - /// , stored as the key-set - /// of the object. - /// - /// - ///

- /// Set this object in the constructor if you create your own - /// class. - ///

- ///
- protected IDictionary InternalDictionary - { - get { return _internalDictionary; } - set { _internalDictionary = value; } - } - - /// - /// The placeholder object used as the value for the - /// instance. - /// - /// - /// There is a single instance of this object globally, used for all - /// s. - /// - protected static object Placeholder - { - get { return PlaceholderObject; } - } - - /// - /// Adds the specified element to this set if it is not already present. - /// - /// The object to add to the set. - /// - /// is the object was added, - /// if the object was already present. - /// - public override bool Add(object element) - { - element = MaskNull(element); - if (InternalDictionary[element] != null) - { - return false; - } - else - { - //The object we are adding is just a placeholder. The thing we are - //really concerned with is 'o', the key. - InternalDictionary.Add(element, PlaceholderObject); - return true; - } - } - - /// - /// Adds all the elements in the specified collection to the set if - /// they are not already present. - /// - /// A collection of objects to add to the set. - /// - /// is the set changed as a result of this - /// operation. - /// - public override bool AddAll(ICollection collection) - { - bool changed = false; - foreach (object o in collection) - { - changed |= this.Add(o); - } - return changed; - } - - /// - /// Removes all objects from this set. - /// - public override void Clear() - { - InternalDictionary.Clear(); - } - - /// - /// Returns if this set contains the specified - /// element. - /// - /// The element to look for. - /// - /// if this set contains the specified element. - /// - public override bool Contains(object element) - { - element = MaskNull(element); - return InternalDictionary[element] != null; - } - - /// - /// Returns if the set contains all the - /// elements in the specified collection. - /// - /// A collection of objects. - /// - /// if the set contains all the elements in the - /// specified collection; also if the - /// supplied is . - /// - public override bool ContainsAll(ICollection collection) - { - if(collection == null) - { - return false; - } - foreach (object o in collection) - { - if (!this.Contains(MaskNull(o))) - { - return false; - } - } - return true; - } - - /// - /// Returns if this set contains no elements. - /// - public override bool IsEmpty - { - get { return InternalDictionary.Count == 0; } - } - - /// - /// Removes the specified element from the set. - /// - /// The element to be removed. - /// - /// if the set contained the specified element. - /// - public override bool Remove(object element) - { - element = MaskNull(element); - bool contained = this.Contains(element); - if (contained) - { - InternalDictionary.Remove(element); - } - return contained; - } - - /// - /// Remove all the specified elements from this set, if they exist in - /// this set. - /// - /// A collection of elements to remove. - /// - /// if the set was modified as a result of this - /// operation. - /// - public override bool RemoveAll(ICollection collection) - { - bool changed = false; - foreach (object o in collection) - { - changed |= this.Remove(o); - } - return changed; - } - - /// - /// Retains only the elements in this set that are contained in the - /// specified collection. - /// - /// - /// The collection that defines the set of elements to be retained. - /// - /// - /// if this set changed as a result of this - /// operation. - /// - public override bool RetainAll(ICollection collection) - { - //Put data from C into a set so we can use the Contains() method. - Set cSet = new HybridSet(collection); - - //We are going to build a set of elements to remove. - Set removeSet = new HybridSet(); - - foreach (object o in this) - { - //If C does not contain O, then we need to remove O from our - //set. We can't do this while iterating through our set, so - //we put it into RemoveSet for later. - if (!cSet.Contains(o)) - { - removeSet.Add(o); - } - } - return this.RemoveAll(removeSet); - } - - /// - /// Copies the elements in the to - /// an array. - /// - /// - ///

- /// The type of array needs to be compatible with the objects in the - /// , obviously. - ///

- ///
- /// - /// An array that will be the target of the copy operation. - /// - /// - /// The zero-based index where copying will start. - /// - public override void CopyTo(Array array, int index) - { - int i = index; - foreach (object o in this) - { - array.SetValue(UnmaskNull(o), i++); - } - } - - /// - /// The number of elements currently contained in this collection. - /// - public override int Count - { - get { return InternalDictionary.Count; } - } - - /// - /// Returns if the - /// is synchronized across - /// threads. - /// - /// - public override bool IsSynchronized - { - get { return false; } - } - - /// - /// An object that can be used to synchronize this collection to make - /// it thread-safe. - /// - /// - /// An object that can be used to synchronize this collection to make - /// it thread-safe. - /// - /// - public override object SyncRoot - { - get { return InternalDictionary.SyncRoot; } - } - - /// - /// Gets an enumerator for the elements in the - /// . - /// - /// - /// An over the elements - /// in the . - /// - public override IEnumerator GetEnumerator() - { - return new DictionarySetEnumerator(InternalDictionary.Keys.GetEnumerator()); - } - - private static object MaskNull(object key) - { - return key == null ? NullPlaceHolderKey : key; - } - - private static object UnmaskNull(object key) - { - return key == NullPlaceHolderKey ? null : key; - } - - #region Inner Class : DictionarySetEnumerator - - private sealed class DictionarySetEnumerator : IEnumerator - { - #region Constructor (s) / Destructor - - public DictionarySetEnumerator(IEnumerator enumerator) - { - _enumerator = enumerator; - } - - #endregion - - #region IEnumerator Members - - public void Reset() - { - _enumerator.Reset(); - } - - public object Current - { - get { return UnmaskNull(_enumerator.Current); } - } - - public bool MoveNext() - { - return _enumerator.MoveNext(); - } - - #endregion - - private IEnumerator _enumerator; - } - - #endregion - } +/* Copyright © 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */ + +#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; + +#endregion + +namespace Spring.Collections +{ + /// + /// is an + /// class that supports the creation of new + /// types where the underlying data + /// store is an instance. + /// + /// + ///

+ /// You can use any object that implements the + /// interface to hold set + /// data. You can define your own, or you can use one of the objects + /// provided in the framework. The type of + /// you + /// choose will affect both the performance and the behavior of the + /// using it. + ///

+ ///

+ /// This object overrides the method, + /// but not the method, because + /// the class is mutable. + /// Therefore, it is not safe to use as a key value in a dictionary. + ///

+ ///

+ /// To make a typed based on your + /// own , simply derive a new + /// class with a constructor that takes no parameters. Some + /// implmentations cannot be defined + /// with a default constructor. If this is the case for your class, you + /// will need to override clone as well. + ///

+ ///

+ /// It is also standard practice that at least one of your constructors + /// takes an or an + /// as an argument. + ///

+ ///
+ /// + [Serializable] + public abstract class DictionarySet : Set + { + private IDictionary _internalDictionary; + + private static readonly object PlaceholderObject = new object(); + private static readonly object NullPlaceHolderKey = new object(); + + /// + /// Provides the storage for elements in the + /// , stored as the key-set + /// of the object. + /// + /// + ///

+ /// Set this object in the constructor if you create your own + /// class. + ///

+ ///
+ protected IDictionary InternalDictionary + { + get { return _internalDictionary; } + set { _internalDictionary = value; } + } + + /// + /// The placeholder object used as the value for the + /// instance. + /// + /// + /// There is a single instance of this object globally, used for all + /// s. + /// + protected static object Placeholder + { + get { return PlaceholderObject; } + } + + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// + /// is the object was added, + /// if the object was already present. + /// + public override bool Add(object element) + { + element = MaskNull(element); + if (InternalDictionary[element] != null) + { + return false; + } + + //The object we are adding is just a placeholder. The thing we are + //really concerned with is 'o', the key. + InternalDictionary.Add(element, PlaceholderObject); + return true; + } + + /// + /// Adds all the elements in the specified collection to the set if + /// they are not already present. + /// + /// A collection of objects to add to the set. + /// + /// is the set changed as a result of this + /// operation. + /// + public override bool AddAll(ICollection collection) + { + bool changed = false; + foreach (object o in collection) + { + changed |= this.Add(o); + } + return changed; + } + + /// + /// Removes all objects from this set. + /// + public override void Clear() + { + InternalDictionary.Clear(); + } + + /// + /// Returns if this set contains the specified + /// element. + /// + /// The element to look for. + /// + /// if this set contains the specified element. + /// + public override bool Contains(object element) + { + element = MaskNull(element); + return InternalDictionary[element] != null; + } + + /// + /// Returns if the set contains all the + /// elements in the specified collection. + /// + /// A collection of objects. + /// + /// if the set contains all the elements in the + /// specified collection; also if the + /// supplied is . + /// + public override bool ContainsAll(ICollection collection) + { + if (collection == null) + { + return false; + } + foreach (object o in collection) + { + if (!this.Contains(MaskNull(o))) + { + return false; + } + } + return true; + } + + /// + /// Returns if this set contains no elements. + /// + public override bool IsEmpty + { + get { return InternalDictionary.Count == 0; } + } + + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// + /// if the set contained the specified element. + /// + public override bool Remove(object element) + { + element = MaskNull(element); + bool contained = this.Contains(element); + if (contained) + { + InternalDictionary.Remove(element); + } + return contained; + } + + /// + /// Remove all the specified elements from this set, if they exist in + /// this set. + /// + /// A collection of elements to remove. + /// + /// if the set was modified as a result of this + /// operation. + /// + public override bool RemoveAll(ICollection collection) + { + bool changed = false; + foreach (object o in collection) + { + changed |= this.Remove(o); + } + return changed; + } + + /// + /// Retains only the elements in this set that are contained in the + /// specified collection. + /// + /// + /// The collection that defines the set of elements to be retained. + /// + /// + /// if this set changed as a result of this + /// operation. + /// + public override bool RetainAll(ICollection collection) + { + //Put data from C into a set so we can use the Contains() method. + Set cSet = new HybridSet(collection); + + //We are going to build a set of elements to remove. + Set removeSet = new HybridSet(); + + foreach (object o in this) + { + //If C does not contain O, then we need to remove O from our + //set. We can't do this while iterating through our set, so + //we put it into RemoveSet for later. + if (!cSet.Contains(o)) + { + removeSet.Add(o); + } + } + return this.RemoveAll(removeSet); + } + + /// + /// Copies the elements in the to + /// an array. + /// + /// + ///

+ /// The type of array needs to be compatible with the objects in the + /// , obviously. + ///

+ ///
+ /// + /// An array that will be the target of the copy operation. + /// + /// + /// The zero-based index where copying will start. + /// + public override void CopyTo(Array array, int index) + { + int i = index; + foreach (object o in this) + { + array.SetValue(UnmaskNull(o), i++); + } + } + + /// + /// The number of elements currently contained in this collection. + /// + public override int Count + { + get { return InternalDictionary.Count; } + } + + /// + /// Returns if the + /// is synchronized across + /// threads. + /// + /// + public override bool IsSynchronized + { + get { return false; } + } + + /// + /// An object that can be used to synchronize this collection to make + /// it thread-safe. + /// + /// + /// An object that can be used to synchronize this collection to make + /// it thread-safe. + /// + /// + public override object SyncRoot + { + get { return InternalDictionary.SyncRoot; } + } + + /// + /// Gets an enumerator for the elements in the + /// . + /// + /// + /// An over the elements + /// in the . + /// + public override IEnumerator GetEnumerator() + { + return new DictionarySetEnumerator(InternalDictionary.Keys.GetEnumerator()); + } + + private static object MaskNull(object key) + { + return key == null ? NullPlaceHolderKey : key; + } + + private static object UnmaskNull(object key) + { + return key == NullPlaceHolderKey ? null : key; + } + + #region Inner Class : DictionarySetEnumerator + + private sealed class DictionarySetEnumerator : IEnumerator + { + #region Constructor (s) / Destructor + + public DictionarySetEnumerator(IEnumerator enumerator) + { + _enumerator = enumerator; + } + + #endregion + + #region IEnumerator Members + + public void Reset() + { + _enumerator.Reset(); + } + + public object Current + { + get { return UnmaskNull(_enumerator.Current); } + } + + public bool MoveNext() + { + return _enumerator.MoveNext(); + } + + #endregion + + private IEnumerator _enumerator; + } + + #endregion + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Collections/SortedSet.cs b/src/Spring/Spring.Core/Collections/SortedSet.cs index f2628fd7..3aed41b3 100644 --- a/src/Spring/Spring.Core/Collections/SortedSet.cs +++ b/src/Spring/Spring.Core/Collections/SortedSet.cs @@ -1,78 +1,88 @@ -/* Copyright © 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */ - -#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; - -#endregion - -namespace Spring.Collections -{ - /// - /// Implements an based on a sorted - /// tree. - /// - /// - ///

- /// This gives good performance for operations on very large data-sets, - /// though not as good - asymptotically - as a - /// . However, iteration occurs - /// in order. - ///

- ///

- /// Elements that you put into this type of collection must implement - /// , and they must actually be comparable. - /// You can't mix and - /// values, for example. - ///

- ///

- /// This implementation does - /// not support elements that are . - ///

- ///
- /// - [Serializable] - public class SortedSet : DictionarySet - { - /// - /// Creates a new set instance based on a sorted tree. - /// - public SortedSet() - { - InternalDictionary = new SortedList(); - } - - /// - /// Creates a new set instance based on a sorted tree and initializes - /// it based on a collection of elements. - /// - /// - /// A collection of elements that defines the initial set contents. - /// - public SortedSet(ICollection initialValues) : this() - { - this.AddAll(initialValues); - } - } +/* Copyright © 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */ + +#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 Spring.Util; + +#endregion + +namespace Spring.Collections +{ + /// + /// Implements an based on a sorted + /// tree. + /// + /// + ///

+ /// This gives good performance for operations on very large data-sets, + /// though not as good - asymptotically - as a + /// . However, iteration occurs + /// in order. + ///

+ ///

+ /// Elements that you put into this type of collection must implement + /// , and they must actually be comparable. + /// You can't mix and + /// values, for example. + ///

+ ///

+ /// This implementation does + /// not support elements that are . + ///

+ ///
+ /// + [Serializable] + public class SortedSet : DictionarySet + { + /// + /// Creates a new set instance based on a sorted tree. + /// + public SortedSet() + { + InternalDictionary = new SortedList(); + } + + /// + /// Creates a new set instance based on a sorted tree using for ordering. + /// + public SortedSet(IComparer comparer) + { + AssertUtils.ArgumentNotNull(comparer, "comparer"); + InternalDictionary = new SortedList(comparer); + } + + /// + /// Creates a new set instance based on a sorted tree and initializes + /// it based on a collection of elements. + /// + /// + /// A collection of elements that defines the initial set contents. + /// + public SortedSet(ICollection initialValues) : this() + { + this.AddAll(initialValues); + } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs index df5932a2..a9eba505 100644 --- a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs @@ -33,6 +33,7 @@ using Spring.Objects.Events; using Spring.Objects.Events.Support; using Spring.Objects.Factory; using Spring.Objects.Factory.Config; +using Spring.Objects.Support; using Spring.Util; #endregion @@ -158,7 +159,8 @@ namespace Spring.Context.Support /// no public constructors. ///

/// - protected AbstractApplicationContext() : this(null, true, null) + protected AbstractApplicationContext() + : this(null, true, null) { } @@ -173,7 +175,8 @@ namespace Spring.Context.Support ///

/// /// Flag specifying whether to make this context case sensitive or not. - protected AbstractApplicationContext(bool caseSensitive) : this(null, caseSensitive, null) + protected AbstractApplicationContext(bool caseSensitive) + : this(null, caseSensitive, null) { } @@ -200,6 +203,7 @@ namespace Spring.Context.Support _defaultObjectPostProcessors = new ArrayList(); AddDefaultObjectPostProcessor(new ObjectPostProcessorChecker()); AddDefaultObjectPostProcessor(new ApplicationContextAwareProcessor(this)); + AddDefaultObjectPostProcessor(new SharedStateAwareProcessor(new ISharedStateFactory[] { new ByTypeSharedStateFactory() }, Int32.MaxValue)); } /// @@ -279,7 +283,7 @@ namespace Spring.Context.Support /// public long StartupDateMilliseconds { - get { return (StartupDate.Ticks - TicksAtEpoch)/10000; } + get { return (StartupDate.Ticks - TicksAtEpoch) / 10000; } } @@ -482,10 +486,10 @@ namespace Spring.Context.Support private void RegisterObjectPostProcessors(IConfigurableListableObjectFactory objectFactory) { - RegisterObjectPostProcessorChecker(objectFactory); + RefreshObjectPostProcessorChecker(objectFactory); IDictionary dict = GetObjectsOfType(typeof(IObjectPostProcessor), true, false); ArrayList objectProcessors = new ArrayList(dict.Values); - objectProcessors.Sort(new OrderComparator()); + // objectProcessors.Sort(new OrderComparator()); foreach (IObjectPostProcessor objectPostProcessor in objectProcessors) { ObjectFactory.AddObjectPostProcessor(objectPostProcessor); @@ -502,19 +506,17 @@ namespace Spring.Context.Support } /// - /// Register an IObjectPostProcessorChecker that logs an info + /// Resets the well-known ObjectPostProcessorChecker that logs an info /// message when an object is created during IObjectPostProcessor /// instantiation, i.e. when an object is not eligible for being /// processed by all IObjectPostProcessors. /// - private void RegisterObjectPostProcessorChecker(IConfigurableListableObjectFactory objectFactory) + private void RefreshObjectPostProcessorChecker(IConfigurableListableObjectFactory objectFactory) { - int objectPostProcessorCount - = ObjectFactory.ObjectPostProcessorCount + 1 - + GetObjectNamesForType(typeof(IObjectPostProcessor), true, false).Length; -// ObjectFactory.AddObjectPostProcessor( -// new ObjectPostProcessorChecker(objectFactory, objectPostProcessorCount)); - ((ObjectPostProcessorChecker) _defaultObjectPostProcessors[0]).Reset(objectFactory, objectPostProcessorCount); + int registeredObjectPostProcessorCount = GetObjectNamesForType(typeof(IObjectPostProcessor), true, false).Length; + int objectPostProcessorCount = ObjectFactory.ObjectPostProcessorCount + 1 + + registeredObjectPostProcessorCount; + ((ObjectPostProcessorChecker)_defaultObjectPostProcessors[0]).Reset(objectFactory, objectPostProcessorCount); } /// @@ -527,7 +529,7 @@ namespace Spring.Context.Support object candidateRegistry = GetObject(EventRegistryObjectName); if (candidateRegistry is IEventRegistry) { - _eventRegistry = (IEventRegistry) candidateRegistry; + _eventRegistry = (IEventRegistry)candidateRegistry; #region Instrumentation @@ -612,7 +614,7 @@ namespace Spring.Context.Support if (candidateSource is IMessageSource) { _messageSource - = (IMessageSource) GetObject(MessageSourceObjectName); + = (IMessageSource)GetObject(MessageSourceObjectName); // make IMessageSource aware of any parent IMessageSource... if (ParentContext != null) @@ -758,7 +760,7 @@ namespace Spring.Context.Support lock (SyncRoot) { - + _startupDate = DateTime.Now; RefreshObjectFactory(); @@ -823,7 +825,7 @@ namespace Spring.Context.Support // index 0 contains the ObjectPostProcessorChecker that is handled separately! for (int i = 1; i < _defaultObjectPostProcessors.Count; i++) { - objectFactory.AddObjectPostProcessor((IObjectPostProcessor) this._defaultObjectPostProcessors[i]); + objectFactory.AddObjectPostProcessor((IObjectPostProcessor)this._defaultObjectPostProcessors[i]); } } @@ -1223,6 +1225,45 @@ namespace Spring.Context.Support return ObjectFactory.GetAliases(name); } + + /// + /// Return an unconfigured(!) 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 unconfigured(!) 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 . + /// + /// + /// + /// This method will only instantiate the requested object. It does NOT inject any dependencies! + /// + public object CreateObject(string name, Type requiredType, object[] arguments) + { + return ObjectFactory.CreateObject(name, requiredType, arguments); + } + /// /// Return an instance (possibly shared or independent) of the given object name. /// @@ -1335,7 +1376,7 @@ namespace Spring.Context.Support /// /// If the supplied is . /// - /// + /// public object GetObject(string name, Type requiredType, object[] arguments) { return ObjectFactory.GetObject(name, requiredType, arguments); @@ -1819,9 +1860,9 @@ namespace Spring.Context.Support } } - #region IPostProcessor implementation + #region IPostProcessor implementation - private sealed class ObjectPostProcessorChecker : IObjectPostProcessor + private sealed class ObjectPostProcessorChecker : IObjectPostProcessor, IOrdered { private int _objectPostProcessorTargetCount; private IConfigurableListableObjectFactory _objectFactory; @@ -1859,6 +1900,11 @@ namespace Spring.Context.Support } return obj; } + + public int Order + { + get { return Int32.MinValue; } + } } #endregion diff --git a/src/Spring/Spring.Core/Core/OrderComparator.cs b/src/Spring/Spring.Core/Core/OrderComparator.cs index 4e4d8c76..9408d77b 100644 --- a/src/Spring/Spring.Core/Core/OrderComparator.cs +++ b/src/Spring/Spring.Core/Core/OrderComparator.cs @@ -39,7 +39,8 @@ namespace Spring.Core ///

/// /// Juergen Hoeller - /// Aleksandar Seovic (.Net) + /// Aleksandar Seovic (.Net) + [Serializable] public class OrderComparator : IComparer { /// @@ -73,8 +74,22 @@ namespace Spring.Core } else { - return 0; + return CompareEqualOrder(o1, o2); } } + + /// + /// Handle the case when both objects have equal sort order priority. By default returns 0, + /// but may be overriden for handling special cases. + /// + /// The first object to compare. + /// The second object to compare. + /// + /// -1 if first object is less then second, 1 if it is greater, or 0 if they are equal. + /// + protected virtual int CompareEqualOrder(object o1, object o2) + { + return 0; + } } } diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableListableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableListableObjectFactory.cs index 67cad903..ac791ffc 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableListableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Config/IConfigurableListableObjectFactory.cs @@ -1,125 +1,125 @@ -#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 - - - -#endregion - +#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 + + + +#endregion + using System; using Spring.Objects.Factory; -namespace Spring.Objects.Factory.Config -{ - /// - /// SPI interface to be implemented by most if not all listable object factories. - /// - /// - ///

- /// Allows for framework-internal plug'n'play, e.g. in - /// . - ///

- ///
- /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IConfigurableListableObjectFactory - : IListableObjectFactory, - IConfigurableObjectFactory, - IAutowireCapableObjectFactory - { - /// - /// 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. - /// - 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. - /// - IObjectDefinition GetObjectDefinition(string name, bool includeAncestors); - - - /// - /// Injects dependencies into the supplied instance - /// using the supplied . - /// - /// - /// 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. - /// - /// - object ConfigureObject(object target, string name, IObjectDefinition definition); - - /// - /// Ensure that all non-lazy-init singletons are instantiated, also - /// considering s. - /// - /// - ///

- /// Typically invoked at the end of factory setup, if desired. - ///

- ///

- /// As this is a startup method, it should destroy already created singletons if - /// it fails, to avoid dangling resources. In other words, after invocation - /// of that method, either all or no singletons at all should be - /// instantiated. - ///

- ///
- /// - /// If one of the singleton objects could not be created. - /// +namespace Spring.Objects.Factory.Config +{ + /// + /// SPI interface to be implemented by most if not all listable object factories. + /// + /// + ///

+ /// Allows for framework-internal plug'n'play, e.g. in + /// . + ///

+ ///
+ /// Juergen Hoeller + /// Rick Evans (.NET) + public interface IConfigurableListableObjectFactory + : IListableObjectFactory, + IConfigurableObjectFactory, + IAutowireCapableObjectFactory + { + /// + /// 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. + /// + 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. + /// + IObjectDefinition GetObjectDefinition(string name, bool includeAncestors); + + + /// + /// Injects dependencies into the supplied instance + /// using the supplied . + /// + /// + /// 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. + /// + /// + object ConfigureObject(object target, string name, IObjectDefinition definition); + + /// + /// Ensure that all non-lazy-init singletons are instantiated, also + /// considering s. + /// + /// + ///

+ /// Typically invoked at the end of factory setup, if desired. + ///

+ ///

+ /// As this is a startup method, it should destroy already created singletons if + /// it fails, to avoid dangling resources. In other words, after invocation + /// of that method, either all or no singletons at all should be + /// instantiated. + ///

+ ///
+ /// + /// If one of the singleton objects could not be created. + /// void PreInstantiateSingletons (); /// @@ -157,5 +157,5 @@ namespace Spring.Objects.Factory.Config /// /// if there is no object with the given name. bool IsAutowireCandidate(string objectName, DependencyDescriptor descriptor); - } -} + } +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Config/SharedStateAwareProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Config/SharedStateAwareProcessor.cs new file mode 100644 index 00000000..75c13351 --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Factory/Config/SharedStateAwareProcessor.cs @@ -0,0 +1,153 @@ +#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.Configuration; +using System.Text; +using System.Threading; +using Common.Logging; +using Spring.Core; +using Spring.Util; + +#endregion + +namespace Spring.Objects.Factory.Config +{ + /// + /// Configure all ISharedStateAware objects, delegating concrete handling to the list of . + /// + public class SharedStateAwareProcessor : IObjectPostProcessor, IOrdered + { + // holds the logger for this processor instance + private readonly ILog Log = LogManager.GetLogger( typeof( SharedStateAwareProcessor ) ); + // holds a list of ISharedStateProvider instances (if any) + private ISharedStateFactory[] _sharedStateFactories = new ISharedStateFactory[0]; + // holds prio + private int _order = Int32.MaxValue; + + /// + /// Return the order value of this object, where a higher value means greater in + /// terms of sorting. + /// + /// + ///

+ /// Normally starting with 0 or 1, with indicating + /// greatest. Same order values will result in arbitrary positions for the affected + /// objects. + ///

+ ///

+ /// Higher value can be interpreted as lower priority, consequently the first object + /// has highest priority. + ///

+ ///
+ /// The order value. + public int Order + { + get { return _order; } + set { _order = value; } + } + + /// + /// Get/Set the (already ordererd!) list of instances. + /// + /// + /// If this list is not set, the containing object factory will automatically + /// be scanned for instances. + /// + public ISharedStateFactory[] SharedStateFactories + { + get { return _sharedStateFactories; } + set + { + AssertUtils.ArgumentHasElements( value, "SharedStateFactories" ); + _sharedStateFactories = value; + } + } + + /// + /// Creates a new empty instance. + /// + public SharedStateAwareProcessor() + { } + + /// + /// Creates a new preconfigured instance. + /// + /// + /// priority value affecting order of invocation of this processor. See interface. + public SharedStateAwareProcessor( ISharedStateFactory[] sharedStateFactories, int order ) + { + SharedStateFactories = sharedStateFactories; + } + + /// + /// Iterates over configured list of s until + /// the first provider is found that
+ /// a) true == provider.CanProvideState( instance, name )
+ /// b) null != provider.GetSharedState( instance, name )
+ ///
+ public object PostProcessBeforeInitialization( object instance, string name ) + { + if (SharedStateFactories.Length == 0) + { + return instance; + } + + ISharedStateAware ssa = instance as ISharedStateAware; + if (ssa != null && ssa.SharedState == null) + { + // probe for first factory willing to serve shared state + foreach (ISharedStateFactory ssf in _sharedStateFactories) + { + if (ssf.CanProvideState( ssa, name )) + { + IDictionary sharedState = ssf.GetSharedStateFor( ssa, name ); + if (sharedState != null) + { + ssa.SharedState = sharedState; + break; + } + } + } + } + return instance; + } + + /// + /// A NoOp for this processor + /// + /// + /// The new object instance. + /// + /// + /// The name of the object. + /// + /// + /// the original . + /// + public object PostProcessAfterInitialization( object instance, string name ) + { + return instance; + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs index 295a8cf9..41ccd8bb 100644 --- a/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/IObjectFactory.cs @@ -1,492 +1,527 @@ -#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; - -#endregion - -namespace Spring.Objects.Factory -{ - /// - /// The root interface for accessing a Spring.NET IoC container. - /// - /// - /// - /// This is the basic client view of a Spring.NET IoC container; further interfaces - /// such as and - /// - /// are available for specific purposes such as enumeration and configuration. - /// - /// - /// This is the root interface to be implemented by objects that can hold a number - /// of object definitions, each uniquely identified by a - /// name. An independent instance of any of these objects can be obtained - /// (the Prototype design pattern), or a single shared instance can be obtained - /// (a superior alternative to the Singleton design pattern, in which the instance is a - /// singleton in the scope of the factory). Which type of instance - /// will be returned depends on the object factory configuration - the API is the same. - /// The Singleton approach is more useful and hence more common in practice. - /// - /// - /// The point of this approach is that the IObjectFactory is a central registry of - /// application components, and centralizes the configuring of application components - /// (no more do individual objects need to read properties files, for example). - /// See chapters 4 and 11 of "Expert One-on-One J2EE Design and Development" for a - /// discussion of the benefits of this approach. - /// - /// - /// Normally an IObjectFactory will load object definitions stored in a configuration - /// source (such as an XML document), and use the - /// namespace to configure the objects. However, an implementation could simply return - /// .NET objects it creates as necessary directly in .NET code. There are no - /// constraints on how the definitions could be stored: LDAP, RDBMS, XML, properties - /// file etc. Implementations are encouraged to support references amongst objects, - /// to either Singletons or Prototypes. - /// - /// - /// In contrast to the methods in - /// , all of the methods - /// in this interface will also check parent factories if this is an - /// . If an object is - /// not found in this factory instance, the immediate parent is asked. Objects in - /// this factory instance are supposed to override objects of the same name in any - /// parent factory. - /// - /// - /// Object factories are supposed to support the standard object lifecycle interfaces - /// as far as possible. The maximum set of initialization methods and their standard - /// order is: - /// - /// - /// - /// - /// - /// 's - /// property. - /// - /// - /// - /// - /// 's - /// property. - /// - /// - /// - /// - /// - /// (only applicable if running within an ). - /// - /// - /// - /// - /// The - /// - /// method of - /// s. - /// - /// - /// - /// - /// 's - /// method. - /// - /// - /// - /// - /// A custom init-method definition. - /// - /// - /// - /// - /// The - /// - /// method of - /// s. - /// - /// - /// - /// - ///

- /// - /// On shutdown of an object factory, the following lifecycle methods apply: - /// - /// - /// - /// - /// - /// 's - /// method. - /// - /// - /// - /// - /// A custom destroy-method definition. - /// - /// - /// - /// - /// - /// Rod Johnson - /// Juergen Hoeller - /// Rick Evans (.NET) - public interface IObjectFactory : IDisposable - { - ///

- /// Is this object a singleton? - /// - /// - /// - /// That is, will - /// always return the same object? - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The name of the object to query. - /// True if the named object is a singleton. - /// - /// If there's no such object definition. - /// - bool IsSingleton(string name); - - - /// - /// Determines whether the specified object name is prototype. That is, will GetObject - /// always return independent instances? - /// - /// 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. - /// - /// - /// - /// The name of the object to query - /// - /// true if the specified object name will always deliver independent instances; otherwise, false. - /// - /// if there is no object with the given name. - bool IsPrototype(string name); - - /// - /// Does this object factory contain an object with the given name? - /// - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The name of the object to query. - /// True if an object with the given name is defined. - bool ContainsObject(string name); - - /// - /// Return the aliases for the given object name, if defined. - /// - /// - /// - /// Will ask the parent factory if the object cannot be found in this factory - /// instance. - /// - /// - /// The object name to check for aliases. - /// The aliases, or an empty array if none. - /// - /// If there's no such object definition. - /// - string[] GetAliases(string name); - -#if !MONO - /// - /// 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. - /// - /// - /// This is the indexer for the - /// interface. - /// - /// - /// The name of the object to return. - /// The instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// -#endif - object this[string name] { get; } - - /// - /// 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 instance of the object. - /// - /// If there's no such object definition. - /// - /// - /// If the object could not be created. - /// - object GetObject(string name); - - /// - /// 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 . - /// - object GetObject(string name, object[] arguments); - - /// - /// 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 . - /// - /// - object GetObject(string name, Type requiredType, object[] arguments); - - /// - /// Return an instance (possibly shared or independent) of the given object name. - /// - /// - /// - /// Provides a measure of type safety by throwing an exception if the object is - /// not of the required . - /// - /// - /// 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 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 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. - /// - object GetObject(string name, Type requiredType); - - /// - /// Determine the type of the object with the given name. - /// - /// - /// - /// More specifically, checks the type of object that - /// would return. - /// For an , returns the type - /// of object that the creates. - /// - /// - /// The name of the object to query. - /// - /// The type of the object or if not determinable. - /// - Type GetType(string name); - - - - /// - /// 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 - /// - bool IsTypeMatch(string name, Type targetType); - - /// - /// Injects dependencies into the supplied instance - /// using the named object definition. - /// - /// - /// - /// In addition to being generally useful, typically this method is used to provide - /// dependency injection functionality for objects that are instantiated outwith the - /// control of a developer. A case in point is the way that the current (1.1) - /// ASP.NET classes instantiate web controls... the instantiation takes place within - /// a private method of a compiled page, and thus cannot be hooked into the - /// typical Spring.NET IOC container lifecycle for dependency injection. - /// - /// - /// - /// The following code snippet assumes that the instantiated factory instance - /// has been configured with an object definition named - /// 'ExampleNamespace.BusinessObject' that has been configured to set the - /// Dao property of any ExampleNamespace.BusinessObject instance - /// to an instance of an appropriate implementation... - /// - /// namespace ExampleNamespace - /// { - /// public class BusinessObject - /// { - /// private IDao _dao; - /// - /// public BusinessObject() {} - /// - /// public IDao Dao - /// { - /// get { return _dao; } - /// set { _dao = value; } - /// } - /// } - /// } - /// - /// with the corresponding driver code looking like so... - /// - /// IObjectFactory factory = GetAnIObjectFactoryImplementation(); - /// BusinessObject instance = new BusinessObject(); - /// factory.ConfigureObject(instance, "object_definition_name"); - /// // at this point the dependencies for the 'instance' object will have been resolved... - /// - /// - /// - /// 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. - /// - /// - /// If there is no object definition for the supplied . - /// - /// - /// If any of the target object's dependencies could not be created. - /// - object ConfigureObject(object target, string name); - } +#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; + +#endregion + +namespace Spring.Objects.Factory +{ + /// + /// The root interface for accessing a Spring.NET IoC container. + /// + /// + /// + /// This is the basic client view of a Spring.NET IoC container; further interfaces + /// such as and + /// + /// are available for specific purposes such as enumeration and configuration. + /// + /// + /// This is the root interface to be implemented by objects that can hold a number + /// of object definitions, each uniquely identified by a + /// name. An independent instance of any of these objects can be obtained + /// (the Prototype design pattern), or a single shared instance can be obtained + /// (a superior alternative to the Singleton design pattern, in which the instance is a + /// singleton in the scope of the factory). Which type of instance + /// will be returned depends on the object factory configuration - the API is the same. + /// The Singleton approach is more useful and hence more common in practice. + /// + /// + /// The point of this approach is that the IObjectFactory is a central registry of + /// application components, and centralizes the configuring of application components + /// (no more do individual objects need to read properties files, for example). + /// See chapters 4 and 11 of "Expert One-on-One J2EE Design and Development" for a + /// discussion of the benefits of this approach. + /// + /// + /// Normally an IObjectFactory will load object definitions stored in a configuration + /// source (such as an XML document), and use the + /// namespace to configure the objects. However, an implementation could simply return + /// .NET objects it creates as necessary directly in .NET code. There are no + /// constraints on how the definitions could be stored: LDAP, RDBMS, XML, properties + /// file etc. Implementations are encouraged to support references amongst objects, + /// to either Singletons or Prototypes. + /// + /// + /// In contrast to the methods in + /// , all of the methods + /// in this interface will also check parent factories if this is an + /// . If an object is + /// not found in this factory instance, the immediate parent is asked. Objects in + /// this factory instance are supposed to override objects of the same name in any + /// parent factory. + /// + /// + /// Object factories are supposed to support the standard object lifecycle interfaces + /// as far as possible. The maximum set of initialization methods and their standard + /// order is: + /// + /// + /// + /// + /// + /// 's + /// property. + /// + /// + /// + /// + /// 's + /// property. + /// + /// + /// + /// + /// + /// (only applicable if running within an ). + /// + /// + /// + /// + /// The + /// + /// method of + /// s. + /// + /// + /// + /// + /// 's + /// method. + /// + /// + /// + /// + /// A custom init-method definition. + /// + /// + /// + /// + /// The + /// + /// method of + /// s. + /// + /// + /// + /// + ///

+ /// + /// On shutdown of an object factory, the following lifecycle methods apply: + /// + /// + /// + /// + /// + /// 's + /// method. + /// + /// + /// + /// + /// A custom destroy-method definition. + /// + /// + /// + /// + /// + /// Rod Johnson + /// Juergen Hoeller + /// Rick Evans (.NET) + public interface IObjectFactory : IDisposable + { + ///

+ /// Is this object a singleton? + /// + /// + /// + /// That is, will + /// always return the same object? + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The name of the object to query. + /// True if the named object is a singleton. + /// + /// If there's no such object definition. + /// + bool IsSingleton(string name); + + + /// + /// Determines whether the specified object name is prototype. That is, will GetObject + /// always return independent instances? + /// + /// 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. + /// + /// + /// + /// The name of the object to query + /// + /// true if the specified object name will always deliver independent instances; otherwise, false. + /// + /// if there is no object with the given name. + bool IsPrototype(string name); + + /// + /// Does this object factory contain an object with the given name? + /// + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The name of the object to query. + /// True if an object with the given name is defined. + bool ContainsObject(string name); + + /// + /// Return the aliases for the given object name, if defined. + /// + /// + /// + /// Will ask the parent factory if the object cannot be found in this factory + /// instance. + /// + /// + /// The object name to check for aliases. + /// The aliases, or an empty array if none. + /// + /// If there's no such object definition. + /// + string[] GetAliases(string name); + +#if !MONO + /// + /// 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. + /// + /// + /// This is the indexer for the + /// interface. + /// + /// + /// The name of the object to return. + /// The instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// +#endif + object this[string name] { get; } + + /// + /// 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 instance of the object. + /// + /// If there's no such object definition. + /// + /// + /// If the object could not be created. + /// + object GetObject(string name); + + /// + /// 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 . + /// + object GetObject(string name, object[] arguments); + + /// + /// 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 . + /// + /// + object GetObject(string name, Type requiredType, object[] arguments); + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// Provides a measure of type safety by throwing an exception if the object is + /// not of the required . + /// + /// + /// 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 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 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. + /// + object GetObject(string name, Type requiredType); + + /// + /// Determine the type of the object with the given name. + /// + /// + /// + /// More specifically, checks the type of object that + /// would return. + /// For an , returns the type + /// of object that the creates. + /// + /// + /// The name of the object to query. + /// + /// The type of the object or if not determinable. + /// + Type GetType(string name); + + + + /// + /// 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 + /// + bool IsTypeMatch(string name, Type targetType); + + /// + /// Return an unconfigured(!) 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 unconfigured(!) 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 . + /// + /// + /// + /// This method will only instantiate the requested object. It does NOT inject any dependencies! + /// + object CreateObject(string name, Type requiredType, object[] arguments); + + /// + /// Injects dependencies into the supplied instance + /// using the named object definition. + /// + /// + /// + /// In addition to being generally useful, typically this method is used to provide + /// dependency injection functionality for objects that are instantiated outwith the + /// control of a developer. A case in point is the way that the current (1.1) + /// ASP.NET classes instantiate web controls... the instantiation takes place within + /// a private method of a compiled page, and thus cannot be hooked into the + /// typical Spring.NET IOC container lifecycle for dependency injection. + /// + /// + /// + /// The following code snippet assumes that the instantiated factory instance + /// has been configured with an object definition named + /// 'ExampleNamespace.BusinessObject' that has been configured to set the + /// Dao property of any ExampleNamespace.BusinessObject instance + /// to an instance of an appropriate implementation... + /// + /// namespace ExampleNamespace + /// { + /// public class BusinessObject + /// { + /// private IDao _dao; + /// + /// public BusinessObject() {} + /// + /// public IDao Dao + /// { + /// get { return _dao; } + /// set { _dao = value; } + /// } + /// } + /// } + /// + /// with the corresponding driver code looking like so... + /// + /// IObjectFactory factory = GetAnIObjectFactoryImplementation(); + /// BusinessObject instance = new BusinessObject(); + /// factory.ConfigureObject(instance, "object_definition_name"); + /// // at this point the dependencies for the 'instance' object will have been resolved... + /// + /// + /// + /// 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. + /// + /// + /// If there is no object definition for the supplied . + /// + /// + /// If any of the target object's dependencies could not be created. + /// + object ConfigureObject(object target, string name); + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs index 3f704708..c45e1773 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractAutowireCapableObjectFactory.cs @@ -729,44 +729,44 @@ namespace Spring.Objects.Factory.Support ignoredDependencyInterfaces.Add(type); } - /// - /// Create an object instance for the given object definition. - /// - /// 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 static factory method. It is invalid to use a non- arguments value - /// in any other case. - /// - /// - /// A new instance of the object. - /// - /// - /// In case of errors. - /// - /// - ///

- /// Delegates to the - /// - /// method version with the allowEagerCaching parameter set to true. - ///

- ///

- /// 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. - ///

- ///
- protected internal override object CreateObject(string name, RootObjectDefinition definition, object[] arguments) - { - return CreateObject(name, definition, arguments, true); - } +// /// +// /// Create an object instance for the given object definition. +// /// +// /// 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 static factory method. It is invalid to use a non- arguments value +// /// in any other case. +// /// +// /// +// /// A new instance of the object. +// /// +// /// +// /// In case of errors. +// /// +// /// +// ///

+// /// Delegates to the +// /// +// /// method version with the allowEagerCaching parameter set to true. +// ///

+// ///

+// /// 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. +// ///

+// ///
+// protected internal override object CreateObject(string name, RootObjectDefinition definition, object[] arguments) +// { +// return CreateObject(name, definition, arguments, true, false); +// } /// /// Create an object instance for the given object definition. @@ -784,6 +784,9 @@ namespace Spring.Objects.Factory.Support /// Whether eager caching of singletons is allowed... typically true for /// singlton objects, but never true for inner object definitions. /// + /// + /// Suppress injecting dependencies yet. + /// /// /// A new instance of the object. /// @@ -801,7 +804,7 @@ namespace Spring.Objects.Factory.Support /// instantiation within this class is performed by this method. ///

/// - protected internal override object CreateObject(string name, RootObjectDefinition definition, object[] arguments, bool allowEagerCaching) + protected internal override object InstantiateObject(string name, RootObjectDefinition definition, object[] arguments, bool allowEagerCaching, bool suppressConfigure) { // guarantee the initialization of objects that the current one depends on.. if (definition.DependsOn != null && definition.DependsOn.Length > 0) @@ -875,7 +878,10 @@ namespace Spring.Objects.Factory.Support eagerlyCached = true; } - instance = ConfigureObject(name, definition, instanceWrapper); + if (!suppressConfigure) + { + instance = ConfigureObject(name, definition, instanceWrapper); + } } catch (ObjectCreationException) { @@ -1634,7 +1640,7 @@ namespace Spring.Objects.Factory.Support object result; try { - instance = CreateObject(innerObjectName, mod, ObjectUtils.EmptyObjects, false); + instance = InstantiateObject(innerObjectName, mod, ObjectUtils.EmptyObjects, false, false); result = GetObjectForInstance(innerObjectName, instance); } catch (ObjectsException ex) diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs index 20b526d0..bb32dc42 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs @@ -54,6 +54,32 @@ namespace Spring.Objects.Factory.Support [Serializable] public abstract class AbstractObjectFactory : IConfigurableObjectFactory { + /// + /// Makes a distinction between sort order and object identity. + /// This is important when used with , since most + /// implementations assume Order == Identity + /// + [Serializable] + private class ObjectOrderComparator : OrderComparator + { + /// + /// Handle the case when both objects have equal sort order priority. By default returns 0, + /// but may be overriden for handling special cases. + /// + /// The first object to compare. + /// The second object to compare. + /// + /// -1 if first object is less then second, 1 if it is greater, or 0 if they are equal. + /// + protected override int CompareEqualOrder(object o1, object o2) + { + if (ReferenceEquals(o1,o2)) return 0; + if (o1 == null) return 1; + if (o2 == null) return -1; + return o1.GetHashCode().CompareTo(o2.GetHashCode()); + } + } + /// /// Marker object to be temporarily registered in the singleton cache, /// while instantiating an object (in order to be able to detect circular references). @@ -160,11 +186,11 @@ namespace Spring.Objects.Factory.Support } /// - /// Gets the of + /// Gets the of /// s /// that will be applied to objects created by this factory. /// - public IList ObjectPostProcessors + public ISet ObjectPostProcessors { get { return objectPostProcessors; } } @@ -203,6 +229,7 @@ namespace Spring.Objects.Factory.Support #region Methods + /// /// Return an instance (possibly shared or independent) of the given object name. /// @@ -235,78 +262,9 @@ namespace Spring.Objects.Factory.Support /// 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; + return GetObjectInternal(name, requiredType, arguments, false); } - - /// /// Apply the property values of the object definition with the supplied /// to the supplied . @@ -334,37 +292,37 @@ namespace Spring.Objects.Factory.Support // explicit no-op... } - /// - /// 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 internal abstract object CreateObject(string name, RootObjectDefinition definition, object[] arguments); +// /// +// /// 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 internal abstract object CreateObject(string name, RootObjectDefinition definition, object[] arguments); /// @@ -383,6 +341,9 @@ namespace Spring.Objects.Factory.Support /// Whether eager caching of singletons is allowed... typically true for /// singlton objects, but never true for inner object definitions. /// + /// + /// Create instance only - suppress injecting dependencies yet. + /// /// /// A new instance of the object. /// @@ -400,8 +361,8 @@ namespace Spring.Objects.Factory.Support /// instantiation within this class is performed by this method. ///

/// - protected internal abstract object CreateObject(string name, RootObjectDefinition definition, object[] arguments, - bool allowEagerCaching); + protected internal abstract object InstantiateObject(string name, RootObjectDefinition definition, object[] arguments, + bool allowEagerCaching, bool suppressConfigure); /// /// Destroy the target object. @@ -1380,6 +1341,7 @@ namespace Spring.Objects.Factory.Support 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) @@ -1429,7 +1391,7 @@ namespace Spring.Objects.Factory.Support /// /// ObjectPostProcessors to apply in CreateObject /// - private IList objectPostProcessors = new ArrayList(); + private ISet objectPostProcessors = new SortedSet(new ObjectOrderComparator()); /// /// Indicates whether any IInstantiationAwareBeanPostProcessors have been registered @@ -1688,13 +1650,34 @@ namespace Spring.Objects.Factory.Support get { return GetObject(name); } } + /// + /// Return an unconfigured(!) instance (possibly shared or independent) of the given object name. + /// + /// + /// + /// This method will only instantiate the requested object. It does NOT inject any dependencies! + /// + public object CreateObject(string name, Type requiredType, object[] arguments) + { + return GetObjectInternal(name, requiredType, arguments, true); + } + /// /// Return an instance (possibly shared or independent) of the given object name. /// /// . public object GetObject(string name) { - return GetObject(name, typeof(object), null); + return GetObjectInternal(name, typeof(object), null, false); + } + + /// + /// Return an instance (possibly shared or independent) of the given object name. + /// + /// + public object GetObject(string name, Type requiredType) + { + return GetObjectInternal(name, requiredType, null, false); } /// @@ -1734,33 +1717,147 @@ namespace Spring.Objects.Factory.Support /// public object GetObject(string name, object[] arguments) { - object instance = null; - string objectName = TransformedObjectName(name); + return GetObjectInternal(name, typeof(object), arguments, false); - // 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); +// string objectName = TransformedObjectName(name); +// object instance = null; +// +// // 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); } + /// + /// Return an instance (possibly shared or independent) of the given object name, + /// optionally injecting dependencies. + /// + /// 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. + /// + /// whether to inject dependencies or not. + /// 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 . + /// + /// + /// + protected object GetObjectInternal(string name, Type requiredType, object[] arguments, bool suppressConfigure) + { + 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 + "]"); + } + + if (arguments != null) + { + // Override constructor values and configure as a prototype if arguments are specified + mergedObjectDefinition = new RootObjectDefinition(mergedObjectDefinition); + mergedObjectDefinition.ConstructorArgumentValues = null; + mergedObjectDefinition.IsSingleton = false; + mergedObjectDefinition.ConstructorArgumentValues = null; + } + + 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 = InstantiateObject(name, mergedObjectDefinition, arguments, true, suppressConfigure); + } + } + // 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; + } /// /// Creates a singleton instance for the specified object name and definition. @@ -1797,7 +1894,7 @@ namespace Spring.Objects.Factory.Support BeforeSingletonCreation(objectName); try { - sharedInstance = CreateObject(objectName, objectDefinition, arguments); + sharedInstance = InstantiateObject(objectName, objectDefinition, arguments, true, false); } finally { @@ -1827,15 +1924,6 @@ namespace Spring.Objects.Factory.Support 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, null); - } - /// /// Injects dependencies into the supplied instance /// using the named object definition. diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs index e8ab0622..98ad0da4 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionValueResolver.cs @@ -263,7 +263,7 @@ namespace Spring.Objects.Factory.Support try { //SPRNET-986 ObjectUtils.EmptyObjects -> null - instance = objectFactory.CreateObject(actualInnerObjectName, mod, null, false); + instance = objectFactory.InstantiateObject(actualInnerObjectName, mod, null, false, false); result = objectFactory.GetObjectForInstance(actualInnerObjectName, instance); } catch (ObjectsException ex) diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs index fcf79d3e..dad16c3a 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/StaticListableObjectFactory.cs @@ -80,6 +80,15 @@ namespace Spring.Objects.Factory.Support get { return GetObject(name); } } + /// + /// This method is not supported by . + /// + /// + public object CreateObject(string name, Type requiredType, object[] arguments) + { + throw new NotSupportedException("StaticListableObjectFactory does not support this method."); + } + /// /// Return an instance of the given object name. /// diff --git a/src/Spring/Spring.Web/Web/Support/ISharedStateAware.cs b/src/Spring/Spring.Core/Objects/ISharedStateAware.cs similarity index 68% rename from src/Spring/Spring.Web/Web/Support/ISharedStateAware.cs rename to src/Spring/Spring.Core/Objects/ISharedStateAware.cs index adf0c638..1cc1e548 100644 --- a/src/Spring/Spring.Web/Web/Support/ISharedStateAware.cs +++ b/src/Spring/Spring.Core/Objects/ISharedStateAware.cs @@ -25,19 +25,19 @@ using System.Web; #endregion -namespace Spring.Web.Support +namespace Spring.Objects { /// - /// This interface should be implemented by s that want to - /// have access to the shared state for the handler. + /// This interface should be implemented by classes that want to + /// have access to the shared state. /// /// ///

/// Shared state is very useful if you have data that needs to be shared by all instances - /// of the same page (or other ). + /// of e.g. the same webform (or other IHttpHandlers). ///

///

- /// For example, class implements this interface, which allows + /// For example, Spring.Web.UI.Page class implements this interface, which allows /// each page derived from it to cache localizalization resources and parsed data binding /// expressions only once and then reuse the cached values, regardless of how many instances /// of the page are created. @@ -47,12 +47,8 @@ namespace Spring.Web.Support { ///

/// Gets or sets the that should be used - /// to store shared state for the . + /// to store shared state for this instance. /// - /// - /// The that should be used - /// to store shared state for the . - /// IDictionary SharedState { get; set; } } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/ISharedStateFactory.cs b/src/Spring/Spring.Core/Objects/ISharedStateFactory.cs new file mode 100644 index 00000000..23a5921d --- /dev/null +++ b/src/Spring/Spring.Core/Objects/ISharedStateFactory.cs @@ -0,0 +1,55 @@ +#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.Collections; + +#endregion + +namespace Spring.Objects +{ + /// + /// Abstracts the state sharing strategy used + /// by + /// + /// Erich Eichinger + public interface ISharedStateFactory + { + /// + /// Indicate, whether the given instance can be served by this factory + /// + /// the instance to serve state + /// the name of the instance + /// + /// a boolean value indicating, whether state can + /// be served for the given instance or not. + /// + bool CanProvideState(object instance, string name); + + /// + /// Returns the shared state for the given instance. + /// + /// the instance to obtain shared state for. + /// the name of this instance + /// a dictionary containing shared state for or null. + IDictionary GetSharedStateFor( object instance, string name ); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Support/AbstractSharedStateFactory.cs b/src/Spring/Spring.Core/Objects/Support/AbstractSharedStateFactory.cs new file mode 100644 index 00000000..41e5d684 --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Support/AbstractSharedStateFactory.cs @@ -0,0 +1,145 @@ +#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 Spring.Collections; +using Spring.Core; +using Spring.Util; + +#endregion + +namespace Spring.Objects.Support +{ + /// + /// Convenience base class for implementations. + /// + public abstract class AbstractSharedStateFactory : ISharedStateFactory, IOrdered + { + private bool _caseSensitiveState; + private int _order = Int32.MaxValue; + private readonly IDictionary _sharedStateCache = new Hashtable(); + + /// + /// Create shared state dictionaries case-sensitive or case-insensitive? + /// + public bool CaseSensitiveState + { + get { return _caseSensitiveState; } + set { _caseSensitiveState = value; } + } + + /// + /// Gets a dictionary acc. to the type of . + /// If no dictionary is found, create it according to + /// + /// the instance to obtain shared state for + /// the name of the instance. + /// + /// A dictionary containing the 's state, + /// or null if no state can be served by this provider. + /// + public IDictionary GetSharedStateFor( object instance, string name ) + { + AssertUtils.ArgumentNotNull(instance, "instance"); + + if (!CanProvideState(instance, name)) + { + return null; + } + + object key = GetKey(instance, name); + if (key == null) + { + return null; + } + + IDictionary sharedState = (IDictionary) _sharedStateCache[key]; + if (sharedState == null) + { + lock(_sharedStateCache) + { + sharedState = (IDictionary) _sharedStateCache[key]; + if (sharedState == null) + { + sharedState = CreateSharedStateDictionary(key); + _sharedStateCache[key] = sharedState; + } + } + } + return sharedState; + } + + /// + /// A number indicating the priority of this ( for more). + /// + public virtual int Order + { + get { return _order; } + set { _order = value; } + } + + /// + /// Creates a dictionary to hold the shared state identified by . + /// + /// a key to create the dictionary for. + /// a dictionary according to and . + protected virtual IDictionary CreateSharedStateDictionary(object key) + { + return _caseSensitiveState ? new Hashtable() : new CaseInsensitiveHashtable(); + } + + /// + /// Indicate, whether the given instance will be served by this provider + /// + /// the instance to serve state + /// the name of the instance + /// + /// a boolean value indicating, whether state shall + /// be resolved for the given instance or not. + /// + public virtual bool CanProvideState(object instance, string name) + { + return true; + } + + /// + /// Create the key used for obtaining the state dictionary for . + /// + /// the instance to create the key for + /// the name of the instance. + /// + /// the key identifying the state dictionary to be used for + /// or null, if this state manager doesn't serve the given instance. + /// + /// + /// + /// Implementations may choose to return null from this method to indicate, + /// that they won't serve state for the given instance. + /// + /// + /// Note:Keys returned by this method are always treated case-sensitive! + /// + /// + protected abstract object GetKey(object instance, string name); + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Support/ByTypeSharedStateFactory.cs b/src/Spring/Spring.Core/Objects/Support/ByTypeSharedStateFactory.cs new file mode 100644 index 00000000..7199fd3e --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Support/ByTypeSharedStateFactory.cs @@ -0,0 +1,104 @@ +#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; + +#endregion + +namespace Spring.Objects.Support +{ + /// + /// Serves shared state on a by-type basis. + /// + public class ByTypeSharedStateFactory : AbstractSharedStateFactory + { + private Type[] typeFilter; + + /// + /// Limit object types to be served by this state manager. + /// + /// + /// Only objects assignable to one of the types in this list + /// will be served state by this manager. + /// + public Type[] TypeFilter + { + set { typeFilter = value; } + } + + /// + /// Creates a new instance matching all types by default. + /// + public ByTypeSharedStateFactory() + {} + + /// + /// Creates a new instance matching only specified list of types. + /// + /// the list of types to serve. + public ByTypeSharedStateFactory(Type[] typeFilter) + { + this.typeFilter = typeFilter; + } + + /// + /// Indicate, whether the given instance will be served by this provider + /// + /// the instance to serve state + /// the name of the instance + /// + /// a boolean value indicating, whether state shall + /// be resolved for the given instance or not. + /// + public override bool CanProvideState( object instance, string name ) + { + if (instance == null) + return false; + + if (typeFilter == null) + return true; + + Type instanceType = instance.GetType(); + foreach (Type type in typeFilter) + { + if (type.IsAssignableFrom( instanceType )) + return true; + } + return false; + } + + /// + /// Returns the for the given . + /// + /// the instance to obtain the key for. + /// the name of the instance (ignored by this provider) + /// instance.GetType() if it matches the list. Null otherwise. + /// + /// This method will only be called if returned true previously. + /// + protected override object GetKey( object instance, string name ) + { + Type key = instance.GetType(); + return key; + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Spring.Core.2005.csproj b/src/Spring/Spring.Core/Spring.Core.2005.csproj index 892dbde2..ea4ae66b 100644 --- a/src/Spring/Spring.Core/Spring.Core.2005.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2005.csproj @@ -554,6 +554,7 @@ + @@ -587,6 +588,8 @@ + + @@ -888,6 +891,7 @@ Code + Code @@ -897,6 +901,7 @@ Code + Code diff --git a/src/Spring/Spring.Core/Spring.Core.2008.csproj b/src/Spring/Spring.Core/Spring.Core.2008.csproj index 605983ae..28d30ee9 100644 --- a/src/Spring/Spring.Core/Spring.Core.2008.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2008.csproj @@ -570,6 +570,7 @@ + @@ -603,6 +604,8 @@ + + @@ -904,6 +907,7 @@ Code + Code @@ -913,6 +917,7 @@ Code + Code diff --git a/src/Spring/Spring.Core/Util/ArrayUtils.cs b/src/Spring/Spring.Core/Util/ArrayUtils.cs index b5c2291e..52dbaae6 100644 --- a/src/Spring/Spring.Core/Util/ArrayUtils.cs +++ b/src/Spring/Spring.Core/Util/ArrayUtils.cs @@ -34,6 +34,22 @@ namespace Spring.Util /// Aleksandar Seovic public sealed class ArrayUtils { + /// + /// Checks if the given array or collection has elements and none of the elements is null. + /// + /// the collection to be checked. + /// true if the collection has a length and contains only non-null elements. + public static bool HasElements(ICollection collection) + { + if (!HasLength(collection)) return false; + IEnumerator it = collection.GetEnumerator(); + while(it.MoveNext()) + { + if (it.Current == null ) return false; + } + return true; + } + /// /// Checks if the given array or collection is null or has no elements. /// diff --git a/src/Spring/Spring.Core/Util/AssertUtils.cs b/src/Spring/Spring.Core/Util/AssertUtils.cs index c5394745..6b252d51 100644 --- a/src/Spring/Spring.Core/Util/AssertUtils.cs +++ b/src/Spring/Spring.Core/Util/AssertUtils.cs @@ -168,6 +168,29 @@ namespace Spring.Util } } + /// + /// Checks the value of the supplied and throws + /// an if it is , contains no elements or only null elements. + /// + /// The array or collection to check. + /// The argument name. + /// + /// If the supplied is , + /// contains no elements or only null elements. + /// + public static void ArgumentHasElements(ICollection argument, string name) + { + if (!ArrayUtils.HasElements(argument)) + { + throw new ArgumentException( + name, + string.Format( + CultureInfo.InvariantCulture, + "Argument '{0}' must not be null or resolve to an empty collection and must contain non-null elements", name)); + } + } + + /// /// Checks whether the specified can be cast /// into the . diff --git a/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs b/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs index eefc76d8..4173b511 100644 --- a/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs +++ b/src/Spring/Spring.Web.Extensions/Web/Script/Services/ScriptHandlerFactory.cs @@ -26,7 +26,6 @@ using System.Web; using System.Web.Script.Services; using Spring.Context; -using Spring.Context.Support; using Spring.Util; using Spring.Web.Services; using Spring.Web.Support; diff --git a/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs b/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs index b6932600..c9256a15 100644 --- a/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs +++ b/src/Spring/Spring.Web/Context/Support/WebApplicationContext.cs @@ -29,8 +29,11 @@ using System.Web; using System.Web.Hosting; using Common.Logging; using Spring.Collections; +using Spring.Objects; +using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; +using Spring.Objects.Support; using Spring.Util; #endregion diff --git a/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs b/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs index 43eae8c3..1a1a515c 100644 --- a/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs +++ b/src/Spring/Spring.Web/Context/Support/WebSupportModule.cs @@ -26,15 +26,17 @@ using System.Reflection; using System.Web; using System.Web.Caching; using System.Web.SessionState; - +using System.Web.UI; using Common.Logging; using Spring.Core.IO; using Spring.Core.TypeConversion; using Spring.Core.TypeResolution; using Spring.Expressions; +using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; using Spring.Threading; using Spring.Util; +using Spring.Web.Support; #endregion @@ -46,6 +48,28 @@ namespace Spring.Context.Support /// Erich Eichinger public class WebSupportModule : IHttpModule { + /// + /// Identifies the Objectdefinition used for the current IHttpHandler instance in TLS + /// + private static readonly string CURRENTHANDLER_OBJECTDEFINITION = "__spring.web" + new Guid().ToString(); + + /// + /// Holds the handler configuration information. + /// + private class HandlerConfigurationMetaData + { + public readonly IConfigurableApplicationContext ApplicationContext; + public readonly string ObjectDefinitionName; + public readonly bool IsContainerManaged; + + public HandlerConfigurationMetaData(IConfigurableApplicationContext applicationContext, string objectDefinitionName, bool isContainerManaged) + { + ApplicationContext = applicationContext; + ObjectDefinitionName = objectDefinitionName; + IsContainerManaged = isContainerManaged; + } + } + private static readonly ILog s_log; private static bool s_isInitialized = false; @@ -64,28 +88,28 @@ namespace Spring.Context.Support /// static WebSupportModule() { - s_log = LogManager.GetLogger(typeof(WebSupportModule)); + s_log = LogManager.GetLogger( typeof( WebSupportModule ) ); // register additional resource handler - ResourceHandlerRegistry.RegisterResourceHandler(WebUtils.DEFAULT_RESOURCE_PROTOCOL, typeof(WebResource)); + ResourceHandlerRegistry.RegisterResourceHandler( WebUtils.DEFAULT_RESOURCE_PROTOCOL, typeof( WebResource ) ); // replace default IResource converter - TypeConverterRegistry.RegisterConverter(typeof(IResource), + TypeConverterRegistry.RegisterConverter( typeof( IResource ), new ResourceConverter( - new ConfigurableResourceLoader(WebUtils.DEFAULT_RESOURCE_PROTOCOL))); + new ConfigurableResourceLoader( WebUtils.DEFAULT_RESOURCE_PROTOCOL ) ) ); // default to hybrid thread storage implementation - LogicalThreadContext.SetStorage(new HybridContextStorage()); + LogicalThreadContext.SetStorage( new HybridContextStorage() ); - s_log.Debug("Set default resource protocol to 'web' and installed HttpContext-aware HybridContextStorage"); + s_log.Debug( "Set default resource protocol to 'web' and installed HttpContext-aware HybridContextStorage" ); } /// /// Registers this module for all events required by the Spring.Web framework /// - public virtual void Init(HttpApplication app) + public virtual void Init( HttpApplication app ) { - lock (typeof(WebSupportModule)) + lock (typeof( WebSupportModule )) { - s_log.Debug("Initializing Application instance"); + s_log.Debug( "Initializing Application instance" ); if (!s_isInitialized) { HttpModuleCollection modules = app.Modules; @@ -94,7 +118,7 @@ namespace Spring.Context.Support if (modules[moduleKey] is SessionStateModule) { #if !NET_1_1 - HookSessionEvent((SessionStateModule) modules[moduleKey]); + HookSessionEvent( (SessionStateModule)modules[moduleKey] ); #else HookSessionEvent11(); #endif @@ -108,16 +132,85 @@ namespace Spring.Context.Support VirtualEnvironment.SetInitialized(); } - app.EndRequest += new EventHandler(VirtualEnvironment.RaiseEndRequest); + app.PreRequestHandlerExecute += new EventHandler( OnPreRequestHandlerExecute ); + app.EndRequest += new EventHandler( VirtualEnvironment.RaiseEndRequest ); // ensure context is instantiated IConfigurableApplicationContext appContext = WebApplicationContext.GetRootContext() as IConfigurableApplicationContext; // configure this app + it's module instances if (appContext == null) { - throw new InvalidOperationException("Implementations of IApplicationContext must also implement IConfigurableApplicationContext"); + throw new InvalidOperationException( "Implementations of IApplicationContext must also implement IConfigurableApplicationContext" ); + } + HttpApplicationConfigurer.Configure( appContext, app ); + } + + /// + /// Configures the current IHttpHandler as specified by . + /// + private void OnPreRequestHandlerExecute( object sender, EventArgs e ) + { + HandlerConfigurationMetaData hCfg = (HandlerConfigurationMetaData)LogicalThreadContext.GetData( CURRENTHANDLER_OBJECTDEFINITION ); + if (hCfg != null) + { + HttpApplication app = (HttpApplication)sender; + //app.Context.Handler = + ConfigureHandler( app.Context.Handler, hCfg.ApplicationContext, hCfg.ObjectDefinitionName, hCfg.IsContainerManaged ); + } + } + + /// + /// + /// + /// + /// + public static void SetCurrentHandlerConfiguration( IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged ) + { + LogicalThreadContext.SetData( CURRENTHANDLER_OBJECTDEFINITION, new HandlerConfigurationMetaData(applicationContext, name, isContainerManaged) ); + } + + /// + /// + /// + /// + /// + /// + public IHttpHandler ConfigureHandler( IHttpHandler handler, IConfigurableApplicationContext applicationContext, string name, bool isContainerManaged) + { + ApplyDependencyInjectionInfrastructure(handler, applicationContext); + + if (isContainerManaged) + { + handler = (IHttpHandler)applicationContext.ObjectFactory.ConfigureObject( handler, name ); + } + else + { + // at a minimum we'll apply ObjectPostProcessors + handler = (IHttpHandler)applicationContext.ObjectFactory.ApplyObjectPostProcessorsBeforeInitialization(handler, name); + handler = (IHttpHandler)applicationContext.ObjectFactory.ApplyObjectPostProcessorsAfterInitialization(handler, name); + } + + return handler; + } + + /// + /// Apply dependency injection stuff on the handler. + /// + /// the handler to be intercepted + /// the context responsible for configuring this handler + private static void ApplyDependencyInjectionInfrastructure(IHttpHandler handler, IApplicationContext applicationContext) + { + if (handler is Control) + { + ControlInterceptor.EnsureControlIntercepted(applicationContext, (Control)handler); + } + else + { + if (handler is ISupportsWebDependencyInjection) + { + ((ISupportsWebDependencyInjection)handler).DefaultApplicationContext = applicationContext; + } } - HttpApplicationConfigurer.Configure(appContext, app); } /// @@ -130,15 +223,15 @@ namespace Spring.Context.Support #region Session Handling Stuff - private static void OnCacheItemRemoved(string key, object value, CacheItemRemovedReason reason) + private static void OnCacheItemRemoved( string key, object value, CacheItemRemovedReason reason ) { - s_log.Debug("end session " + key + " because of " + reason); + s_log.Debug( "end session " + key + " because of " + reason ); try { - HttpSessionState ss = CreateSessionState(key, value); + HttpSessionState ss = CreateSessionState( key, value ); - VirtualEnvironment.RaiseEndSession(ss, reason); + VirtualEnvironment.RaiseEndSession( ss, reason ); } catch (Exception ex) { @@ -146,51 +239,51 @@ namespace Spring.Context.Support // are we on a current request? if (HttpContext.Current != null) { - s_log.Error(msg, ex); + s_log.Error( msg, ex ); } else { // this is an async session timout - log as fatal since this is the thread's exit point! - s_log.Fatal(msg, ex); + s_log.Fatal( msg, ex ); } } finally { if (s_originalCallback != null) { - s_originalCallback(key, value, reason); - } + s_originalCallback( key, value, reason ); + } } } #if !NET_1_1 - private static void HookSessionEvent(SessionStateModule sessionStateModule) + private static void HookSessionEvent( SessionStateModule sessionStateModule ) { // Hook only into InProcState - all others ignore SessionEnd anyway - object store = ExpressionEvaluator.GetValue(sessionStateModule, "_store"); + object store = ExpressionEvaluator.GetValue( sessionStateModule, "_store" ); if ((store != null) && store.GetType().Name == "InProcSessionStateStore") { - s_log.Debug("attaching to InProcSessionStateStore"); - s_originalCallback = (CacheItemRemovedCallback) ExpressionEvaluator.GetValue(store, "_callback"); - ExpressionEvaluator.SetValue(store, "_callback", new CacheItemRemovedCallback(OnCacheItemRemoved)); + s_log.Debug( "attaching to InProcSessionStateStore" ); + s_originalCallback = (CacheItemRemovedCallback)ExpressionEvaluator.GetValue( store, "_callback" ); + ExpressionEvaluator.SetValue( store, "_callback", new CacheItemRemovedCallback( OnCacheItemRemoved ) ); - CACHEKEYPREFIXLENGTH = (int) ExpressionEvaluator.GetValue(store, "CACHEKEYPREFIXLENGTH"); + CACHEKEYPREFIXLENGTH = (int)ExpressionEvaluator.GetValue( store, "CACHEKEYPREFIXLENGTH" ); } } - private static HttpSessionState CreateSessionState(string key, object state) + private static HttpSessionState CreateSessionState( string key, object state ) { - string id = key.Substring(CACHEKEYPREFIXLENGTH); + string id = key.Substring( CACHEKEYPREFIXLENGTH ); ISessionStateItemCollection sessionItems = - (ISessionStateItemCollection) ExpressionEvaluator.GetValue(state, "_sessionItems"); + (ISessionStateItemCollection)ExpressionEvaluator.GetValue( state, "_sessionItems" ); HttpStaticObjectsCollection staticObjects = - (HttpStaticObjectsCollection) ExpressionEvaluator.GetValue(state, "_staticObjects"); - int timeout = (int) ExpressionEvaluator.GetValue(state, "_timeout"); - TypeRegistry.RegisterType("SessionStateModule", typeof(SessionStateModule)); + (HttpStaticObjectsCollection)ExpressionEvaluator.GetValue( state, "_staticObjects" ); + int timeout = (int)ExpressionEvaluator.GetValue( state, "_timeout" ); + TypeRegistry.RegisterType( "SessionStateModule", typeof( SessionStateModule ) ); HttpCookieMode cookieMode = - (HttpCookieMode) ExpressionEvaluator.GetValue(null, "SessionStateModule.s_configCookieless"); + (HttpCookieMode)ExpressionEvaluator.GetValue( null, "SessionStateModule.s_configCookieless" ); SessionStateMode stateMode = - (SessionStateMode) ExpressionEvaluator.GetValue(null, "SessionStateModule.s_configMode"); + (SessionStateMode)ExpressionEvaluator.GetValue( null, "SessionStateModule.s_configMode" ); HttpSessionStateContainer container = new HttpSessionStateContainer( id , sessionItems @@ -202,11 +295,11 @@ namespace Spring.Context.Support , true ); - return (HttpSessionState) Activator.CreateInstance( - typeof(HttpSessionState) + return (HttpSessionState)Activator.CreateInstance( + typeof( HttpSessionState ) , BindingFlags.Instance | BindingFlags.NonPublic , null - , new object[] {container} + , new object[] { container } , CultureInfo.InvariantCulture ); } diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs index f9c58e7e..3e8a49b1 100644 --- a/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs +++ b/src/Spring/Spring.Web/Objects/Factory/Support/WebObjectFactory.cs @@ -327,7 +327,7 @@ namespace Spring.Objects.Factory.Support scopedSingletonCache.Add(objectName, TemporarySingletonPlaceHolder); try { - instance = CreateObject(objectName, objectDefinition, arguments, true); + instance = InstantiateObject(objectName, objectDefinition, arguments, true, false); AssertUtils.ArgumentNotNull(instance, "instance"); scopedSingletonCache[objectName] = instance; } diff --git a/src/Spring/Spring.Web/Spring.Web.2005.csproj b/src/Spring/Spring.Web/Spring.Web.2005.csproj index 64008c51..6fd4af08 100644 --- a/src/Spring/Spring.Web/Spring.Web.2005.csproj +++ b/src/Spring/Spring.Web/Spring.Web.2005.csproj @@ -159,9 +159,6 @@ Code - - - @@ -184,7 +181,6 @@ Code - Code @@ -192,10 +188,8 @@ - - ASPXCodeBehind Code diff --git a/src/Spring/Spring.Web/Spring.Web.2008.csproj b/src/Spring/Spring.Web/Spring.Web.2008.csproj index 5ee91d65..5a58e020 100644 --- a/src/Spring/Spring.Web/Spring.Web.2008.csproj +++ b/src/Spring/Spring.Web/Spring.Web.2008.csproj @@ -160,9 +160,6 @@ Code - - - @@ -185,7 +182,6 @@ Code - Code @@ -193,10 +189,8 @@ - - ASPXCodeBehind Code diff --git a/src/Spring/Spring.Web/Web/Process/IProcess.cs b/src/Spring/Spring.Web/Web/Process/IProcess.cs deleted file mode 100644 index 9c9617c5..00000000 --- a/src/Spring/Spring.Web/Web/Process/IProcess.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; - -namespace Spring.Web.Process -{ - /// - /// An interface that different process implementations need to support. - /// - public interface IProcess - { - /// - /// Unique ID of this process instance. - /// - string Id { get; } - - /// - /// Controller for the component. - /// - /// - /// Process controller will be shared by all the views - /// that belong to this process. - /// - object Controller { get; set; } - - /// - /// Gets the name of the current view. - /// - string CurrentView { get; } - - /// - /// Gets the the flag that indicates if selected view - /// has changed during the current request. - /// - bool ViewChanged { get; } - - /// - /// Starts the process. - /// - /// Referrer URL. - void Start(string referrerUrl); - - /// - /// Resolves view for the specified view name. - /// - /// Name of the view to go to. - void SetView(string viewName); - - /// - /// Ends the process. - /// - void End(); - } -} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Process/ProcessManager.cs b/src/Spring/Spring.Web/Web/Process/ProcessManager.cs deleted file mode 100644 index 89c66723..00000000 --- a/src/Spring/Spring.Web/Web/Process/ProcessManager.cs +++ /dev/null @@ -1,69 +0,0 @@ -#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.Collections; - -namespace Spring.Web.Process -{ - /// - /// Singleton that keeps track of all active process instances. - /// - /// Aleksandar Seovic - public class ProcessManager - { - private static readonly ProcessManager instance = new ProcessManager(); - - private IDictionary processInstances = new Hashtable(); - - /// - /// Creates singleton instance. - /// - private ProcessManager() - {} - - /// - /// Registers process instance. - /// - /// Process instance to register. - public static void RegisterProcess(IProcess process) - { - instance.processInstances.Add(process.Id, process); - } - - /// - /// Returns process with the specified ID. - /// - /// Process ID to use for lookup. - /// Process with the specified ID, or null if process with that ID is not registered. - public static IProcess GetProcess(string id) - { - return (IProcess) instance.processInstances[id]; - } - - /// - /// Unregisters process with the specified ID. - /// - /// ID of the process to unregister. - public static void UnregisterProcess(string id) - { - instance.processInstances.Remove(id); - } - } -} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Services/WebServiceHandlerFactory.cs b/src/Spring/Spring.Web/Web/Services/WebServiceHandlerFactory.cs index e17d8db9..65572a52 100644 --- a/src/Spring/Spring.Web/Web/Services/WebServiceHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Services/WebServiceHandlerFactory.cs @@ -29,6 +29,7 @@ using System.Web.Services; using Spring.Context; using Spring.Context.Support; +using Spring.Objects.Factory.Config; using Spring.Util; using Spring.Web.Support; diff --git a/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs index 9ece991e..58e310ff 100644 --- a/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/AbstractHandlerFactory.cs @@ -48,6 +48,43 @@ namespace Spring.Web.Support /// Aleksandar Seovic public abstract class AbstractHandlerFactory : IHttpHandlerFactory { + #region NamedObjectDefinition Utility + /// + /// Holds a named + /// + /// Erich Eichinger + protected internal class NamedObjectDefinition + { + private readonly string _name; + private readonly IObjectDefinition _objectDefinition; + + /// + /// Creates a new name/objectdefinition pair. + /// + public NamedObjectDefinition(string name, IObjectDefinition objectDefinition) + { + _name = name; + _objectDefinition = objectDefinition; + } + + /// + /// Get the name of the attached object definition + /// + public string Name + { + get { return _name; } + } + + /// + /// Get the . + /// + public IObjectDefinition ObjectDefinition + { + get { return _objectDefinition; } + } + } + #endregion + /// /// Holds all handlers having == true. /// @@ -255,39 +292,5 @@ namespace Spring.Web.Support return (pageDefinition == null) ? (NamedObjectDefinition)null : new NamedObjectDefinition( objectDefinitionName, pageDefinition ); } - - /// - /// DO NOT USE - this is subject to change! - /// - protected internal class NamedObjectDefinition - { - private readonly string _name; - private readonly IObjectDefinition _objectDefinition; - - /// - /// DO NOT USE - /// - public NamedObjectDefinition( string name, IObjectDefinition objectDefinition ) - { - _name = name; - _objectDefinition = objectDefinition; - } - - /// - /// DO NOT USE - /// - public string Name - { - get { return _name; } - } - - /// - /// DO NOT USE - /// - public IObjectDefinition ObjectDefinition - { - get { return _objectDefinition; } - } - } } } \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/AbstractProcessHandler.cs b/src/Spring/Spring.Web/Web/Support/AbstractProcessHandler.cs deleted file mode 100644 index 37fe10f4..00000000 --- a/src/Spring/Spring.Web/Web/Support/AbstractProcessHandler.cs +++ /dev/null @@ -1,312 +0,0 @@ -#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.Web; -using System.Web.SessionState; -using Spring.Collections; -using Spring.Context; -using Spring.Util; -using Spring.Web.Process; -using Spring.Web.Support; - -#endregion - -namespace Spring.Web.Support -{ - /// - /// An abstract base class that defines common behavior for different process implementations. - /// - /// Aleksandar Seovic - public abstract class AbstractProcessHandler : IProcess, ISharedStateAware, IApplicationContextAware, IHttpHandler, IRequiresSessionState - { - /// - /// Parameter name that is used for process ID. - /// - protected internal const string ProcessIdParamName = "pid"; - - #region Fields - - private string id = Guid.NewGuid().ToString("N"); - private IProcess parent; - private object controller; - private string defaultView; - private string currentView; - private IDictionary views = new CaseInsensitiveHashtable(); //CollectionsUtil.CreateCaseInsensitiveHashtable(); - private IDictionary sharedState; - private IApplicationContext applicationContext; - private string processUrl; - private bool viewChanged; - - #endregion - - #region Constructors - - /// - /// Creates instance of the process and registers it with the . - /// - public AbstractProcessHandler() - { - ProcessManager.RegisterProcess(this); - } - - #endregion - - #region Properties - - /// - /// Unique ID of this component instance. - /// - public string Id - { - get { return this.id; } - } - - /// - /// Gets or sets the parent process. - /// - internal IProcess Parent - { - get { return this.parent; } - set { this.parent = value; } - } - - /// - /// Returns a thread-safe dictionary that contains state that is shared by - /// all views of this component. - /// - public IDictionary SharedState - { - get { return this.sharedState; } - set { this.sharedState = value; } - } - - /// - /// Controller for the component. - /// - /// - /// Process controller will be shared by all the views - /// that belong to this component. - /// - public object Controller - { - get { return this.controller; } - set { this.controller = value; } - } - - /// - /// Default view for the component. - /// - public string DefaultView - { - get { return this.defaultView; } - set { this.defaultView = value; } - } - - /// - /// Gets the name of the current view. - /// - public string CurrentView - { - get - { - if (this.currentView == null) - { - this.CurrentView = this.defaultView; - } - return this.currentView; - } - set - { - string oldView = this.currentView; - if (this.views.Contains(value)) - { - this.currentView = (string) this.views[value]; - } - else - { - this.currentView = value; - } - this.viewChanged = (oldView != this.currentView); - } - } - - /// - /// Gets the the flag that indicates if selected view - /// has changed during the current request. - /// - public bool ViewChanged - { - get { return this.viewChanged; } - } - - /// - /// Gets a map of process views. - /// - public IDictionary Views - { - get { return this.views; } - } - - /// - /// Gets the process URL. - /// - protected string ProcessUrl - { - get { return this.processUrl; } - } - - #endregion - - #region Public methods - - /// - /// Starts the process. - /// - /// Process URL. - public void Start(string url) - { - this.processUrl = url; - this.NavigateToStartView(); - } - - /// - /// Resolves and sets the view for the specified view name. - /// - /// Name of the view to go to. - public virtual void SetView(string viewName) - { - this.CurrentView = viewName; - this.NavigateToCurrentView(); - } - - /// - /// Ends the process by unregistering it from the . - /// - public virtual void End() - { - ProcessManager.UnregisterProcess(this.id); - if (this.parent != null) - { - this.parent.SetView(this.parent.CurrentView); - } - } - - #endregion - - #region Abstract methods - - /// - /// Method that needs to be implemented by specific process implementations - /// in order to navigate to the first view in the process. - /// - protected abstract void NavigateToStartView(); - - /// - /// Method that needs to be implemented by specific process implementations - /// in order to navigate to the current view. - /// - protected abstract void NavigateToCurrentView(); - - #endregion - - #region IHttpHandler implementation - - /// - /// Processes the request by delegating to appropriate view, which could be - /// another process. - /// - /// - void IHttpHandler.ProcessRequest(HttpContext context) - { - IHttpHandler handler = (IHttpHandler) this.applicationContext.GetObject(WebUtils.GetPageName(this.CurrentView)); - this.viewChanged = false; - - if (handler is AbstractProcessHandler) - { - ((AbstractProcessHandler) handler).Parent = this; - // TODO: start child process - } - - if (handler is IProcessAware) - { - ((IProcessAware) handler).Process = this; - } - if (handler is ISharedStateAware) - { - ((ISharedStateAware) handler).SharedState = this.sharedState; - } - - context.Handler = handler; - handler.ProcessRequest(context); - } - - /// - /// Returns true because this wrapper handler can be reused. - /// Actual page is instantiated at the beginning of the ProcessRequest method. - /// - bool IHttpHandler.IsReusable - { - get { return false; } - } - - #endregion - - #region IApplicationContextAware implementation - - /// - /// Sets the that this - /// object runs in. - /// - /// - /// - ///

- /// Normally this call will be used to initialize the object. - ///

- ///

- /// Invoked after population of normal object properties but before an - /// init callback such as - /// 's - /// - /// or a custom init-method. Invoked after the setting of any - /// 's - /// - /// property. - ///

- ///
- /// - /// In the case of application context initialization errors. - /// - /// - /// If thrown by any application context methods. - /// - /// - public IApplicationContext ApplicationContext - { - set { this.applicationContext = value; } - } - - #endregion - } -} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs b/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs index 705b6d67..d78c190f 100644 --- a/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs +++ b/src/Spring/Spring.Web/Web/Support/PageHandlerFactory.cs @@ -32,10 +32,9 @@ using Common.Logging; using Spring.Collections; using Spring.Context; using Spring.Context.Support; -using Spring.Objects.Factory.Config; +using Spring.Objects; using Spring.Objects.Factory.Support; using Spring.Util; -using Spring.Web.Process; #endregion @@ -78,9 +77,9 @@ namespace Spring.Web.Support /// Requested page URL /// Translated server path for the page /// Instance of the IHttpHandler object that should be used to process request. - public override IHttpHandler GetHandler( HttpContext context, string requestType, string url, string physicalPath ) + public override IHttpHandler GetHandler(HttpContext context, string requestType, string url, string physicalPath) { - new SecurityPermission( SecurityPermissionFlag.UnmanagedCode ).Assert(); + new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); return base.GetHandler(context, requestType, url, physicalPath); } @@ -93,321 +92,31 @@ namespace Spring.Web.Support /// The requested . /// The physical path of the requested resource. /// A handler instance for the current request. - protected override IHttpHandler CreateHandlerInstance( HttpContext context, string requestType, string url, string physicalPath ) + protected override IHttpHandler CreateHandlerInstance(HttpContext context, string requestType, string url, string physicalPath) { - IHttpHandler pageHandlerWrapper; - IConfigurableApplicationContext appContext = GetCheckedApplicationContext( url ); + IHttpHandler handler; + IConfigurableApplicationContext appContext = GetCheckedApplicationContext(url); if (appContext == null) { - throw new InvalidOperationException( - "Implementations of IApplicationContext must also implement IConfigurableApplicationContext" ); + throw new InvalidOperationException("PageHandlerFactory requires an IConfigurableApplicationContext"); } - string appRelativeVirtualPath = WebUtils.GetAppRelativePath( url ); - NamedObjectDefinition namedPageDefinition = FindWebObjectDefinition( appRelativeVirtualPath, appContext.ObjectFactory ); + string appRelativeVirtualPath = WebUtils.GetAppRelativePath(url); + NamedObjectDefinition namedPageDefinition = FindWebObjectDefinition(appRelativeVirtualPath, appContext.ObjectFactory); if (namedPageDefinition != null) { - Type pageType = namedPageDefinition.ObjectDefinition.ObjectType; - if (typeof( IRequiresSessionState ).IsAssignableFrom( pageType )) - { - pageHandlerWrapper = new SessionAwarePageHandlerWrapper( appContext, namedPageDefinition.Name, url, null ); - } - else - { - pageHandlerWrapper = new PageHandlerWrapper( appContext, namedPageDefinition.Name, url, null ); - } + handler = (IHttpHandler)appContext.CreateObject(namedPageDefinition.Name, typeof(IHttpHandler), null); + WebSupportModule.SetCurrentHandlerConfiguration(appContext, namedPageDefinition.Name, true); } else { - Type pageType = WebObjectUtils.GetCompiledPageType( url ); - if (typeof( IRequiresSessionState ).IsAssignableFrom( pageType )) - { - pageHandlerWrapper = new SessionAwarePageHandlerWrapper( appContext, appRelativeVirtualPath, url, physicalPath ); - } - else - { - pageHandlerWrapper = new PageHandlerWrapper( appContext, appRelativeVirtualPath, url, physicalPath ); - } - } - return pageHandlerWrapper; - } - } - - /// - /// Wrapper for handlers that do not require . - /// - /// - /// NOTE: This class has to extend System.Web.UI.Page instead of simply - /// implementing IHttpHandler in order for Server.Transfer to work properly. - /// This in turn requires explicit IHttpHandler implementation in order to - /// override non-virtual methods from the base Page class. - /// - internal class PageHandlerWrapper : Page, IHttpHandler - { -#if NET_2_0 && !MONO_2_0 - private static readonly FieldInfo fiHttpContext_CurrentHandler = - typeof( HttpContext ).GetField( "_currentHandler", BindingFlags.NonPublic | BindingFlags.Instance ); -#endif -#if MONO_2_0 - private static readonly FieldInfo fiHttpContext_CurrentHandler = - typeof(HttpContext).GetField("handler", BindingFlags.NonPublic | BindingFlags.Instance); -#endif -#if NET_2_0 || !MONO_2_0 - private static readonly MethodInfo miPage_SetPreviousPage = - typeof( System.Web.UI.Page ).GetMethod( "SetPreviousPage", BindingFlags.NonPublic | BindingFlags.Instance ); -#endif - - private readonly IApplicationContext appContext; - private readonly string pageId; - private readonly string url; - private readonly string path; - - // cache handler if IsReusable == true - // since we don't use sync, make it volatile - private volatile IHttpHandler cachedHandler; - - // holds shared state for handlerType - private Type handlerType; - private IDictionary handlerState; - - private readonly object syncRoot = new object(); - - /// - /// Initializes a new instance of the class. - /// - /// Application context instance to retrieve page from. - /// Name of the page object to execute. - /// Requested page URL. - /// Translated server path for the page. - public PageHandlerWrapper( IApplicationContext appContext, string pageName, string url, string path ) - { - this.appContext = appContext; - this.pageId = pageName; - this.url = url; - this.path = path; - } - - /// - /// Initializes a new instance of the class. - /// - /// Application context instance to retrieve page from. - /// Name of the page object to execute. - public PageHandlerWrapper( IApplicationContext appContext, string pageName ) - : this( appContext, pageName, null, null ) - { - } - - #region Properties - - /// - /// Use for sync access to this PageHandler instance. - /// - public object SyncRoot - { - get { return syncRoot; } - } - - /// - /// Gets that contains handler state. - /// - /// - /// This will be assigned to the SharedState - /// property of instances that implement - /// interface. - /// - public IDictionary HandlerState - { - get { return handlerState; } - } - - #endregion - - void IHttpHandler.ProcessRequest( HttpContext context ) - { - IHttpHandler handler = cachedHandler; - - if (handler == null) - { - if (path != null) - { - handler = CreatePageInstance(); - } - else - { - handler = GetOrCreateProcessHandler( context ); - } - - // note, that we don't care about sync here. The last call wins (it's the most current handler instance anyway) - if (handler.IsReusable) - cachedHandler = handler; + handler = WebObjectUtils.CreatePageInstance(url); + WebSupportModule.SetCurrentHandlerConfiguration(appContext, url, false); } - // replace handler proxy on context with "real" handler - if (this == context.Handler) - { - context.Handler = handler; - } - -#if NET_2_0 - // this may happen under load, if GetHandler() - // and ProcessRequest() are executed under different threads - // fix this... - if (this == context.CurrentHandler) - { - fiHttpContext_CurrentHandler.SetValue( context, handler ); - } - - if (handler is System.Web.UI.Page) - { - System.Web.UI.Page page = (Page)handler; - - // TODO: to fix this would require a change to the Mono source as there is no mechanisim (public or private) for explicitly setting the - // PreviousPage at the moment -#if !MONO_2_0 - // During Server.Transfer/Execute() the PreviousPage property gets set - if (this.PreviousPage != null) - { - miPage_SetPreviousPage.Invoke( page, new object[] { this.PreviousPage } ); - } -#endif - } -#endif - - ApplySharedState( handler ); - ApplyDependencyInjection( handler ); - - handler.ProcessRequest( context ); - } - - /// - /// Returns true because this wrapper handler can be reused. - /// Actual page is instantiated at the beginning of the ProcessRequest method. - /// - bool IHttpHandler.IsReusable - { - get { return true; } - } - - /// - /// Creates a page instance corresponding to this handler's url. - /// - private IHttpHandler CreatePageInstance() - { - IHttpHandler handler; - handler = WebObjectUtils.CreatePageInstance( url ); - if (handler is IApplicationContextAware) - { - ((IApplicationContextAware)handler).ApplicationContext = appContext; - } return handler; } - - /// - /// Gets or - if not found - creates a process handler instance. - /// - private IHttpHandler GetOrCreateProcessHandler( HttpContext context ) - { - IHttpHandler handler = null; - string processId = context.Request[AbstractProcessHandler.ProcessIdParamName]; - if (processId != null) - { - handler = (IHttpHandler)ProcessManager.GetProcess( processId ); - } - - if (handler == null) - { - handler = (IHttpHandler)this.appContext.GetObject( this.pageId ); - if (handler is IProcess) - { - ((IProcess)handler).Start( url ); - } - } - return handler; - } - - /// - /// Apply dependency injection stuff on the handler. - /// - /// - private void ApplyDependencyInjection( IHttpHandler handler ) - { - if (handler is Control) - { - ControlInterceptor.EnsureControlIntercepted( appContext, (Control)handler ); - } - else - { - if (handler is ISupportsWebDependencyInjection) - { - ((ISupportsWebDependencyInjection)handler).DefaultApplicationContext = appContext; - } - } - } - - /// - /// Applies to the given handler if applicable. - /// - private void ApplySharedState( IHttpHandler handler ) - { - if (handler is ISharedStateAware) - { - CheckIfPageWasRecompiled( handler ); - ((ISharedStateAware)handler).SharedState = this.handlerState; - } - } - - /// - /// Checks, if page has been recompiled. Creates/discards handlerState if necessary. - /// - /// - private void CheckIfPageWasRecompiled( IHttpHandler handler ) - { - if (handlerType != handler.GetType()) - { - lock (SyncRoot) - { - if (handlerType != handler.GetType()) - { - // discard old handlerState and cache new pagetype - handlerState = new SynchronizedHashtable(); - handlerType = handler.GetType(); - } - } - } - } - } - - /// - /// Wrapper for handlers that require . - /// - /// - /// Delays page object instantiation until ProcessRequest is called - /// in order to be able to access session state. - /// - internal class SessionAwarePageHandlerWrapper : PageHandlerWrapper, IRequiresSessionState - { - /// - /// Initializes a new instance of the class. - /// - /// Application context instance to retrieve page from. - /// Name of the page object to execute. - /// Requested page URL. - /// Translated server path for the page. - public SessionAwarePageHandlerWrapper( IApplicationContext appContext, string pageName, string url, string path ) - : base( appContext, pageName, url, path ) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// Application context instance to retrieve page from. - /// Name of the page object to execute. - public SessionAwarePageHandlerWrapper( IApplicationContext appContext, string pageName ) - : base( appContext, pageName ) - { - } } } diff --git a/src/Spring/Spring.Web/Web/Support/SharedStateResourceCache.cs b/src/Spring/Spring.Web/Web/Support/SharedStateResourceCache.cs index 46f18162..fb119699 100644 --- a/src/Spring/Spring.Web/Web/Support/SharedStateResourceCache.cs +++ b/src/Spring/Spring.Web/Web/Support/SharedStateResourceCache.cs @@ -22,6 +22,7 @@ using System.Collections; using Spring.Globalization; +using Spring.Objects; using Spring.Util; #endregion diff --git a/src/Spring/Spring.Web/Web/UI/Page.cs b/src/Spring/Spring.Web/Web/UI/Page.cs index 1d7909c1..e540fc6b 100644 --- a/src/Spring/Spring.Web/Web/UI/Page.cs +++ b/src/Spring/Spring.Web/Web/UI/Page.cs @@ -37,14 +37,14 @@ using Spring.Core; using Spring.DataBinding; using Spring.Globalization; using Spring.Globalization.Resolvers; +using Spring.Objects; using Spring.Util; using Spring.Validation; -using Spring.Web.Process; using Spring.Web.Support; #if NET_2_0 using System.Web.Compilation; #endif -using IValidator=Spring.Validation.IValidator; +using IValidator = Spring.Validation.IValidator; #endregion @@ -70,9 +70,9 @@ namespace Spring.Web.UI ///

/// /// Aleksandar Seovic - [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] - [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] - public class Page : System.Web.UI.Page, IHttpHandler, IApplicationContextAware, ISharedStateAware, IProcessAware, + [AspNetHostingPermission( SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal )] + [AspNetHostingPermission( SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal )] + public class Page : System.Web.UI.Page, IHttpHandler, IApplicationContextAware, ISharedStateAware, ISupportsWebDependencyInjection, IWebDataBound, IValidationContainer { #region Constants @@ -87,8 +87,8 @@ namespace Spring.Web.UI private static readonly object EventInitComplete = new object(); #else internal static readonly MethodInfo GetLocalResourceProvider = - typeof(ResourceExpressionBuilder).GetMethod("GetLocalResourceProvider", BindingFlags.NonPublic | BindingFlags.Static, null, - new Type[] {typeof(TemplateControl)}, null); + typeof( ResourceExpressionBuilder ).GetMethod( "GetLocalResourceProvider", BindingFlags.NonPublic | BindingFlags.Static, null, + new Type[] { typeof( TemplateControl ) }, null ); #endif #endregion @@ -107,7 +107,6 @@ namespace Spring.Web.UI private MasterPage master; private String masterPageFile; #endif - private IProcess process; private object controller; private IDictionary sharedState; @@ -120,7 +119,7 @@ namespace Spring.Web.UI private IDictionary results; private IApplicationContext applicationContext; private IApplicationContext defaultApplicationContext; - private string traceCategory = "Spring.Page"; + private static readonly string traceCategory = "Spring.Page"; private IDictionary styles = new ListDictionary(); private IDictionary styleFiles = new ListDictionary(); @@ -197,7 +196,7 @@ namespace Spring.Web.UI #if !NET_2_0 protected virtual void OnPreInit(EventArgs e) #else - protected override void OnPreInit(EventArgs e) + protected override void OnPreInit( EventArgs e ) #endif { InitializeCulture(); @@ -209,7 +208,7 @@ namespace Spring.Web.UI handler(this, e); } #else - base.OnPreInit(e); + base.OnPreInit( e ); #endif } @@ -237,7 +236,7 @@ namespace Spring.Web.UI Thread.CurrentThread.CurrentUICulture = userCulture; if (userCulture.IsNeutralCulture) { - Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(userCulture.Name); + Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture( userCulture.Name ); } else { @@ -261,7 +260,7 @@ namespace Spring.Web.UI /// /// Initializes data model and controls. /// - protected override void OnInit(EventArgs e) + protected override void OnInit( EventArgs e ) { InitializeBindingManager(); @@ -271,7 +270,7 @@ namespace Spring.Web.UI } else { - LoadModel(LoadModelFromPersistenceMedium()); + LoadModel( LoadModelFromPersistenceMedium() ); } #if !NET_2_0 @@ -282,11 +281,11 @@ namespace Spring.Web.UI master.Initialize(this); } #endif - base.OnInit(e); + base.OnInit( e ); // initialize controls - Trace.Write(traceCategory, "Initialize Controls"); - OnInitializeControls(EventArgs.Empty); + Trace.Write( traceCategory, "Initialize Controls" ); + OnInitializeControls( EventArgs.Empty ); #if !NET_2_0 passedInit = true; @@ -319,12 +318,12 @@ namespace Spring.Web.UI /// /// Raises the event after page initialization. /// - protected virtual void OnPreLoadViewState(EventArgs e) + protected virtual void OnPreLoadViewState( EventArgs e ) { - EventHandler handler = (EventHandler) base.Events[EventPreLoadViewState]; + EventHandler handler = (EventHandler)base.Events[EventPreLoadViewState]; if (handler != null) { - handler(this, e); + handler( this, e ); } } @@ -343,8 +342,8 @@ namespace Spring.Web.UI /// public event EventHandler PreLoadViewState { - add { base.Events.AddHandler(EventPreLoadViewState, value); } - remove { base.Events.RemoveHandler(EventPreLoadViewState, value); } + add { base.Events.AddHandler( EventPreLoadViewState, value ); } + remove { base.Events.RemoveHandler( EventPreLoadViewState, value ); } } /// @@ -353,17 +352,17 @@ namespace Spring.Web.UI /// private void RaisePreLoadViewStateEvent() { - this.OnPreLoadViewState(EventArgs.Empty); + this.OnPreLoadViewState( EventArgs.Empty ); if (this.HasControls()) { - PreLoadViewStateRecursive(this.Controls); + PreLoadViewStateRecursive( this.Controls ); } } /// /// Recursively raises PreLoadViewState event. /// - private void PreLoadViewStateRecursive(ControlCollection controls) + private void PreLoadViewStateRecursive( ControlCollection controls ) { for (int i = 0; i < controls.Count; i++) { @@ -371,12 +370,12 @@ namespace Spring.Web.UI if (control is UserControl) { - ((UserControl) control).OnPreLoadViewState(EventArgs.Empty); + ((UserControl)control).OnPreLoadViewState( EventArgs.Empty ); } if (control.HasControls()) { - PreLoadViewStateRecursive(control.Controls); + PreLoadViewStateRecursive( control.Controls ); } } } @@ -420,27 +419,27 @@ namespace Spring.Web.UI this.BindFormData(); if (this.HasControls()) { - BindFormDataRecursive(this.Controls); + BindFormDataRecursive( this.Controls ); } } /// /// Recursively calls for all controls. /// - private void BindFormDataRecursive(ControlCollection controls) + private void BindFormDataRecursive( ControlCollection controls ) { - for(int i = 0; i < controls.Count; i++) + for (int i = 0; i < controls.Count; i++) { Control control = controls[i]; - if(control is UserControl) + if (control is UserControl) { ((UserControl)control).BindFormData(); } - if(control.HasControls()) + if (control.HasControls()) { - BindFormDataRecursive(control.Controls); + BindFormDataRecursive( control.Controls ); } } } @@ -458,17 +457,17 @@ namespace Spring.Web.UI /// into a data model. ///
/// Event arguments. - protected override void OnLoad(EventArgs e) + protected override void OnLoad( EventArgs e ) { // create dialog result if necessary -// if (GetType().IsDefined(typeof(DialogAttribute), true)) -// { -// if (!IsPostBack) -// { -// ViewState["__dialogResult"] = "redirect:" + Request.UrlReferrer.AbsoluteUri; -// } -// Results["close"] = new Result((string) ViewState["__dialogResult"]); -// } + // if (GetType().IsDefined(typeof(DialogAttribute), true)) + // { + // if (!IsPostBack) + // { + // ViewState["__dialogResult"] = "redirect:" + Request.UrlReferrer.AbsoluteUri; + // } + // Results["close"] = new Result((string) ViewState["__dialogResult"]); + // } if (IsPostBack) { @@ -477,8 +476,8 @@ namespace Spring.Web.UI } - Trace.Write(traceCategory, "Execute Handlers for Load Event"); - base.OnLoad(e); + Trace.Write( traceCategory, "Execute Handlers for Load Event" ); + base.OnLoad( e ); } /// @@ -486,26 +485,23 @@ namespace Spring.Web.UI /// PreRender event afterwards. /// /// Event arguments. - protected override void OnPreRender(EventArgs e) + protected override void OnPreRender( EventArgs e ) { - if (Process == null || !Process.ViewChanged) - { - // bind data from model to form - BindFormData(); + // bind data from model to form + BindFormData(); - if (localizer != null) - { - Trace.Write(traceCategory, "Apply Localized Resources"); - localizer.ApplyResources(this, messageSource, UserCulture); - } + if (localizer != null) + { + Trace.Write( traceCategory, "Apply Localized Resources" ); + localizer.ApplyResources( this, messageSource, UserCulture ); } - base.OnPreRender(e); + base.OnPreRender( e ); object modelToSave = SaveModel(); if (modelToSave != null) { - SaveModelToPersistenceMedium(modelToSave); + SaveModelToPersistenceMedium( modelToSave ); } } @@ -515,20 +511,20 @@ namespace Spring.Web.UI ///
public event EventHandler InitializeControls { - add { base.Events.AddHandler(EventInitializeControls, value); } - remove { base.Events.RemoveHandler(EventInitializeControls, value); } + add { base.Events.AddHandler( EventInitializeControls, value ); } + remove { base.Events.RemoveHandler( EventInitializeControls, value ); } } /// /// Raises InitializeControls event. /// /// Event arguments. - protected virtual void OnInitializeControls(EventArgs e) + protected virtual void OnInitializeControls( EventArgs e ) { - EventHandler handler = (EventHandler) base.Events[EventInitializeControls]; + EventHandler handler = (EventHandler)base.Events[EventInitializeControls]; if (handler != null) { - handler(this, e); + handler( this, e ); } } @@ -540,27 +536,27 @@ namespace Spring.Web.UI /// /// Returns the specified object, with dependencies injected. /// - protected virtual new Control LoadControl(string virtualPath) + protected virtual new Control LoadControl( string virtualPath ) { - Control control = base.LoadControl(virtualPath); - control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + Control control = base.LoadControl( virtualPath ); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control ); return control; } #if NET_2_0 - /// - /// Obtains a object by type - /// and injects dependencies according to Spring config file. - /// - /// The type of a user control. - /// parameters to pass to the control - /// - /// Returns the specified object, with dependencies injected. - /// - protected virtual new Control LoadControl(Type t, params object[] parameters) + /// + /// Obtains a object by type + /// and injects dependencies according to Spring config file. + /// + /// The type of a user control. + /// parameters to pass to the control + /// + /// Returns the specified object, with dependencies injected. + /// + protected virtual new Control LoadControl( Type t, params object[] parameters ) { - Control control = base.LoadControl(t, parameters); - control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); + Control control = base.LoadControl( t, parameters ); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control ); return control; } #endif @@ -599,7 +595,7 @@ namespace Spring.Web.UI /// The default implementation uses to store and retrieve /// the model for the current /// - protected virtual void SaveModelToPersistenceMedium(object modelToSave) + protected virtual void SaveModelToPersistenceMedium( object modelToSave ) { Session[Request.CurrentExecutionFilePath + ".Model"] = modelToSave; } @@ -611,7 +607,7 @@ namespace Spring.Web.UI /// This method should be overriden by the developer /// in order to load data model for the page. /// - protected virtual void LoadModel(object savedModel) + protected virtual void LoadModel( object savedModel ) { } @@ -634,15 +630,6 @@ namespace Spring.Web.UI #region Process and Controller support - /// - /// Gets or sets the process that this page belongs to. - /// - public IProcess Process - { - get { return this.process; } - set { this.process = value; } - } - /// /// Gets or sets controller for the page. /// @@ -660,7 +647,7 @@ namespace Spring.Web.UI public object Controller { get { return GetController(); } - set { SetController(value); } + set { SetController( value ); } } /// @@ -671,7 +658,7 @@ namespace Spring.Web.UI /// but must ensure to also change the behaviour of accordingly. /// /// Controller for the page. - protected virtual void SetController(object controller) + protected virtual void SetController( object controller ) { this.controller = controller; } @@ -686,7 +673,6 @@ namespace Spring.Web.UI /// /// The controller for this page. /// - /// If this page is being part of a process, the process' is returned. /// If no controller is set, a reference to the page itself is returned. /// /// @@ -694,14 +680,7 @@ namespace Spring.Web.UI { if (controller == null) { - if (process != null) - { - return process.Controller; - } - else - { - return this; - } + return this; } return controller; } @@ -714,8 +693,8 @@ namespace Spring.Web.UI /// Returns a thread-safe dictionary that contains state that is shared by /// all instances of this page. /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public IDictionary SharedState { get { return this.sharedState; } @@ -723,10 +702,10 @@ namespace Spring.Web.UI } #if NET_2_0 - /// - /// Overrides the default PreviousPage property to return an instance of , - /// and to work properly during server-side transfers and executes. - /// + /// + /// Overrides the default PreviousPage property to return an instance of , + /// and to work properly during server-side transfers and executes. + /// public new Page PreviousPage { get { return this.Context.PreviousHandler as Page; } @@ -785,14 +764,14 @@ namespace Spring.Web.UI } } #else - /// - /// Gets the master page that determines the overall look of the page. - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + /// + /// Gets the master page that determines the overall look of the page. + /// + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public new MasterPage Master { - get { return (MasterPage) base.Master; } + get { return (MasterPage)base.Master; } } #endif @@ -800,8 +779,8 @@ namespace Spring.Web.UI /// /// Returns true if page uses master page, false otherwise. /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public bool HasMaster { get { return Master != null || MasterPageFile != null; } @@ -815,8 +794,8 @@ namespace Spring.Web.UI /// Gets a dictionary of registered styles. ///
/// Registered styles. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public IDictionary Styles { get { return styles; } @@ -826,8 +805,8 @@ namespace Spring.Web.UI /// Gets a dictionary of registered style files. ///
/// Registered style files. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public IDictionary StyleFiles { get { return styleFiles; } @@ -838,7 +817,7 @@ namespace Spring.Web.UI ///
/// Style name. /// Style definition. - public void RegisterStyle(string name, string style) + public void RegisterStyle( string name, string style ) { styles[name] = style; } @@ -848,9 +827,9 @@ namespace Spring.Web.UI ///
/// Style name. /// True if specified style is registered, False otherwise. - public bool IsStyleRegistered(string name) + public bool IsStyleRegistered( string name ) { - return styles.Contains(name); + return styles.Contains( name ); } /// @@ -858,7 +837,7 @@ namespace Spring.Web.UI /// /// Style file key. /// Style file name. - public void RegisterStyleFile(string key, string fileName) + public void RegisterStyleFile( string key, string fileName ) { styleFiles[key] = fileName; } @@ -868,9 +847,9 @@ namespace Spring.Web.UI ///
/// Style file key. /// True if specified style file is registered, False otherwise. - public bool IsStyleFileRegistered(string key) + public bool IsStyleFileRegistered( string key ) { - return styleFiles.Contains(key); + return styleFiles.Contains( key ); } #endregion @@ -881,8 +860,8 @@ namespace Spring.Web.UI /// Gets a dictionary of registered head scripts. ///
/// Registered head scripts. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public IDictionary HeadScripts { get { return headScripts; } @@ -893,9 +872,9 @@ namespace Spring.Web.UI ///
/// Script key. /// Script text. - public void RegisterHeadScriptBlock(string key, string script) + public void RegisterHeadScriptBlock( string key, string script ) { - RegisterHeadScriptBlock(key, Script.DefaultType, script); + RegisterHeadScriptBlock( key, Script.DefaultType, script ); } /// @@ -904,10 +883,10 @@ namespace Spring.Web.UI /// Script key. /// Script language. /// Script text. - [Obsolete("The 'language' attribute is deprecated. Please use RegisterHeadScriptBlock(string key, MimeMediaType type, string script) instead", false)] - public void RegisterHeadScriptBlock(string key, string language, string script) + [Obsolete( "The 'language' attribute is deprecated. Please use RegisterHeadScriptBlock(string key, MimeMediaType type, string script) instead", false )] + public void RegisterHeadScriptBlock( string key, string language, string script ) { - headScripts[key] = new ScriptBlock(language, script); + headScripts[key] = new ScriptBlock( language, script ); } /// @@ -916,9 +895,9 @@ namespace Spring.Web.UI /// Script key. /// Script language MIME type. /// Script text. - public void RegisterHeadScriptBlock(string key, MimeMediaType type, string script) + public void RegisterHeadScriptBlock( string key, MimeMediaType type, string script ) { - headScripts[key] = new ScriptBlock(type, script); + headScripts[key] = new ScriptBlock( type, script ); } /// @@ -926,9 +905,9 @@ namespace Spring.Web.UI /// /// Script key. /// Script file name. - public void RegisterHeadScriptFile(string key, string fileName) + public void RegisterHeadScriptFile( string key, string fileName ) { - RegisterHeadScriptFile(key, Script.DefaultType, fileName); + RegisterHeadScriptFile( key, Script.DefaultType, fileName ); } /// @@ -937,10 +916,10 @@ namespace Spring.Web.UI /// Script key. /// Script language. /// Script file name. - [Obsolete("The 'language' attribute is deprecated. Please use RegisterHeadScriptFile(string key, MimeMediaType type, string filename) instead", false)] - public void RegisterHeadScriptFile(string key, string language, string fileName) + [Obsolete( "The 'language' attribute is deprecated. Please use RegisterHeadScriptFile(string key, MimeMediaType type, string filename) instead", false )] + public void RegisterHeadScriptFile( string key, string language, string fileName ) { - headScripts[key] = new ScriptFile(language, fileName); + headScripts[key] = new ScriptFile( language, fileName ); } /// @@ -949,9 +928,9 @@ namespace Spring.Web.UI /// Script key. /// Script language MIME type. /// Script file name. - public void RegisterHeadScriptFile(string key, MimeMediaType type, string fileName) + public void RegisterHeadScriptFile( string key, MimeMediaType type, string fileName ) { - headScripts[key] = new ScriptFile(type, fileName); + headScripts[key] = new ScriptFile( type, fileName ); } /// @@ -961,9 +940,9 @@ namespace Spring.Web.UI /// Element ID of the event source. /// Name of the event to handle. /// Script text. - public void RegisterHeadScriptEvent(string key, string element, string eventName, string script) + public void RegisterHeadScriptEvent( string key, string element, string eventName, string script ) { - RegisterHeadScriptEvent(key, Script.DefaultType, element, eventName, script); + RegisterHeadScriptEvent( key, Script.DefaultType, element, eventName, script ); } /// @@ -974,10 +953,10 @@ namespace Spring.Web.UI /// Element ID of the event source. /// Name of the event to handle. /// Script text. - [Obsolete("The 'language' attribute is deprecated. Please use RegisterHeadScriptEvent(string key, MimeMediaType mimeType, string element, string eventName, string script) instead")] - public void RegisterHeadScriptEvent(string key, string language, string element, string eventName, string script) + [Obsolete( "The 'language' attribute is deprecated. Please use RegisterHeadScriptEvent(string key, MimeMediaType mimeType, string element, string eventName, string script) instead" )] + public void RegisterHeadScriptEvent( string key, string language, string element, string eventName, string script ) { - headScripts[key] = new ScriptEvent(language, element, eventName, script); + headScripts[key] = new ScriptEvent( language, element, eventName, script ); } /// @@ -988,9 +967,9 @@ namespace Spring.Web.UI /// Element ID of the event source. /// Name of the event to handle. /// Script text. - public void RegisterHeadScriptEvent(string key, MimeMediaType mimeType, string element, string eventName, string script) + public void RegisterHeadScriptEvent( string key, MimeMediaType mimeType, string element, string eventName, string script ) { - headScripts[key] = new ScriptEvent(mimeType, element, eventName, script); + headScripts[key] = new ScriptEvent( mimeType, element, eventName, script ); } /// @@ -998,9 +977,9 @@ namespace Spring.Web.UI /// /// Script key. /// True if specified head script is registered, False otherwise. - public bool IsHeadScriptRegistered(string key) + public bool IsHeadScriptRegistered( string key ) { - return headScripts.Contains(key); + return headScripts.Contains( key ); } #endregion @@ -1011,11 +990,11 @@ namespace Spring.Web.UI /// Gets or sets the CSS root. /// /// The CSS root. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public string CssRoot { - get { return WebUtils.CreateAbsolutePath(Request.ApplicationPath, cssRoot); } + get { return WebUtils.CreateAbsolutePath( Request.ApplicationPath, cssRoot ); } set { cssRoot = value; } } @@ -1023,11 +1002,11 @@ namespace Spring.Web.UI /// Gets or sets the scripts root. /// /// The scripts root. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public string ScriptsRoot { - get { return WebUtils.CreateAbsolutePath(Request.ApplicationPath, scriptsRoot); } + get { return WebUtils.CreateAbsolutePath( Request.ApplicationPath, scriptsRoot ); } set { scriptsRoot = value; } } @@ -1035,11 +1014,11 @@ namespace Spring.Web.UI /// Gets or sets the images root. /// /// The images root. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public string ImagesRoot { - get { return WebUtils.CreateAbsolutePath(Request.ApplicationPath, imagesRoot); } + get { return WebUtils.CreateAbsolutePath( Request.ApplicationPath, imagesRoot ); } set { imagesRoot = value; } } @@ -1050,8 +1029,8 @@ namespace Spring.Web.UI /// /// Gets or sets map of result names to target URLs /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public IDictionary Results { get @@ -1073,12 +1052,12 @@ namespace Spring.Web.UI } else if (entry.Value is String) { - results[entry.Key] = new Result((string) entry.Value); + results[entry.Key] = new Result( (string)entry.Value ); } else { throw new TypeMismatchException( - "Unable to create result object. Please use either String or Result instances to define results."); + "Unable to create result object. Please use either String or Result instances to define results." ); } } } @@ -1088,9 +1067,9 @@ namespace Spring.Web.UI /// Redirects user to a URL mapped to specified result name. /// /// Result name. - protected internal void SetResult(string resultName) + protected internal void SetResult( string resultName ) { - GetResult(resultName).Navigate(this); + GetResult( resultName ).Navigate( this ); } @@ -1099,9 +1078,9 @@ namespace Spring.Web.UI /// /// Name of the result. /// The context to use for evaluating the SpEL expression in the Result. - protected internal void SetResult(string resultName, object context) + protected internal void SetResult( string resultName, object context ) { - GetResult(resultName).Navigate(context); + GetResult( resultName ).Navigate( context ); } @@ -1112,10 +1091,10 @@ namespace Spring.Web.UI /// /// Name of the result. /// A redirect url string. - protected internal string GetResultUrl(string resultName) + protected internal string GetResultUrl( string resultName ) { - Result result = GetResult(resultName); - return ResolveUrl(result.GetRedirectUri(this)); + Result result = GetResult( resultName ); + return ResolveUrl( result.GetRedirectUri( this ) ); } /// @@ -1126,20 +1105,20 @@ namespace Spring.Web.UI /// Name of the result. /// The context to use for evaluating the SpEL expression in the Result /// A redirect url string. - protected internal string GetResultUrl(string resultName, object context) + protected internal string GetResultUrl( string resultName, object context ) { - Result result = GetResult(resultName); - return ResolveUrl(result.GetRedirectUri(context)); + Result result = GetResult( resultName ); + return ResolveUrl( result.GetRedirectUri( context ) ); } - private Result GetResult(string resultName) + private Result GetResult( string resultName ) { Result result = (Result)Results[resultName]; if (result == null) { throw new ArgumentException( - string.Format("No URL mapping found for the specified result '{0}'.", resultName), "resultName"); + string.Format( "No URL mapping found for the specified result '{0}'.", resultName ), "resultName" ); } return result; } @@ -1167,7 +1146,7 @@ namespace Spring.Web.UI /// /// True if all of the specified validators are valid, False otherwise. /// - public bool Validate(object validationContext, params IValidator[] validators) + public bool Validate( object validationContext, params IValidator[] validators ) { IDictionary contextParams = CreateValidatorParameters(); bool result = true; @@ -1175,9 +1154,9 @@ namespace Spring.Web.UI { if (validator == null) { - throw new ArgumentException("Validator is not defined."); + throw new ArgumentException( "Validator is not defined." ); } - result = validator.Validate(validationContext, contextParams, this.validationErrors) && result; + result = validator.Validate( validationContext, contextParams, this.validationErrors ) && result; } return result; @@ -1238,7 +1217,7 @@ namespace Spring.Web.UI /// a unique key identifying the instance in the dictionary. protected virtual string GetBindingManagerKey() { - return CreateSharedStateKey("DataBindingManager"); + return CreateSharedStateKey( "DataBindingManager" ); } /// @@ -1256,13 +1235,13 @@ namespace Spring.Web.UI return new BaseBindingManager(); } - /// - /// Expose BindingManager via IDataBound interface - /// - IBindingContainer IDataBound.BindingManager - { - get { return this.BindingManager; } - } + /// + /// Expose BindingManager via IDataBound interface + /// + IBindingContainer IDataBound.BindingManager + { + get { return this.BindingManager; } + } /// /// Gets the binding manager. @@ -1290,16 +1269,16 @@ namespace Spring.Web.UI this.bindingManager = sharedState[key] as BaseBindingManager; if (this.bindingManager == null) { - Trace.Write(traceCategory, "Initialize Data Bindings"); + Trace.Write( traceCategory, "Initialize Data Bindings" ); this.bindingManager = CreateBindingManager(); if (this.bindingManager == null) { - throw new ArgumentNullException("bindingManager", - "CreateBindingManager() must not return null"); + throw new ArgumentNullException( "bindingManager", + "CreateBindingManager() must not return null" ); } InitializeDataBindings(); sharedState[key] = this.bindingManager; - OnDataBindingsInitialized(EventArgs.Empty); + OnDataBindingsInitialized( EventArgs.Empty ); } } } @@ -1308,13 +1287,13 @@ namespace Spring.Web.UI /// /// Raises the event. /// - protected virtual void OnDataBindingsInitialized(EventArgs e) + protected virtual void OnDataBindingsInitialized( EventArgs e ) { EventHandler handler = (EventHandler)base.Events[EventDataBindingsInitialized]; - if(handler != null) + if (handler != null) { - handler(this, e); + handler( this, e ); } } @@ -1325,11 +1304,11 @@ namespace Spring.Web.UI { add { - base.Events.AddHandler(EventDataBindingsInitialized, value); + base.Events.AddHandler( EventDataBindingsInitialized, value ); } remove { - base.Events.RemoveHandler(EventDataBindingsInitialized, value); + base.Events.RemoveHandler( EventDataBindingsInitialized, value ); } } @@ -1340,11 +1319,11 @@ namespace Spring.Web.UI { if (BindingManager.HasBindings) { - Trace.Write(traceCategory, "Bind Data Model onto Controls"); + Trace.Write( traceCategory, "Bind Data Model onto Controls" ); - BindingManager.BindTargetToSource(this, Controller, ValidationErrors); + BindingManager.BindTargetToSource( this, Controller, ValidationErrors ); } - OnDataBound(EventArgs.Empty); + OnDataBound( EventArgs.Empty ); } /// @@ -1354,11 +1333,11 @@ namespace Spring.Web.UI { if (BindingManager.HasBindings) { - Trace.Write(traceCategory, "Unbind Controls into Data Model"); + Trace.Write( traceCategory, "Unbind Controls into Data Model" ); - BindingManager.BindSourceToTarget(this, Controller, ValidationErrors); + BindingManager.BindSourceToTarget( this, Controller, ValidationErrors ); } - OnDataUnbound(EventArgs.Empty); + OnDataUnbound( EventArgs.Empty ); } /// @@ -1367,20 +1346,20 @@ namespace Spring.Web.UI /// public event EventHandler DataBound { - add { base.Events.AddHandler(EventDataBound, value); } - remove { base.Events.RemoveHandler(EventDataBound, value); } + add { base.Events.AddHandler( EventDataBound, value ); } + remove { base.Events.RemoveHandler( EventDataBound, value ); } } /// /// Raises DataBound event. /// /// Event arguments. - protected virtual void OnDataBound(EventArgs e) + protected virtual void OnDataBound( EventArgs e ) { - EventHandler handler = (EventHandler) base.Events[EventDataBound]; + EventHandler handler = (EventHandler)base.Events[EventDataBound]; if (handler != null) { - handler(this, e); + handler( this, e ); } } @@ -1390,20 +1369,20 @@ namespace Spring.Web.UI /// public event EventHandler DataUnbound { - add { base.Events.AddHandler(EventDataUnbound, value); } - remove { base.Events.RemoveHandler(EventDataUnbound, value); } + add { base.Events.AddHandler( EventDataUnbound, value ); } + remove { base.Events.RemoveHandler( EventDataUnbound, value ); } } /// /// Raises DataBound event. /// /// Event arguments. - protected virtual void OnDataUnbound(EventArgs e) + protected virtual void OnDataUnbound( EventArgs e ) { - EventHandler handler = (EventHandler) base.Events[EventDataUnbound]; + EventHandler handler = (EventHandler)base.Events[EventDataUnbound]; if (handler != null) { - handler(this, e); + handler( this, e ); } } @@ -1438,8 +1417,8 @@ namespace Spring.Web.UI /// If thrown by any application context methods. /// /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public virtual IApplicationContext ApplicationContext { get { return applicationContext; } @@ -1454,8 +1433,8 @@ namespace Spring.Web.UI /// Gets or sets the localizer. /// /// The localizer. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public ILocalizer Localizer { get { return this.localizer; } @@ -1464,7 +1443,7 @@ namespace Spring.Web.UI this.localizer = value; if (this.localizer.ResourceCache is NullResourceCache) { - this.localizer.ResourceCache = new SharedStateResourceCache(this); + this.localizer.ResourceCache = new SharedStateResourceCache( this ); } } } @@ -1473,16 +1452,16 @@ namespace Spring.Web.UI /// Gets or sets the culture resolver. /// /// The culture resolver. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public ICultureResolver CultureResolver { get { -// if (cultureResolver == null) -// { -// cultureResolver = new DefaultWebCultureResolver(); -// } + // if (cultureResolver == null) + // { + // cultureResolver = new DefaultWebCultureResolver(); + // } return cultureResolver; } set { cultureResolver = value; } @@ -1492,8 +1471,8 @@ namespace Spring.Web.UI /// Gets or sets the local message source. /// /// The local message source. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public IMessageSource MessageSource { get { return messageSource; } @@ -1502,7 +1481,7 @@ namespace Spring.Web.UI messageSource = value; if (messageSource != null && messageSource is AbstractMessageSource) { - ((AbstractMessageSource) messageSource).ParentMessageSource = applicationContext; + ((AbstractMessageSource)messageSource).ParentMessageSource = applicationContext; } } } @@ -1514,7 +1493,7 @@ namespace Spring.Web.UI { if (MessageSource == null) { - string MessageSourceKey = CreateSharedStateKey("MessageSource"); + string MessageSourceKey = CreateSharedStateKey( "MessageSource" ); if (this.SharedState[MessageSourceKey] == null) { lock (this.SharedState.SyncRoot) @@ -1526,14 +1505,14 @@ namespace Spring.Web.UI ResourceManager rm = GetLocalResourceManager(); if (rm != null) { - defaultMessageSource.ResourceManagers.Add(rm); + defaultMessageSource.ResourceManagers.Add( rm ); } this.SharedState[MessageSourceKey] = defaultMessageSource; } } } - MessageSource = (IMessageSource) this.SharedState[MessageSourceKey]; + MessageSource = (IMessageSource)this.SharedState[MessageSourceKey]; } } @@ -1555,13 +1534,13 @@ namespace Spring.Web.UI #if !NET_2_0 return new ResourceManager(GetType().BaseType); #else - object resourceProvider = GetLocalResourceProvider.Invoke(typeof(ResourceExpressionBuilder), new object[] {this}); + object resourceProvider = GetLocalResourceProvider.Invoke( typeof( ResourceExpressionBuilder ), new object[] { this } ); MethodInfo GetLocalResourceAssembly = - resourceProvider.GetType().GetMethod("GetLocalResourceAssembly", BindingFlags.NonPublic | BindingFlags.Instance); - Assembly localResourceAssembly = (Assembly) GetLocalResourceAssembly.Invoke(resourceProvider, null); + resourceProvider.GetType().GetMethod( "GetLocalResourceAssembly", BindingFlags.NonPublic | BindingFlags.Instance ); + Assembly localResourceAssembly = (Assembly)GetLocalResourceAssembly.Invoke( resourceProvider, null ); if (localResourceAssembly != null) { - return new ResourceManager(VirtualPathUtility.GetFileName(this.AppRelativeVirtualPath), localResourceAssembly); + return new ResourceManager( VirtualPathUtility.GetFileName( this.AppRelativeVirtualPath ), localResourceAssembly ); } return null; @@ -1573,9 +1552,9 @@ namespace Spring.Web.UI /// /// Resource name. /// Message text. - public string GetMessage(string name) + public string GetMessage( string name ) { - return messageSource.GetMessage(name, UserCulture); + return messageSource.GetMessage( name, UserCulture ); } /// @@ -1584,9 +1563,9 @@ namespace Spring.Web.UI /// Resource name. /// Message arguments that will be used to format return value. /// Formatted message text. - public string GetMessage(string name, params object[] args) + public string GetMessage( string name, params object[] args ) { - return messageSource.GetMessage(name, UserCulture, args); + return messageSource.GetMessage( name, UserCulture, args ); } /// @@ -1594,32 +1573,32 @@ namespace Spring.Web.UI /// /// Resource name. /// Resource object. - public object GetResourceObject(string name) + public object GetResourceObject( string name ) { - return messageSource.GetResourceObject(name, UserCulture); + return messageSource.GetResourceObject( name, UserCulture ); } /// /// Gets or sets user's culture /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + [Browsable( false )] + [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )] public virtual CultureInfo UserCulture { get { return CultureResolver.ResolveCulture(); } set { - CultureResolver.SetCulture(value); + CultureResolver.SetCulture( value ); Thread.CurrentThread.CurrentUICulture = value; if (value.IsNeutralCulture) { - Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(value.Name); + Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture( value.Name ); } else { Thread.CurrentThread.CurrentCulture = value; } - OnUserCultureChanged(EventArgs.Empty); + OnUserCultureChanged( EventArgs.Empty ); } } @@ -1632,11 +1611,11 @@ namespace Spring.Web.UI /// Raises UserLocaleChanged event. /// /// Event arguments. - protected virtual void OnUserCultureChanged(EventArgs e) + protected virtual void OnUserCultureChanged( EventArgs e ) { if (UserCultureChanged != null) { - UserCultureChanged(this, e); + UserCultureChanged( this, e ); } } @@ -1650,16 +1629,9 @@ namespace Spring.Web.UI ///
/// Key suffix /// Generated unique shared state key. - protected string CreateSharedStateKey(string key) + protected virtual string CreateSharedStateKey( string key ) { - if (this.Process != null) - { - return this.Process.CurrentView + "." + key; - } - else - { - return key; - } + return key; } #endregion @@ -1678,10 +1650,10 @@ namespace Spring.Web.UI /// /// Injects dependencies into control before adding it. /// - protected override void AddedControl(Control control, int index) + protected override void AddedControl( Control control, int index ) { - control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control); - base.AddedControl(control, index); + control = WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control ); + base.AddedControl( control, index ); } #endregion Dependency Injection Support diff --git a/test/Spring/Spring.Core.Tests/CommonTypes.cs b/test/Spring/Spring.Core.Tests/CommonTypes.cs index 421c7254..68b894d7 100644 --- a/test/Spring/Spring.Core.Tests/CommonTypes.cs +++ b/test/Spring/Spring.Core.Tests/CommonTypes.cs @@ -138,6 +138,11 @@ namespace Spring return false; } + public object CreateObject(string name, Type requiredType, object[] arguments) + { + return null; + } + public string[] GetAliases(string name) { return null; @@ -232,7 +237,13 @@ namespace Spring return null; } - public object GetObject(string name, Type requiredType) + public object CreateObject(string name, Type requiredType, object[] arguments) + { + innerExecute(); + return null; + } + + public object GetObject(string name, Type requiredType) { innerExecute(); return null; diff --git a/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs b/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs index 67ffa22a..7020d9f4 100644 --- a/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs +++ b/test/Spring/Spring.Core.Tests/Context/CommonTypes.cs @@ -431,6 +431,11 @@ namespace Spring.Context return null; } + public object CreateObject(string name, Type requiredType, object[] arguments) + { + return null; + } + public object GetObject(string name, Type requiredType) { return null; diff --git a/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs b/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs index ef2492bc..b02ce052 100644 --- a/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs +++ b/test/Spring/Spring.Core.Tests/Context/Support/ApplicationObjectSupportTests.cs @@ -173,6 +173,11 @@ namespace Spring.Context.Support return null; } + public object CreateObject(string name, Type requiredType, object[] arguments) + { + return null; + } + public object GetObject(string name, Type requiredType) { return null; diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs index 4b56291a..33bfd7b2 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/AbstractObjectFactoryTests.cs @@ -31,11 +31,6 @@ 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(); @@ -66,8 +61,8 @@ namespace Spring.Objects.Factory throw new System.NotImplementedException(); } - protected override object CreateObject(string name, RootObjectDefinition definition, object[] arguments, - bool allowEagerCaching) + protected override object InstantiateObject(string name, RootObjectDefinition definition, object[] arguments, + bool allowEagerCaching, bool suppressConfigure) { throw new NotImplementedException(); } diff --git a/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SharedStateAwareProcessorTests.cs b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SharedStateAwareProcessorTests.cs new file mode 100644 index 00000000..edd5a35c --- /dev/null +++ b/test/Spring/Spring.Core.Tests/Objects/Factory/Config/SharedStateAwareProcessorTests.cs @@ -0,0 +1,232 @@ +#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.Web.UI; +using NUnit.Framework; +using Rhino.Mocks; +using Spring.Objects.Factory.Support; +using Spring.Objects.Support; + +#endregion + +namespace Spring.Objects.Factory.Config +{ + /// + /// + /// + /// Erich Eichinger + [TestFixture] + public class SharedStateAwareProcessorTests + { + [Test] + public void DoesNotAllowNullOrEmptyFactoryList() + { + // check default ctor init + SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); + Assert.IsNotNull( ssap.SharedStateFactories ); + Assert.AreEqual( 0, ssap.SharedStateFactories.Length ); + + // check we accept a list at all + ssap = new SharedStateAwareProcessor( new ISharedStateFactory[] { new ByTypeSharedStateFactory() }, Int32.MaxValue ); + + // now ensure that SharedStateFactories will never be null or empty + ssap = new SharedStateAwareProcessor(); + try + { + ssap.SharedStateFactories = null; + Assert.Fail( "should throw ArgumentException" ); + } + catch (ArgumentException) + { } + + try + { + ssap.SharedStateFactories = new ISharedStateFactory[0]; + Assert.Fail( "should throw ArgumentException" ); + } + catch (ArgumentException) + { } + + try + { + ssap.SharedStateFactories = new ISharedStateFactory[] { null }; + Assert.Fail( "should throw ArgumentException" ); + } + catch (ArgumentException) + { } + + try + { + ssap = new SharedStateAwareProcessor( null, Int32.MaxValue ); + Assert.Fail( "should throw ArgumentException" ); + } + catch (ArgumentException) + { } + + try + { + ssap = new SharedStateAwareProcessor( new ISharedStateFactory[0], Int32.MaxValue ); + Assert.Fail( "should throw ArgumentException" ); + } + catch (ArgumentException) + { } + + try + { + ssap = new SharedStateAwareProcessor( new ISharedStateFactory[] { null }, Int32.MaxValue ); + Assert.Fail( "should throw ArgumentException" ); + } + catch (ArgumentException) + { } + } + + [Test] + public void BeforeInitializationIsNoOp() + { + SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); + object res = ssap.PostProcessBeforeInitialization( this, null ); + Assert.AreSame( this, res ); + } + + [Test] + public void IgnoresAlreadyPopulatedState() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + + MockRepository mocks = new MockRepository(); + ISharedStateFactory ssf1 = (ISharedStateFactory)mocks.CreateMock( typeof( ISharedStateFactory ) ); + ISharedStateAware ssa = (ISharedStateAware)mocks.DynamicMock( typeof( ISharedStateAware ) ); + + SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); + ssap.SharedStateFactories = new ISharedStateFactory[] { ssf1 }; + of.RegisterSingleton( "ssap", ssap ); + + using (Record( mocks )) + { + // preset SharedState - ssap must ignore it + Expect.Call( ssa.SharedState ).Return( new Hashtable() ); + // expect nothing else! + } + + using (Playback( mocks )) + { + ssap.PostProcessBeforeInitialization( ssa, "myPage" ); + } + } + + [Test] + public void ProbesSharedStateFactories() + { + DefaultListableObjectFactory of = new DefaultListableObjectFactory(); + + MockRepository mocks = new MockRepository(); + ISharedStateFactory ssf1 = (ISharedStateFactory)mocks.CreateMock( typeof( ISharedStateFactory ) ); + ISharedStateFactory ssf2 = (ISharedStateFactory)mocks.CreateMock( typeof( ISharedStateFactory ) ); + ISharedStateFactory ssf3 = (ISharedStateFactory)mocks.CreateMock( typeof( ISharedStateFactory ) ); + ISharedStateFactory ssf4 = (ISharedStateFactory)mocks.CreateMock( typeof( ISharedStateFactory ) ); + IDictionary ssf3ProvidedState = new Hashtable(); + + SharedStateAwareProcessor ssap = new SharedStateAwareProcessor(); + ssap.SharedStateFactories = new ISharedStateFactory[] { ssf1, ssf2, ssf3, ssf4 }; + of.RegisterSingleton( "ssap", ssap ); + + ISharedStateAware ssa = (ISharedStateAware)mocks.DynamicMock( typeof( ISharedStateAware ) ); + + // Ensure we iterate over configured SharedStateFactories until + // the first provider is found that + // a) true == provider.CanProvideState( instance, name ) + // b) null != provider.GetSharedState( instance, name ) + + using (Record( mocks )) + { + Expect.Call( ssa.SharedState ).Return( null ); + Expect.Call( ssf1.CanProvideState( ssa, "pageName" ) ).Return( false ); + Expect.Call( ssf2.CanProvideState( ssa, "pageName" ) ).Return( true ); + Expect.Call( ssf2.GetSharedStateFor( ssa, "pageName" ) ).Return( null ); + Expect.Call( ssf3.CanProvideState( ssa, "pageName" ) ).Return( true ); + Expect.Call( ssf3.GetSharedStateFor( ssa, "pageName" ) ).Return( ssf3ProvidedState ); + Expect.Call( ssa.SharedState = ssf3ProvidedState ); + } + + using (Playback( mocks )) + { + ssap.PostProcessBeforeInitialization( ssa, "pageName" ); + } + } + + #region Rhino.Mocks Compatibility Adapter + + private static IDisposable Record( MockRepository mocks ) + { +#if !NET_1_1 + return mocks.Record(); +#else + return new RecordModeChanger(mocks); +#endif + } + + private static IDisposable Playback( MockRepository mocks ) + { +#if !NET_1_1 + return mocks.Playback(); +#else + return new PlaybackModeChanger(mocks); +#endif + } + +#if NET_1_1 + private class RecordModeChanger : IDisposable + { + private MockRepository _mocks; + + public RecordModeChanger(MockRepository mocks) + { + _mocks = mocks; + } + + public void Dispose() + { + _mocks.ReplayAll(); + } + } + + private class PlaybackModeChanger : IDisposable + { + private MockRepository _mocks; + + public PlaybackModeChanger(MockRepository mocks) + { + _mocks = mocks; + } + + public void Dispose() + { + _mocks.VerifyAll(); + } + } +#endif + + #endregion Rhino.Mocks Compatibility Adapter + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/AbstractSharedStateFactoryTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/AbstractSharedStateFactoryTests.cs new file mode 100644 index 00000000..c3200baa --- /dev/null +++ b/test/Spring/Spring.Core.Tests/Objects/Support/AbstractSharedStateFactoryTests.cs @@ -0,0 +1,110 @@ +#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 NUnit.Framework; + +#endregion + +namespace Spring.Objects.Support +{ + /// + /// + /// + /// Erich Eichinger + [TestFixture] + public class AbstractSharedStateFactoryTests + { + private class TestSharedStateFactory : AbstractSharedStateFactory + { + public static readonly object SPECIAL_OBJECT = new object(); + + protected override object GetKey(object instance, string name) + { + if (instance == SPECIAL_OBJECT) return null; + return name+"|"+instance.GetHashCode(); + } + } + + [Test] + public void DefaultsToCaseInsensitiveState() + { + TestSharedStateFactory p = new TestSharedStateFactory(); + Assert.IsFalse(p.CaseSensitiveState); + IDictionary state = p.GetSharedStateFor(new object(), "no name" ); + state["foo"] = this; + Assert.AreSame(this, state["FOO"]); + } + + [Test] + public void StateDictionaryBehavesAccordingToCaseSensitiveState() + { + TestSharedStateFactory p = new TestSharedStateFactory(); + + // create case-insensitive dict + Assert.IsFalse(p.CaseSensitiveState); + IDictionary state = p.GetSharedStateFor(new object(), "no name" ); + state["foo"] = this; + Assert.AreSame(this, state["FOO"]); + + // create case-sensitive dict + p.CaseSensitiveState = true; + state = p.GetSharedStateFor(new object(), "no name" ); + state["foo"] = this; + Assert.IsFalse(state.Contains("FOO")); + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void ThrowsOnNullInstance() + { + TestSharedStateFactory p = new TestSharedStateFactory(); + // allow "null" for name + IDictionary state = p.GetSharedStateFor(new object(), null); + Assert.IsNotNull(state); + // throws on null for instance + p.GetSharedStateFor(null, "no name"); + } + + [Test] + public void SharedStateCacheIsCaseSensitive() + { + TestSharedStateFactory p = new TestSharedStateFactory(); + // allow "null" for name + IDictionary state = p.GetSharedStateFor(this, "foo"); + IDictionary state2 = p.GetSharedStateFor(this, "FOO"); + Assert.IsNotNull(state); + Assert.IsNotNull(state2); + Assert.AreNotSame(state, state2); + } + + [Test] + public void ReturnsNullStateIfKeyIsNull() + { + TestSharedStateFactory p = new TestSharedStateFactory(); + // force provider to produce a null key + IDictionary state = p.GetSharedStateFor(TestSharedStateFactory.SPECIAL_OBJECT, null); + Assert.IsNull(state); + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Web/Web/Process/IProcessAware.cs b/test/Spring/Spring.Core.Tests/Objects/Support/ByTypeSharedStateProviderTests.cs similarity index 56% rename from src/Spring/Spring.Web/Web/Process/IProcessAware.cs rename to test/Spring/Spring.Core.Tests/Objects/Support/ByTypeSharedStateProviderTests.cs index 427c4204..81c52c2c 100644 --- a/src/Spring/Spring.Web/Web/Process/IProcessAware.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/ByTypeSharedStateProviderTests.cs @@ -1,7 +1,7 @@ #region License /* - * Copyright 2002-2004 the original author or authors. + * 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. @@ -18,20 +18,22 @@ #endregion -using System.Web; +#region Imports -namespace Spring.Web.Process +using System; +using NUnit.Framework; + +#endregion + +namespace Spring.Objects.Support { /// - /// Interface that should be implemented by all s - /// that want to be aware of the they belong to. + /// /// - /// Aleksandar Seovic - public interface IProcessAware + /// Erich Eichinger + [TestFixture] + public class ByTypeSharedStateProviderTests { - /// - /// Gets or sets a process instance. - /// - IProcess Process { get; set; } + // TODO } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2005.csproj b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2005.csproj index cb72fead..68f22942 100644 --- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2005.csproj +++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2005.csproj @@ -315,6 +315,7 @@ + @@ -330,6 +331,8 @@ + + Code diff --git a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj index 037f1ac3..a8c5f282 100644 --- a/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj +++ b/test/Spring/Spring.Core.Tests/Spring.Core.Tests.2008.csproj @@ -1,7 +1,7 @@  Local - 9.0.21022 + 9.0.30729 2.0 {44B16BAA-6DF8-447C-9D7F-3AD3D854D904} Debug @@ -315,6 +315,7 @@ + @@ -329,6 +330,8 @@ + + Code diff --git a/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs index 129a4b51..731210e8 100644 --- a/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/AssertUtilsTests.cs @@ -147,5 +147,32 @@ namespace Spring.Util { AssertUtils.ArgumentHasLength(new byte[1], "foo", "Bang!"); } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ArgumentHasElementsArgumentIsNull() + { + AssertUtils.ArgumentHasElements(null, "foo"); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ArgumentHasElementsArgumentIsEmpty() + { + AssertUtils.ArgumentHasElements(new object[0], "foo"); + } + + [Test] + [ExpectedException(typeof(ArgumentException))] + public void ArgumentHasElementsArgumentContainsNull() + { + AssertUtils.ArgumentHasElements(new object[] { new object(), null, new object() }, "foo"); + } + + [Test] + public void ArgumentHasElementsArgumentContainsNonNullsOnly() + { + AssertUtils.ArgumentHasElements(new object[] { new object(), new object(), new object() }, "foo"); + } } } diff --git a/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2008.csproj b/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2008.csproj index b84699cf..23029bc1 100644 --- a/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2008.csproj +++ b/test/Spring/Spring.Web.Tests/Spring.Web.Tests.2008.csproj @@ -1,7 +1,7 @@  Local - 9.0.21022 + 9.0.30729 2.0 {C67E47AA-1ACD-41B4-A465-4D336A2319CA} Debug diff --git a/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs b/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs index 3de497b6..67c77379 100644 --- a/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs +++ b/test/Spring/Spring.Web.Tests/Web/Support/AbstractHandlerFactoryTests.cs @@ -25,6 +25,7 @@ using System.Web; using NUnit.Framework; using Rhino.Mocks; using Spring.Context; +using Spring.Objects.Factory.Config; using Spring.Objects.Factory.Support; #endregion