From ff4dac6ea9045b559badea6843438fffbf96005b Mon Sep 17 00:00:00 2001 From: sbohlen Date: Wed, 10 Nov 2010 01:16:59 +0000 Subject: [PATCH 01/11] initial port of lower-level classes --- .../Collections/Generic/DictionarySet.cs | 249 ++++++++ .../Collections/Generic/HashedSet.cs | 33 ++ .../Spring.Core/Collections/Generic/ISet.cs | 139 +++++ .../Collections/Generic/ImmutableSet.cs | 308 ++++++++++ .../Collections/Generic/OrderedSet.cs | 30 + .../Spring.Core/Collections/Generic/Set.cs | 561 ++++++++++++++++++ .../Collections/Generic/SortedSet.cs | 69 +++ .../Collections/Generic/SynchronizedSet.cs | 262 ++++++++ .../Annotation/ConfigurationAttribute.cs | 64 ++ .../Context/Annotation/ConfigurationClass.cs | 163 +++++ .../Annotation/ConfigurationClassMethod.cs | 122 ++++ ...onfigurationClassObjectDefinitionReader.cs | 219 +++++++ .../Annotation/ConfigurationClassParser.cs | 138 +++++ .../ConfigurationClassPostProcessor.cs | 90 +++ .../Context/Annotation/DefinitionAttribute.cs | 85 +++ .../Context/Annotation/DependsOnAttribute.cs | 45 ++ .../Context/Annotation/ImportAttribute.cs | 53 ++ .../Annotation/ImportResourceAttribute.cs | 59 ++ .../Context/Annotation/LazyAttrribute.cs | 53 ++ .../Context/Annotation/PrimaryAttribute.cs | 23 + .../Context/Annotation/ScopeAttribute.cs | 48 ++ .../Parsing/FailFastProblemReporter.cs | 36 ++ .../Objects/Factory/Parsing/Location.cs | 52 ++ .../ObjectDefinitionParsingException.cs | 23 + .../Objects/Factory/Parsing/Problem.cs | 78 +++ .../IObjectDefinitionRegistryPostProcessor.cs | 11 + .../Support/ObjectDefinitionReaderUtils.cs | 18 +- .../Objects/Factory/Support/ObjectScope.cs | 0 .../Spring.Core/Spring.Core.2010.csproj | 28 + src/Spring/Spring.Web/Spring.Web.2010.csproj | 1 - 30 files changed, 3055 insertions(+), 5 deletions(-) create mode 100644 src/Spring/Spring.Core/Collections/Generic/DictionarySet.cs create mode 100644 src/Spring/Spring.Core/Collections/Generic/HashedSet.cs create mode 100644 src/Spring/Spring.Core/Collections/Generic/ISet.cs create mode 100644 src/Spring/Spring.Core/Collections/Generic/ImmutableSet.cs create mode 100644 src/Spring/Spring.Core/Collections/Generic/OrderedSet.cs create mode 100644 src/Spring/Spring.Core/Collections/Generic/Set.cs create mode 100644 src/Spring/Spring.Core/Collections/Generic/SortedSet.cs create mode 100644 src/Spring/Spring.Core/Collections/Generic/SynchronizedSet.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/ConfigurationAttribute.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/ConfigurationClass.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/ConfigurationClassMethod.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/ConfigurationClassParser.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/DefinitionAttribute.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/DependsOnAttribute.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/ImportAttribute.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/ImportResourceAttribute.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/LazyAttrribute.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/PrimaryAttribute.cs create mode 100644 src/Spring/Spring.Core/Context/Annotation/ScopeAttribute.cs create mode 100644 src/Spring/Spring.Core/Objects/Factory/Parsing/FailFastProblemReporter.cs create mode 100644 src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs create mode 100644 src/Spring/Spring.Core/Objects/Factory/Parsing/ObjectDefinitionParsingException.cs create mode 100644 src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs create mode 100644 src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs rename src/Spring/{Spring.Web => Spring.Core}/Objects/Factory/Support/ObjectScope.cs (100%) diff --git a/src/Spring/Spring.Core/Collections/Generic/DictionarySet.cs b/src/Spring/Spring.Core/Collections/Generic/DictionarySet.cs new file mode 100644 index 00000000..d41228fb --- /dev/null +++ b/src/Spring/Spring.Core/Collections/Generic/DictionarySet.cs @@ -0,0 +1,249 @@ +/* Copyright © 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */ + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Spring.Collections.Generic +{ + /// + ///

DictionarySet is an abstract class that supports the creation of new Set + /// types where the underlying data store is an IDictionary instance.

+ /// + ///

You can use any object that implements the IDictionary 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 IDictionary you choose will affect both the performance and the behavior + /// of the Set using it.

+ /// + ///

To make a Set typed based on your own IDictionary, simply derive a + /// new class with a constructor that takes no parameters. Some Set 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 ICollection or + /// an ISet as an argument.

+ ///
+ [Serializable] + public abstract class DictionarySet : Set + { + /// + /// Provides the storage for elements in the Set, stored as the key-set + /// of the IDictionary object. Set this object in the constructor + /// if you create your own Set class. + /// + protected IDictionary InternalDictionary = null; + + private static readonly object PlaceholderObject = new object(); + + /// + /// The placeholder object used as the value for the IDictionary instance. + /// + /// + /// There is a single instance of this object globally, used for all Sets. + /// + protected object Placeholder + { + get { return PlaceholderObject; } + } + + + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The to add to the set. + /// is the object was added, if it was already present. + public override bool Add(T o) + { + if (InternalDictionary.ContainsKey(o)) + { + 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(o, 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, if not. + public override bool AddAll(ICollection c) + { + bool changed = false; + foreach (T o in c) + { + changed |= this.Add(o); + } + return changed; + } + + /// + /// Removes all objects from the 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, otherwise. + public override bool Contains(T o) + { + return InternalDictionary.ContainsKey(o); + } + + /// + /// 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, otherwise. + public override bool ContainsAll(ICollection c) + { + foreach (T o in c) + { + if (!this.Contains(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, otherwise. + public override bool Remove(T o) + { + bool contained = this.Contains(o); + if (contained) + { + InternalDictionary.Remove(o); + } + 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 c) + { + bool changed = false; + foreach (T o in c) + { + changed |= this.Remove(o); + } + return changed; + } + + /// + /// Retains only the elements in this set that are contained in the specified collection. + /// + /// 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 c) + { + //Put data from C into a set so we can use the Contains() method. + Set cSet = new HashedSet(c); + + //We are going to build a set of elements to remove. + Set removeSet = new HashedSet(); + + foreach (T 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 Set to an array of T. The type of array needs + /// to be compatible with the objects in the Set, obviously. + /// + /// An array that will be the target of the copy operation. + /// The zero-based index where copying will start. + public override void CopyTo(T[] array, int index) + { + InternalDictionary.Keys.CopyTo(array, index); + } + + /// + /// The number of elements contained in this collection. + /// + public override int Count + { + get { return InternalDictionary.Count; } + } + + /// + /// None of the objects based on DictionarySet are synchronized. Use the + /// SyncRoot property instead. + /// + public override bool IsSynchronized + { + get { return false; } + } + + /// + /// Returns an object that can be used to synchronize the Set between threads. + /// + public override object SyncRoot + { + get { return ((ICollection) InternalDictionary).SyncRoot; } + } + + /// + /// Gets an enumerator for the elements in the Set. + /// + /// An IEnumerator over the elements in the Set. + public override IEnumerator GetEnumerator() + { + return InternalDictionary.Keys.GetEnumerator(); + } + + /// + /// Indicates wether the Set is read-only or not + /// + public override bool IsReadOnly + { + get { return InternalDictionary.IsReadOnly; } + } + + /// + /// Copies the elements in the Set to an array. The type of array needs + /// to be compatible with the objects in the Set, obviously. Needed for + /// non-generic ISet methods implementation + /// + /// An array that will be the target of the copy operation. + /// The zero-based index where copying will start. + protected override void NonGenericCopyTo(Array array, int index) + { + ((ICollection) InternalDictionary.Keys).CopyTo(array, index); + } + } +} diff --git a/src/Spring/Spring.Core/Collections/Generic/HashedSet.cs b/src/Spring/Spring.Core/Collections/Generic/HashedSet.cs new file mode 100644 index 00000000..4cfcf694 --- /dev/null +++ b/src/Spring/Spring.Core/Collections/Generic/HashedSet.cs @@ -0,0 +1,33 @@ +/* Copyright © 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */ +using System; +using System.Collections.Generic; + +namespace Spring.Collections.Generic +{ + /// + /// Implements a Set based on a Dictionary (which is equivalent of + /// non-genric HashTable) This will give the best lookup, add, and remove + /// performance for very large data-sets, but iteration will occur in no particular order. + /// + [Serializable] + public class HashedSet : DictionarySet + { + /// + /// Creates a new set instance based on a Dictinary. + /// + public HashedSet() + { + InternalDictionary = new Dictionary(); + } + + /// + /// Creates a new set instance based on a Dictinary and + /// initializes it based on a collection of elements. + /// + /// A collection of elements that defines the initial set contents. + public HashedSet(ICollection initialValues) : this() + { + this.AddAll(initialValues); + } + } +} diff --git a/src/Spring/Spring.Core/Collections/Generic/ISet.cs b/src/Spring/Spring.Core/Collections/Generic/ISet.cs new file mode 100644 index 00000000..c2182a2c --- /dev/null +++ b/src/Spring/Spring.Core/Collections/Generic/ISet.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Spring.Collections.Generic +{ + /// + ///

A collection that contains no duplicate elements. This interface models the mathematical + /// Set abstraction. + /// The order of elements in a set is dependant on (a)the data-structure implementation, and + /// (b)the implementation of the various Set methods, and thus is not guaranteed.

+ /// + ///

None of the Set implementations in this library are guranteed to be thread-safe + /// in any way unless wrapped in a SynchronizedSet.

+ /// + ///

The following table summarizes the binary operators that are supported by the Set class.

+ /// + /// + /// Operation + /// Description + /// Method + /// + /// + /// Union (OR) + /// Element included in result if it exists in either A OR B. + /// Union() + /// + /// + /// Intersection (AND) + /// Element included in result if it exists in both A AND B. + /// InterSect() + /// + /// + /// Exclusive Or (XOR) + /// Element included in result if it exists in one, but not both, of A and B. + /// ExclusiveOr() + /// + /// + /// Minus (n/a) + /// Take all the elements in A. Now, if any of them exist in B, remove + /// them. Note that unlike the other operators, A - B is not the same as B - A. + /// Minus() + /// + /// + ///
+ public interface ISet : ICollection, IEnumerable, IEnumerable, ICloneable + { + // Clear is declared in ICollection, but not in ICollection + // void Clear(); + + // Remove is declared in ICollection, but not in ICollection + // bool Remove(T o); + + // Contains is declared in ICollection, but not in ICollection + // bool Contains(T o); + + /// + /// Performs a "union" of the two sets, where all the elements + /// in both sets are present. That is, the element is included if it is in either a or b. + /// Neither this set nor the input set are modified during the operation. The return value + /// is a Clone() of this set with the extra elements added in. + /// + /// A collection of elements. + /// A new Set containing the union of this Set with the specified collection. + /// Neither of the input objects is modified by the union. + ISet Union(ISet a); + + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. That is, the element is included if it exists in + /// both sets. The Intersect() operation does not modify the input sets. It returns + /// a Clone() of this set with the appropriate elements removed. + /// + /// A set of elements. + /// The intersection of this set with a. + ISet Intersect(ISet a); + + /// + /// Performs a "minus" of set b from set a. This returns a set of all + /// the elements in set a, removing the elements that are also in set b. + /// The original sets are not modified during this operation. The result set is a Clone() + /// of this Set containing the elements from the operation. + /// + /// A set of elements. + /// A set containing the elements from this set with the elements in a removed. + ISet Minus(ISet a); + + /// + /// Performs an "exclusive-or" of the two sets, keeping only the elements that + /// are in one of the sets, but not in both. The original sets are not modified + /// during this operation. The result set is a Clone() of this set containing + /// the elements from the exclusive-or operation. + /// + /// A set of elements. + /// A set containing the result of a ^ b. + ISet ExclusiveOr(ISet a); + + /// + /// 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, otherwise. + bool ContainsAll(ICollection c); + + /// + /// Returns if this set contains no elements. + /// + bool IsEmpty { get; } + + /// + /// 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 it was already present. + new bool Add(T o); + + /// + /// 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, if not. + bool AddAll(ICollection c); + + /// + /// 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. + bool RemoveAll(ICollection c); + + + /// + /// Retains only the elements in this set that are contained in the specified collection. + /// + /// Collection that defines the set of elements to be retained. + /// if this set changed as a result of this operation. + bool RetainAll(ICollection c); + } +} diff --git a/src/Spring/Spring.Core/Collections/Generic/ImmutableSet.cs b/src/Spring/Spring.Core/Collections/Generic/ImmutableSet.cs new file mode 100644 index 00000000..1f3fea0e --- /dev/null +++ b/src/Spring/Spring.Core/Collections/Generic/ImmutableSet.cs @@ -0,0 +1,308 @@ +/* Copyright © 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Spring.Collections.Generic +{ + /// + ///

Implements an immutable (read-only) Set wrapper.

+ ///

Although this is advertised as immutable, it really isn't. Anyone with access to the + /// basisSet can still change the data-set. So GetHashCode() is not implemented + /// for this Set, as is the case for all Set implementations in this library. + /// This design decision was based on the efficiency of not having to Clone() the + /// basisSet every time you wrap a mutable Set.

+ ///
+ [Serializable] + public sealed class ImmutableSet : Set + { + private const string ERROR_MESSAGE = "Object is immutable."; + private ISet mBasisSet; + + internal ISet BasisSet + { + get { return mBasisSet; } + } + + /// + /// Constructs an immutable (read-only) Set wrapper. + /// + /// The Set that is wrapped. + public ImmutableSet(ISet basisSet) + { + mBasisSet = basisSet; + } + + /// + /// Adds the specified element to this set if it is not already present. + /// + /// The object to add to the set. + /// nothing + /// is always thrown + public override sealed bool Add(T o) + { + throw new NotSupportedException(ERROR_MESSAGE); + } + + /// + /// 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. + /// nothing + /// is always thrown + public override sealed bool AddAll(ICollection c) + { + throw new NotSupportedException(ERROR_MESSAGE); + } + + /// + /// Removes all objects from the set. + /// + /// is always thrown + public override sealed void Clear() + { + throw new NotSupportedException(ERROR_MESSAGE); + } + + /// + /// Returns if this set contains the specified element. + /// + /// The element to look for. + /// if this set contains the specified element, otherwise. + public override sealed bool Contains(T o) + { + return mBasisSet.Contains(o); + } + + /// + /// 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, otherwise. + public override sealed bool ContainsAll(ICollection c) + { + return mBasisSet.ContainsAll(c); + } + + /// + /// Returns if this set contains no elements. + /// + public override sealed bool IsEmpty + { + get { return mBasisSet.IsEmpty; } + } + + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// nothing + /// is always thrown + public override sealed bool Remove(T o) + { + throw new NotSupportedException(ERROR_MESSAGE); + } + + /// + /// Remove all the specified elements from this set, if they exist in this set. + /// + /// A collection of elements to remove. + /// nothing + /// is always thrown + public override sealed bool RemoveAll(ICollection c) + { + throw new NotSupportedException(ERROR_MESSAGE); + } + + /// + /// Retains only the elements in this set that are contained in the specified collection. + /// + /// Collection that defines the set of elements to be retained. + /// nothing + /// is always thrown + public override sealed bool RetainAll(ICollection c) + { + throw new NotSupportedException(ERROR_MESSAGE); + } + + /// + /// Copies the elements in the Set to an array of T. The type of array needs + /// to be compatible with the objects in the Set, obviously. + /// + /// An array that will be the target of the copy operation. + /// The zero-based index where copying will start. + public override sealed void CopyTo(T[] array, int index) + { + mBasisSet.CopyTo(array, index); + } + + /// + /// The number of elements contained in this collection. + /// + public override sealed int Count + { + get { return mBasisSet.Count; } + } + + /// + /// Returns an object that can be used to synchronize use of the Set across threads. + /// + public override sealed bool IsSynchronized + { + get { return ((ICollection) mBasisSet).IsSynchronized; } + } + + /// + /// Returns an object that can be used to synchronize the Set between threads. + /// + public override sealed object SyncRoot + { + get { return ((ICollection) mBasisSet).SyncRoot; } + } + + /// + /// Gets an enumerator for the elements in the Set. + /// + /// An IEnumerator over the elements in the Set. + public override sealed IEnumerator GetEnumerator() + { + return mBasisSet.GetEnumerator(); + } + + /// + /// Returns a clone of the Set instance. + /// + /// A clone of this object. + public override sealed object Clone() + { + return new ImmutableSet(mBasisSet); + } + + /// + /// Performs a "union" of the two sets, where all the elements + /// in both sets are present. That is, the element is included if it is in either a or b. + /// Neither this set nor the input set are modified during the operation. The return value + /// is a Clone() of this set with the extra elements added in. + /// + /// A collection of elements. + /// A new Set containing the union of this Set with the specified collection. + /// Neither of the input objects is modified by the union. + public override sealed ISet Union(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(m.Union(a)); + } + + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. That is, the element is included if it exists in + /// both sets. The Intersect() operation does not modify the input sets. It returns + /// a Clone() of this set with the appropriate elements removed. + /// + /// A set of elements. + /// The intersection of this set with a. + public override sealed ISet Intersect(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(m.Intersect(a)); + } + + /// + /// Performs a "minus" of set b from set a. This returns a set of all + /// the elements in set a, removing the elements that are also in set b. + /// The original sets are not modified during this operation. The result set is a Clone() + /// of this Set containing the elements from the operation. + /// + /// A set of elements. + /// A set containing the elements from this set with the elements in a removed. + public override sealed ISet Minus(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(m.Minus(a)); + } + + /// + /// Performs an "exclusive-or" of the two sets, keeping only the elements that + /// are in one of the sets, but not in both. The original sets are not modified + /// during this operation. The result set is a Clone() of this set containing + /// the elements from the exclusive-or operation. + /// + /// A set of elements. + /// A set containing the result of a ^ b. + public override sealed ISet ExclusiveOr(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(m.ExclusiveOr(a)); + } + + /// + /// Indicates that the given instance is read-only + /// + public override sealed bool IsReadOnly + { + get { return true; } + } + + /// + /// Performs CopyTo when called trhough non-generic ISet (ICollection) interface + /// + /// + /// + protected override void NonGenericCopyTo(Array array, int index) + { + ((ICollection) this.BasisSet).CopyTo(array, index); + } + + /// + /// Performs Union when called trhough non-generic ISet interface + /// + /// + /// + protected override sealed ISet NonGenericUnion(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(((ISet) m).Union(a)); + } + + /// + /// Performs Minus when called trhough non-generic ISet interface + /// + /// + /// + protected override sealed ISet NonGenericMinus(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(((ISet) m).Minus(a)); + } + + /// + /// Performs Intersect when called trhough non-generic ISet interface + /// + /// + /// + protected override sealed ISet NonGenericIntersect(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(((ISet) m).Intersect(a)); + } + + /// + /// Performs ExclusiveOr when called trhough non-generic ISet interface + /// + /// + /// + protected override sealed ISet NonGenericExclusiveOr(ISet a) + { + ISet m = GetUltimateBasisSet(); + return new ImmutableSet(((ISet) m).ExclusiveOr(a)); + } + + private ISet GetUltimateBasisSet() + { + ISet m = this.mBasisSet; + while (m is ImmutableSet) + m = ((ImmutableSet) m).mBasisSet; + return m; + } + } +} diff --git a/src/Spring/Spring.Core/Collections/Generic/OrderedSet.cs b/src/Spring/Spring.Core/Collections/Generic/OrderedSet.cs new file mode 100644 index 00000000..30107594 --- /dev/null +++ b/src/Spring/Spring.Core/Collections/Generic/OrderedSet.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; + +namespace Spring.Collections.Generic +{ + /// + /// Implements an ordered Set based on a dictionary. + /// + [Serializable] + public class OrderedSet : DictionarySet + { + /// + /// Initializes a new instance of the class. + /// + public OrderedSet() + { + InternalDictionary = new Dictionary(); + } + + /// + /// Initializes a new instance of the class. + /// + /// A collection of elements that defines the initial set contents. + public OrderedSet(ICollection initialValues) + : this() + { + AddAll(initialValues); + } + } +} diff --git a/src/Spring/Spring.Core/Collections/Generic/Set.cs b/src/Spring/Spring.Core/Collections/Generic/Set.cs new file mode 100644 index 00000000..84a3ea8c --- /dev/null +++ b/src/Spring/Spring.Core/Collections/Generic/Set.cs @@ -0,0 +1,561 @@ +/* Copyright © 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Spring.Collections.Generic +{ + ///

A collection that contains no duplicate elements. This class models the mathematical + /// Set abstraction, and is the base class for all other Set implementations. + /// The order of elements in a set is dependant on (a)the data-structure implementation, and + /// (b)the implementation of the various Set methods, and thus is not guaranteed.

+ /// + ///

None of the Set implementations in this library are guranteed to be thread-safe + /// in any way unless wrapped in a SynchronizedSet.

+ /// + ///

The following table summarizes the binary operators that are supported by the Set class.

+ /// + /// + /// Operation + /// Description + /// Method + /// Operator + /// + /// + /// Union (OR) + /// Element included in result if it exists in either A OR B. + /// Union() + /// | + /// + /// + /// Intersection (AND) + /// Element included in result if it exists in both A AND B. + /// InterSect() + /// & + /// + /// + /// Exclusive Or (XOR) + /// Element included in result if it exists in one, but not both, of A and B. + /// ExclusiveOr() + /// ^ + /// + /// + /// Minus (n/a) + /// Take all the elements in A. Now, if any of them exist in B, remove + /// them. Note that unlike the other operators, A - B is not the same as B - A. + /// Minus() + /// - + /// + /// + ///
+ [Serializable] + public abstract class Set : ISet, ICollection, IEnumerable, + ISet, ICollection, IEnumerable, ICloneable + { + /// + /// Performs a "union" of the two sets, where all the elements + /// in both sets are present. That is, the element is included if it is in either a or b. + /// Neither this set nor the input set are modified during the operation. The return value + /// is a Clone() of this set with the extra elements added in. + /// + /// A collection of elements. + /// A new Set containing the union of this Set with the specified collection. + /// Neither of the input objects is modified by the union. + public virtual ISet Union(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + { + resultSet.AddAll(a); + } + return resultSet; + } + + /// + /// Performs a "union" of two sets, where all the elements + /// in both are present. That is, the element is included if it is in either a or b. + /// The return value is a Clone() of one of the sets (a if it is not ) with elements of the other set + /// added in. Neither of the input sets is modified by the operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing the union of the input sets. if both sets are . + public static ISet Union(ISet a, ISet b) + { + if (a == null && b == null) + return null; + else if (a == null) + return (ISet) b.Clone(); + else if (b == null) + return (ISet) a.Clone(); + else + return a.Union(b); + } + + /// + /// Performs a "union" of two sets, where all the elements + /// in both are present. That is, the element is included if it is in either a or b. + /// The return value is a Clone() of one of the sets (a if it is not ) with elements of the other set + /// added in. Neither of the input sets is modified by the operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing the union of the input sets. if both sets are . + public static Set operator |(Set a, Set b) + { + return (Set) Union(a, b); + } + + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. That is, the element is included if it exists in + /// both sets. The Intersect() operation does not modify the input sets. It returns + /// a Clone() of this set with the appropriate elements removed. + /// + /// A set of elements. + /// The intersection of this set with a. + public virtual ISet Intersect(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + resultSet.RetainAll(a); + else + resultSet.Clear(); + return resultSet; + } + + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. That is, the element is included only if it exists in + /// both a and b. Neither input object is modified by the operation. + /// The result object is a Clone() of one of the input objects (a if it is not ) containing the + /// elements from the intersect operation. + /// + /// A set of elements. + /// A set of elements. + /// The intersection of the two input sets. if both sets are . + public static ISet Intersect(ISet a, ISet b) + { + if (a == null && b == null) + return null; + else if (a == null) + { + return b.Intersect(a); + } + else + return a.Intersect(b); + } + + /// + /// Performs an "intersection" of the two sets, where only the elements + /// that are present in both sets remain. That is, the element is included only if it exists in + /// both a and b. Neither input object is modified by the operation. + /// The result object is a Clone() of one of the input objects (a if it is not ) containing the + /// elements from the intersect operation. + /// + /// A set of elements. + /// A set of elements. + /// The intersection of the two input sets. if both sets are . + public static Set operator &(Set a, Set b) + { + return (Set) Intersect(a, b); + } + + /// + /// Performs a "minus" of set b from set a. This returns a set of all + /// the elements in set a, removing the elements that are also in set b. + /// The original sets are not modified during this operation. The result set is a Clone() + /// of this Set containing the elements from the operation. + /// + /// A set of elements. + /// A set containing the elements from this set with the elements in a removed. + public virtual ISet Minus(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + resultSet.RemoveAll(a); + return resultSet; + } + + /// + /// Performs a "minus" of set b from set a. This returns a set of all + /// the elements in set a, removing the elements that are also in set b. + /// The original sets are not modified during this operation. The result set is a Clone() + /// of set a containing the elements from the operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing A - B elements. if a is . + public static ISet Minus(ISet a, ISet b) + { + if (a == null) + return null; + else + return a.Minus(b); + } + + /// + /// Performs a "minus" of set b from set a. This returns a set of all + /// the elements in set a, removing the elements that are also in set b. + /// The original sets are not modified during this operation. The result set is a Clone() + /// of set a containing the elements from the operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing A - B elements. if a is . + public static Set operator -(Set a, Set b) + { + return (Set) Minus(a, b); + } + + + /// + /// Performs an "exclusive-or" of the two sets, keeping only the elements that + /// are in one of the sets, but not in both. The original sets are not modified + /// during this operation. The result set is a Clone() of this set containing + /// the elements from the exclusive-or operation. + /// + /// A set of elements. + /// A set containing the result of a ^ b. + public virtual ISet ExclusiveOr(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + foreach (T element in a) + { + if (resultSet.Contains(element)) + resultSet.Remove(element); + else + resultSet.Add(element); + } + return resultSet; + } + + /// + /// Performs an "exclusive-or" of the two sets, keeping only the elements that + /// are in one of the sets, but not in both. The original sets are not modified + /// during this operation. The result set is a Clone() of one of the sets + /// (a if it is not ) containing + /// the elements from the exclusive-or operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing the result of a ^ b. if both sets are . + public static ISet ExclusiveOr(ISet a, ISet b) + { + if (a == null && b == null) + return null; + else if (a == null) + return (ISet) b.Clone(); + else if (b == null) + return (ISet) a.Clone(); + else + return a.ExclusiveOr(b); + } + + /// + /// Performs an "exclusive-or" of the two sets, keeping only the elements that + /// are in one of the sets, but not in both. The original sets are not modified + /// during this operation. The result set is a Clone() of one of the sets + /// (a if it is not ) containing + /// the elements from the exclusive-or operation. + /// + /// A set of elements. + /// A set of elements. + /// A set containing the result of a ^ b. if both sets are . + public static Set operator ^(Set a, Set b) + { + return (Set) ExclusiveOr(a, b); + } + + /// + /// 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 it was already present. + public abstract bool Add(T o); + + /// + /// 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, if not. + public abstract bool AddAll(ICollection c); + + /// + /// Removes all objects from the set. + /// + public abstract void Clear(); + + /// + /// Returns if this set contains the specified element. + /// + /// The element to look for. + /// if this set contains the specified element, otherwise. + public abstract bool Contains(T o); + + /// + /// 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, otherwise. + public abstract bool ContainsAll(ICollection c); + + /// + /// Returns if this set contains no elements. + /// + public abstract bool IsEmpty { get; } + + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// if the set contained the specified element, otherwise. + public abstract bool Remove(T o); + + /// + /// 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 abstract bool RemoveAll(ICollection c); + + + /// + /// Retains only the elements in this set that are contained in the specified collection. + /// + /// Collection that defines the set of elements to be retained. + /// if this set changed as a result of this operation. + public abstract bool RetainAll(ICollection c); + + /// + /// Returns a clone of the Set instance. This will work for derived Set + /// classes if the derived class implements a constructor that takes no arguments. + /// + /// A clone of this object. + public virtual object Clone() + { + Set newSet = (Set) Activator.CreateInstance(this.GetType()); + newSet.AddAll(this); + return newSet; + } + + + /// + /// Copies the elements in the Set to an array. The type of array needs + /// to be compatible with the objects in the Set, obviously. + /// + /// An array that will be the target of the copy operation. + /// The zero-based index where copying will start. + public abstract void CopyTo(T[] array, int index); + + /// + /// The number of elements currently contained in this collection. + /// + public abstract int Count { get; } + + /// + /// Returns if the Set is synchronized across threads. Note that + /// enumeration is inherently not thread-safe. Use the SyncRoot to lock the + /// object during enumeration. + /// + public abstract bool IsSynchronized { get; } + + /// + /// An object that can be used to synchronize this collection to make it thread-safe. + /// When implementing this, if your object uses a base object, like an IDictionary, + /// or anything that has a SyncRoot, return that object instead of "this". + /// + public abstract object SyncRoot { get; } + + /// + /// Gets an enumerator for the elements in the Set. + /// + /// An IEnumerator over the elements in the Set. + public abstract IEnumerator GetEnumerator(); + + /// + /// Indicates whether the given instance is read-only or not + /// + /// + /// if the ISet is read-only; otherwise, . + /// In the default implementation of Set, this property always returns false. + /// + public virtual bool IsReadOnly + { + get { return false; } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + void ICollection.Add(T item) + { + this.Add(item); + } + + #region Protected helpers + + /// + /// Performs CopyTo when called trhough non-generic ISet (ICollection) interface + /// + /// + /// + protected abstract void NonGenericCopyTo(Array array, int index); + + /// + /// Performs Union when called trhough non-generic ISet interface + /// + /// + /// + protected virtual ISet NonGenericUnion(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + resultSet.AddAll(a); + return resultSet; + } + + /// + /// Performs Minus when called trhough non-generic ISet interface + /// + /// + /// + protected virtual ISet NonGenericMinus(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + resultSet.RemoveAll(a); + return resultSet; + } + + /// + /// Performs Intersect when called trhough non-generic ISet interface + /// + /// + /// + protected virtual ISet NonGenericIntersect(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + if (a != null) + resultSet.RetainAll(a); + else + resultSet.Clear(); + return resultSet; + } + + /// + /// Performs ExclusiveOr when called trhough non-generic ISet interface + /// + /// + /// + protected virtual ISet NonGenericExclusiveOr(ISet a) + { + ISet resultSet = (ISet) this.Clone(); + foreach (object element in a) + { + if (resultSet.Contains(element)) + resultSet.Remove(element); + else + resultSet.Add(element); + } + return resultSet; + } + + #endregion Protected helpers + + #region ISet implementation + + void ICollection.CopyTo(Array array, int index) + { + this.NonGenericCopyTo(array, index); + } + + ISet ISet.Union(ISet a) + { + return this.NonGenericUnion(a); + } + + ISet ISet.Intersect(ISet a) + { + return NonGenericIntersect(a); + } + + ISet ISet.Minus(ISet a) + { + return NonGenericMinus(a); + } + + ISet ISet.ExclusiveOr(ISet a) + { + return NonGenericExclusiveOr(a); + } + + bool ISet.Contains(object o) + { + if (o is T) + return this.Contains((T) o); + else + return false; + } + + bool ISet.ContainsAll(ICollection c) + { + ICollection col = new List(c.Count); + foreach (object o in c) + { + if (o is T) + col.Add((T) o); + else + return false; + } + return this.ContainsAll(col); + } + + bool ISet.Add(object o) + { + return this.Add((T) o); + } + + bool ISet.AddAll(ICollection c) + { + bool changed = false; + foreach (T obj in c) + changed |= this.Add(obj); + return changed; + } + + bool ISet.Remove(object o) + { + if (o is T) + return this.Remove((T) o); + else + return false; + } + + bool ISet.RemoveAll(ICollection c) + { + ICollection col = new List(c.Count); + foreach (object o in c) + { + if (o is T) + col.Add((T) o); + } + return this.RemoveAll(col); + } + + bool ISet.RetainAll(ICollection c) + { + ICollection col = new List(c.Count); + foreach (object o in c) + { + if (o is T) + col.Add((T) o); + } + return this.RetainAll(col); + } + + #endregion ISet implementation + } +} diff --git a/src/Spring/Spring.Core/Collections/Generic/SortedSet.cs b/src/Spring/Spring.Core/Collections/Generic/SortedSet.cs new file mode 100644 index 00000000..6e3c20c6 --- /dev/null +++ b/src/Spring/Spring.Core/Collections/Generic/SortedSet.cs @@ -0,0 +1,69 @@ +/* Copyright © 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Spring.Collections.Generic +{ + /// + /// Implements a Set based on a sorted tree. This gives good performance for operations on very + /// large data-sets, though not as good - asymptotically - as a HashedSet. However, iteration + /// occurs in order. Elements that you put into this type of collection must implement IComparable, + /// and they must actually be comparable. You can't mix string and int values, for example. + /// + [Serializable] + public class SortedSet : DictionarySet + { + /// + /// Creates a new set instance based on a sorted tree. + /// + public SortedSet() + { + InternalDictionary = new SortedDictionary(); + } + + /// + /// Creates a new set instance based on a sorted tree. + /// + /// The to use for sorting. + public SortedSet(IComparer 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); + } + + + /// + /// 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() + { + ((ISet) this).AddAll(initialValues); + } + + /// + /// 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. + /// The to use for sorting. + public SortedSet(ICollection initialValues, IComparer comparer) + : this(comparer) + { + this.AddAll(initialValues); + } + } +} diff --git a/src/Spring/Spring.Core/Collections/Generic/SynchronizedSet.cs b/src/Spring/Spring.Core/Collections/Generic/SynchronizedSet.cs new file mode 100644 index 00000000..ee6c77cd --- /dev/null +++ b/src/Spring/Spring.Core/Collections/Generic/SynchronizedSet.cs @@ -0,0 +1,262 @@ +/* Copyright © 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Spring.Collections.Generic +{ + /// + ///

Implements a thread-safe Set wrapper. The implementation is extremely conservative, + /// serializing critical sections to prevent possible deadlocks, and locking on everything. + /// The one exception is for enumeration, which is inherently not thread-safe. For this, you + /// have to lock the SyncRoot object for the duration of the enumeration.

+ ///
+ [Serializable] + public sealed class SynchronizedSet : Set + { + private ISet mBasisSet; + private object mSyncRoot; + + /// + /// Constructs a thread-safe Set wrapper. + /// + /// The Set object that this object will wrap. + public SynchronizedSet(ISet basisSet) + { + mBasisSet = basisSet; + mSyncRoot = ((ICollection) basisSet).SyncRoot; + if (mSyncRoot == null) + throw new NullReferenceException("The Set you specified returned a null SyncRoot."); + } + + /// + /// 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 it was already present. + public override sealed bool Add(T o) + { + lock (mSyncRoot) + { + return mBasisSet.Add(o); + } + } + + /// + /// 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, if not. + public override sealed bool AddAll(ICollection c) + { + Set temp; + lock (((ICollection) c).SyncRoot) + { + temp = new HashedSet(c); + } + + lock (mSyncRoot) + { + return mBasisSet.AddAll(temp); + } + } + + /// + /// Removes all objects from the set. + /// + public override sealed void Clear() + { + lock (mSyncRoot) + { + mBasisSet.Clear(); + } + } + + /// + /// Returns if this set contains the specified element. + /// + /// The element to look for. + /// if this set contains the specified element, otherwise. + public override sealed bool Contains(T o) + { + lock (mSyncRoot) + { + return mBasisSet.Contains(o); + } + } + + /// + /// 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, otherwise. + public override sealed bool ContainsAll(ICollection c) + { + Set temp; + lock (((ICollection) c).SyncRoot) + { + temp = new HashedSet(c); + } + lock (mSyncRoot) + { + return mBasisSet.ContainsAll(temp); + } + } + + /// + /// Returns if this set contains no elements. + /// + public override sealed bool IsEmpty + { + get + { + lock (mSyncRoot) + { + return mBasisSet.IsEmpty; + } + } + } + + + /// + /// Removes the specified element from the set. + /// + /// The element to be removed. + /// if the set contained the specified element, otherwise. + public override sealed bool Remove(T o) + { + lock (mSyncRoot) + { + return mBasisSet.Remove(o); + } + } + + /// + /// 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 sealed bool RemoveAll(ICollection c) + { + Set temp; + lock (((ICollection) c).SyncRoot) + { + temp = new HashedSet(c); + } + lock (mSyncRoot) + { + return mBasisSet.RemoveAll(temp); + } + } + + /// + /// Retains only the elements in this set that are contained in the specified collection. + /// + /// Collection that defines the set of elements to be retained. + /// if this set changed as a result of this operation. + public override sealed bool RetainAll(ICollection c) + { + Set temp; + lock (((ICollection) c).SyncRoot) + { + temp = new HashedSet(c); + } + lock (mSyncRoot) + { + return mBasisSet.RetainAll(temp); + } + } + + /// + /// Copies the elements in the Set to an array. The type of array needs + /// to be compatible with the objects in the Set, obviously. + /// + /// An array that will be the target of the copy operation. + /// The zero-based index where copying will start. + public override sealed void CopyTo(T[] array, int index) + { + lock (mSyncRoot) + { + mBasisSet.CopyTo(array, index); + } + } + + /// + /// The number of elements contained in this collection. + /// + public override sealed int Count + { + get + { + lock (mSyncRoot) + { + return mBasisSet.Count; + } + } + } + + /// + /// Returns , indicating that this object is thread-safe. The exception to this + /// is enumeration, which is inherently not thread-safe. Use the SyncRoot object to + /// lock this object for the entire duration of the enumeration. + /// + public override sealed bool IsSynchronized + { + get { return true; } + } + + /// + /// Returns an object that can be used to synchronize the Set between threads. + /// + public override sealed object SyncRoot + { + get { return mSyncRoot; } + } + + /// + /// Enumeration is, by definition, not thread-safe. Use a lock on the SyncRoot + /// to synchronize the entire enumeration process. + /// + /// + public override sealed IEnumerator GetEnumerator() + { + return mBasisSet.GetEnumerator(); + } + + /// + /// Returns a clone of the Set instance. + /// + /// A clone of this object. + public override object Clone() + { + return new SynchronizedSet((ISet) mBasisSet.Clone()); + } + + /// + /// Indicates whether given instace is read-only or not + /// + public override bool IsReadOnly + { + get + { + lock (mSyncRoot) + { + return mBasisSet.IsReadOnly; + } + } + } + + /// + /// Performs CopyTo when called trhough non-generic ISet (ICollection) interface + /// + /// + /// + protected override void NonGenericCopyTo(Array array, int index) + { + lock (mSyncRoot) + { + ((ICollection) this.mBasisSet).CopyTo(array, index); + } + } + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationAttribute.cs b/src/Spring/Spring.Core/Context/Annotation/ConfigurationAttribute.cs new file mode 100644 index 00000000..9b00778a --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/ConfigurationAttribute.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Spring.Context.Annotation +{ + /// + /// Indicates that a class declares one or more methods and may be processed + /// by the Spring container to generate object definitions and service requests for those objects + /// at runtime. + /// + /// Configuration is meta-annotated as a {@link Component}, therefore Configuration + /// classes are candidates for component-scanning and may also take advantage of + /// at the field and method but not at the constructor level. + /// + /// May be used in conjunction with the attribute to indicate that all object + /// methods declared within this class are by default lazily initialized. + /// + ///

Constraints

+ ///
    + ///
  • Configuration classes must be non-final
  • + ///
  • Configuration classes must be non-local (may not be declared within a method)
  • + ///
  • Configuration classes must have a default/no-arg constructor and may not use + /// {@link Autowired} constructor parameters
  • + ///
+ ///
+ [AttributeUsage(AttributeTargets.Class)] + public class ConfigurationAttribute : Attribute + { + private string _name; + + /// + /// Initializes a new instance of the Configuration class. + /// + /// + public ConfigurationAttribute(string name) + { + _name = name; + } + + /// + /// Explicitly specify the name of the Spring object definition associated + /// with this Configuration class. If left unspecified (the common case), + /// a object name will be automatically generated. + /// + /// The custom name applies only if the Configuration class is picked up via + /// component scanning or supplied directly to a . + /// If the Configuration class is registered as a traditional XML object definition, + /// the name/id of the object element will take precedence. + /// + /// + /// + /// The name. + public string Name + { + get { return _name; } + set + { + _name = value; + } + } + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClass.cs b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClass.cs new file mode 100644 index 00000000..53a594e7 --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClass.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spring.Core.IO; +using Spring.Collections.Generic; +using Spring.Objects.Factory.Parsing; + +namespace Spring.Context.Annotation +{ + public class ConfigurationClass + { + private Type _configurationClassType; + + private IDictionary _importedResources = new Dictionary(); + + private ISet _methods = new HashedSet(); + + private string _objectName; + + private IResource _resource; + + /// + /// Initializes a new instance of the ConfigurationClass class. + /// + /// + /// + public ConfigurationClass(string objectName, Type type) + { + this._objectName = objectName; + this._configurationClassType = type; + } + + public Type ConfigurationClassType + { + get + { + return _configurationClassType; + } + } + + public IDictionary ImportedResources + { + get + { + return _importedResources; + } + } + + public ISet Methods + { + get + { + return _methods; + } + } + + public string ObjectName + { + get + { + return _objectName; + } + set + { + _objectName = value; + } + } + + public IResource Resource + { + get + { + return _resource; + } + } + + public string SimpleName + { + get { return ConfigurationClassType.Name; } + } + + public void AddImportedResource(string importedResource, Type readerClass) + { + _importedResources.Add(importedResource, readerClass); + } + + public override bool Equals(object other) + { + return this == other || (other is ConfigurationClass && ConfigurationClassType.Name.Equals(((ConfigurationClass)other).ConfigurationClassType.Name)); + } + + public override int GetHashCode() + { + return ConfigurationClassType.Name.GetHashCode() * 14; + } + + public void Validate(IProblemReporter problemReporter) + { + // An @Bean method may only be overloaded through inheritance. No single + // @Configuration class may declare two @Bean methods with the same name. + char hashDelim = '#'; + Dictionary methodNameCounts = new Dictionary(); + foreach (ConfigurationClassMethod method in _methods) + { + String dClassName = method.MethodMetadata.DeclaringType.FullName; + String methodName = method.MethodMetadata.Name; + String fqMethodName = dClassName + hashDelim + methodName; + if (!methodNameCounts.ContainsKey(fqMethodName)) + { + methodNameCounts.Add(fqMethodName, 1); + } + else + { + int currentCount = methodNameCounts[fqMethodName]; + methodNameCounts.Add(fqMethodName, currentCount++); + } + } + + foreach (String methodName in methodNameCounts.Keys) + { + int count = methodNameCounts[methodName]; + if (count > 1) + { + String shortMethodName = methodName.Substring(methodName.IndexOf(hashDelim) + 1); + problemReporter.Error(new ObjectMethodOverloadingProblem(shortMethodName, count, Resource, ConfigurationClassType)); + } + } + + if (Attribute.GetCustomAttribute(_configurationClassType, typeof(ConfigurationAttribute)) != null) + { + + if (ConfigurationClassType.IsSealed) + { + problemReporter.Error(new SealedConfigurationProblem(SimpleName, Resource, ConfigurationClassType)); + + } + + foreach (ConfigurationClassMethod method in _methods) + { + method.Validate(problemReporter); + } + } + } + + private class SealedConfigurationProblem : Problem + { + public SealedConfigurationProblem(string name, IResource resource, Type configurationClassType) + : base(String.Format("[Configuration] class '{0}' may not be sealed. Remove the sealed modifier to continue.", name), new Location(resource, configurationClassType)) + { } + + } + + private class ObjectMethodOverloadingProblem : Problem + { + public ObjectMethodOverloadingProblem(string methodName, int count, IResource resource, Type configurationClassType) + : base(String.Format("[Configuration] class '{0}' has {1} overloaded [Definiton] methods named '{2}'. " + + "Only one [Definition] method of a given name is allowed within each [Configuration] class.", configurationClassType.Name, count, methodName), new Location(resource, configurationClassType)) + { } + + } + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassMethod.cs b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassMethod.cs new file mode 100644 index 00000000..91fbe3fd --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassMethod.cs @@ -0,0 +1,122 @@ +#region License + +/* + * Copyright © 2002-2010 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.Generic; +using System; +using System.Text; +using Spring.Core.IO; +using System.Reflection; +using Spring.Objects.Factory.Parsing; + +namespace Spring.Context.Annotation +{ + + /** + * Represents a {@link Configuration} class method marked with the {@link Bean} annotation. + * + * @author Chris Beams + * @author Juergen Hoeller + * @since 3.0 + * @see ConfigurationClass + * @see ConfigurationClassParser + * @see ConfigurationClassBeanDefinitionReader + */ + + public class ConfigurationClassMethod + { + private ConfigurationClass _configurationClass; + + private MethodInfo _methodInfo; + + /// + /// Initializes a new instance of the ConfigurationClassMethod class. + /// + /// + /// + public ConfigurationClassMethod(MethodInfo methodInfo, ConfigurationClass configurationClass) + { + _methodInfo = methodInfo; + _configurationClass = configurationClass; + } + + public ConfigurationClass ConfigurationClass + { + get + { + return _configurationClass; + } + } + + public MethodInfo MethodMetadata + { + get + { + return _methodInfo; + } + } + + public Location ResourceLocation + { + get { return new Location(_configurationClass.Resource, _methodInfo); } + + } + + public override string ToString() + { + return string.Format("{0}:name={1},declaringClass={2}", this.GetType().Name, _methodInfo.Name, _methodInfo.DeclaringType.FullName); + } + + public void Validate(IProblemReporter problemReporter) + { + if (Attribute.GetCustomAttribute(ConfigurationClass.GetType(), typeof(ConfigurationAttribute)) != null) + { + if (!MethodMetadata.IsVirtual) + { + problemReporter.Error(new NonVirtualMethodError(MethodMetadata.Name, ResourceLocation)); + } + } + + else + { + if (MethodMetadata.IsStatic) + { + problemReporter.Error(new StaticMethodError(MethodMetadata.Name, ResourceLocation)); + } + } + } + + private class StaticMethodError : Problem + { + public StaticMethodError(string methodName, Location location) + : base(String.Format("Method '{0}' must not be static; remove the method's static modifier to continue", + methodName), location) + { } + } + + private class NonVirtualMethodError : Problem + { + public NonVirtualMethodError(string methodName, Location location) + : base(String.Format("Method '{0}' must not be private, final or static; change the method's modifiers to continue", + methodName), location) + { } + } + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs new file mode 100644 index 00000000..276b54ad --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spring.Objects.Factory.Support; +using Spring.Objects.Factory.Parsing; +using Spring.Collections.Generic; +using System.Reflection; +using Spring.Objects.Factory.Config; +using Common.Logging; + +namespace Spring.Context.Annotation +{ + public class ConfigurationClassObjectDefinitionReader + { + private readonly ILog _logger = LogManager.GetLogger(typeof(ConfigurationClassObjectDefinitionReader)); + + private IProblemReporter _problemReporter; + + private IObjectDefinitionRegistry _registry; + + /// + /// Initializes a new instance of the ConfigurationClassObjectDefinitionReader class. + /// + /// + /// + public ConfigurationClassObjectDefinitionReader(IObjectDefinitionRegistry registry, IProblemReporter problemReporter) + { + _registry = registry; + _problemReporter = problemReporter; + } + + public static bool CheckConfigurationClassCandidate(Type type) + { + if (type != null) + { + return (Attribute.GetCustomAttribute(type.GetType(), typeof(ConfigurationAttribute)) != null); + } + + return false; + } + + public void LoadBeanDefinitions(ISet configurationModel) + { + foreach (ConfigurationClass configClass in configurationModel) + { + LoadBeanDefinitionsForConfigurationClass(configClass); + } + } + + private void LoadBeanDefinitionForConfigurationClassIfNecessary(ConfigurationClass configClass) + { + if (configClass.ObjectName != null) + { + // a bean definition already exists for this configuration class -> nothing to do + return; + } + + // no bean definition exists yet -> this must be an imported configuration class (@Import). + GenericObjectDefinition configBeanDef = new GenericObjectDefinition(); + String className = configClass.ConfigurationClassType.Name; + configBeanDef.ObjectTypeName = className; + if (CheckConfigurationClassCandidate(configClass.ConfigurationClassType)) + { + String configObjectName = ObjectDefinitionReaderUtils.RegisterWithGeneratedName(configBeanDef, _registry); + configClass.ObjectName = configObjectName; + if (_logger.IsDebugEnabled) + { + _logger.Debug(String.Format("Registered bean definition for imported [Configuration] class {0}", configObjectName)); + } + } + } + + private void LoadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass) + { + LoadBeanDefinitionForConfigurationClassIfNecessary(configClass); + + foreach (ConfigurationClassMethod method in configClass.Methods) + { + LoadBeanDefinitionsForModelMethod(method); + } + + LoadBeanDefinitionsFromImportedResources(configClass.ImportedResources); + } + + private void LoadBeanDefinitionsForModelMethod(ConfigurationClassMethod method) + { + ConfigurationClass configClass = method.ConfigurationClass; + MethodInfo metadata = method.MethodMetadata; + + RootObjectDefinition beanDef = new ConfigurationClassObjectDefinition(); + //beanDef.Resource = configClass.Resource; + //beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource())); + beanDef.FactoryObjectName = configClass.ObjectName; + beanDef.FactoryMethodName = metadata.Name; + beanDef.AutowireMode = Objects.Factory.Config.AutoWiringMode.Constructor; + //beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE); + + // consider name and any aliases + //Dictionary beanAttributes = metadata.getAnnotationAttributes(Bean.class.getName()); + object[] objectAttributes = metadata.GetCustomAttributes(typeof(DefinitionAttribute), true); + List names = new List(); + for (int i = 0; i < objectAttributes.Length; i++) + { + string[] namesAndAliases = ((DefinitionAttribute)objectAttributes[i]).Name; + for (int j = 0; j > namesAndAliases.Length; j++) + { + names.Add(namesAndAliases[j]); + } + + } + + string beanName = (names.Count > 0 ? names[0] : method.MethodMetadata.Name); + for (int i = 1; i < names.Count; i++) + { + _registry.RegisterAlias(beanName, names[i]); + } + + // has this already been overridden (e.g. via XML)? + if (_registry.ContainsObjectDefinition(beanName)) + { + IObjectDefinition existingBeanDef = _registry.GetObjectDefinition(beanName); + // is the existing bean definition one that was created from a configuration class? + if (!(existingBeanDef is ConfigurationClassObjectDefinition)) + { + // no -> then it's an external override, probably XML + // overriding is legal, return immediately + if (_logger.IsDebugEnabled) + { + _logger.Debug(String.Format("Skipping loading bean definition for {0}: a definition for object " + + "'{1}' already exists. This is likely due to an override in XML.", method, beanName)); + } + return; + } + } + + if (Attribute.GetCustomAttribute(metadata, typeof(PrimaryAttribute)) != null) + { + //TODO: determine how to respond to this attribute's presence + //beanDef.isPrimary = true; + } + + // is this bean to be instantiated lazily? + if (Attribute.GetCustomAttribute(metadata, typeof(LazyAttrribute)) != null) + { + beanDef.IsLazyInit = (Attribute.GetCustomAttribute(metadata, typeof(LazyAttrribute)) as LazyAttrribute).LazyInitialize; + } + + if (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) != null) + { + DependsOnAttribute attrib = Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) as DependsOnAttribute; + beanDef.DependsOn = (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) as DependsOnAttribute).Name; + } + + //Autowire autowire = (Autowire) beanAttributes.get("autowire"); + //if (autowire.isAutowire()) { + // beanDef.setAutowireMode(autowire.value()); + //} + + //String initMethodName = (String) beanAttributes.get("initMethod"); + //if (StringUtils.hasText(initMethodName)) { + // beanDef.setInitMethodName(initMethodName); + //} + + //String destroyMethodName = (String) beanAttributes.get("destroyMethod"); + //if (StringUtils.hasText(destroyMethodName)) { + // beanDef.setDestroyMethodName(destroyMethodName); + //} + + // consider scoping + if (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) != null) + { + ScopeAttribute attrib = Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) as ScopeAttribute; + beanDef.Scope = (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) as ScopeAttribute).ObjectScope.ToString(); + } + + if (_logger.IsDebugEnabled) + { + _logger.Debug(String.Format("Registering bean definition for [Definition] method {0}.{1}()", configClass.ConfigurationClassType.Name, beanName)); + } + + _registry.RegisterObjectDefinition(beanName, beanDef); + } + + private void LoadBeanDefinitionsFromImportedResources(IDictionary importedResources) + { + IDictionary readerInstanceCache = new Dictionary(); + foreach (KeyValuePair entry in importedResources) + { + String resource = entry.Key; + Type readerClass = entry.Value; + + if (!readerInstanceCache.ContainsKey(readerClass)) + { + try + { + IObjectDefinitionReader readerInstance = + (IObjectDefinitionReader)Activator.CreateInstance(readerClass.GetType(), _registry); + + readerInstanceCache.Add(readerClass, readerInstance); + } + catch (Exception ex) + { + throw new InvalidOperationException(String.Format("Could not instantiate IObjectDefinitionReader class {0}", readerClass.FullName)); + } + } + + IObjectDefinitionReader reader = readerInstanceCache[readerClass]; + + reader.LoadObjectDefinitions(resource); + } + } + + private class ConfigurationClassObjectDefinition : RootObjectDefinition + { + } + + } + +} diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassParser.cs b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassParser.cs new file mode 100644 index 00000000..1a681a5a --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassParser.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spring.Objects.Factory.Parsing; +using Spring.Collections.Generic; +using Spring.Util; +using System.Reflection; + +namespace Spring.Context.Annotation +{ + + public class ConfigurationClassParser + { + private ISet _configurationClasses = new HashedSet(); + + private Stack _importStack = new Stack(); + + private IProblemReporter _problemReporter; + + /// + /// Initializes a new instance of the ConfigurationClassParser class. + /// + /// + public ConfigurationClassParser(IProblemReporter problemReporter) + { + _problemReporter = problemReporter; + } + + public ISet ConfigurationClasses + { + get { return _configurationClasses; } + } + + //public void Parse(String className, String beanName) + //{ + // ProcessConfigurationClass(new ConfigurationClass(className, beanName)); + //} + + public void Parse(Type type, string objectName) + { + ProcessConfigurationClass(new ConfigurationClass(objectName, type)); + } + + public void Validate() + { + foreach (ConfigurationClass configClass in ConfigurationClasses) + { + configClass.Validate(_problemReporter); + } + } + + protected void ProcessConfigurationClass(ConfigurationClass configurationClass) + { + DoProcessConfigurationClass(configurationClass); + + if (ConfigurationClasses.Contains(configurationClass) && configurationClass.ObjectName != null) + { + // Explicit object definition found, probably replacing an import. + // Let's remove the old one and go with the new one. + ConfigurationClasses.Remove(configurationClass); + } + ConfigurationClasses.Add(configurationClass); + } + + private void DoProcessConfigurationClass(ConfigurationClass configurationClass) + { + if (Attribute.GetCustomAttribute(configurationClass.ConfigurationClassType, typeof(ImportAttribute)) != null) + { + ImportAttribute attrib = Attribute.GetCustomAttribute(configurationClass.ConfigurationClassType.GetType(), typeof(ImportAttribute)) as ImportAttribute; + ProcessImport(configurationClass, attrib.Types); + } + + if (Attribute.GetCustomAttribute(configurationClass.ConfigurationClassType, typeof(ImportResourceAttribute)) != null) + { + ImportResourceAttribute attrib = Attribute.GetCustomAttribute(configurationClass.ConfigurationClassType.GetType(), typeof(ImportResourceAttribute)) as ImportResourceAttribute; + + foreach (string resource in attrib.Resources) + { + configurationClass.AddImportedResource(resource, attrib.DefinitionReader.GetType()); + } + } + + ISet definitionMethods = GetAllMethodsWithCustomAttributeForClass(configurationClass.ConfigurationClassType, typeof(DefinitionAttribute)); + foreach (MethodInfo definitionMethod in definitionMethods) + { + configurationClass.Methods.Add(new ConfigurationClassMethod(definitionMethod, configurationClass)); + + } + } + + private ISet GetAllMethodsWithCustomAttributeForClass(Type theClass, Type customAttribute) + { + ISet methods = new HashedSet(); + + foreach (MethodInfo method in theClass.GetMethods()) + { + if (Attribute.GetCustomAttribute(method, customAttribute) != null) + { + methods.Add(method); + } + } + + return methods; + } + + private void ProcessImport(ConfigurationClass configClass, Type[] classesToImport) + { + if (_importStack.Contains(configClass)) + { + _problemReporter.Error(new CircularImportProblem(configClass, _importStack, configClass.ConfigurationClassType)); + } + else + { + _importStack.Push(configClass); + foreach (Type classToImport in classesToImport) + { + ProcessConfigurationClass(new ConfigurationClass(null, classToImport)); + } + _importStack.Pop(); + } + } + + private class CircularImportProblem : Problem + { + public CircularImportProblem(ConfigurationClass configClass, Stack importStack, Type configurationClassType) + : base(String.Format("A circular @Import has been detected: " + + "Illegal attempt by [Configuration] class '{0}' to import class '{1}' as '{2}' is " + + "already present in the current import stack [{3}]", + importStack.Peek().SimpleName, configClass.SimpleName, + configClass.SimpleName, importStack), + new Location(importStack.Peek().Resource, configurationClassType) + ) + { } + + } + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs new file mode 100644 index 00000000..8c58bcf1 --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Common.Logging; +using Spring.Objects.Factory.Parsing; +using Spring.Objects.Factory.Support; +using Spring.Objects.Factory.Config; +using Spring.Collections.Generic; +using Spring.Objects.Factory; + +namespace Spring.Context.Annotation +{ + public class ConfigurationClassPostProcessor : IObjectDefinitionRegistryPostProcessor + { + private ILog _logger = LogManager.GetLogger(typeof(ConfigurationClassPostProcessor)); + + private bool _postProcessObjectDefinitionRegistryCalled = false; + + private bool _postProcessObjectFactoryCalled = false; + + private IProblemReporter _problemReporter = new FailFastProblemReporter(); + + public IProblemReporter ProblemReporter + { + set { _problemReporter = (value ?? new FailFastProblemReporter()); } + } + + //public int getOrder() + //{ + // return Ordered.HIGHEST_PRECEDENCE; + //} + + public void PostProcessObjectDefinitionRegistry(IObjectDefinitionRegistry registry) + { + if (_postProcessObjectDefinitionRegistryCalled) + { + throw new InvalidOperationException("PostProcessObjectDefinitionRegistry already called for this post-processor"); + } + if (_postProcessObjectFactoryCalled) + { + throw new InvalidOperationException("PostProcessObjectFactory already called for this post-processor"); + } + _postProcessObjectDefinitionRegistryCalled = true; + ProcessConfigObjectDefinitions(registry); + } + + private void ProcessConfigObjectDefinitions(IObjectDefinitionRegistry registry) + { + ISet configCandidates = new HashedSet(); + foreach (string objectName in registry.GetObjectDefinitionNames()) + { + IObjectDefinition objectDef = registry.GetObjectDefinition(objectName); + if (ConfigurationClassObjectDefinitionReader.CheckConfigurationClassCandidate(objectDef.ObjectType)) + { + configCandidates.Add(new ObjectDefinitionHolder(objectDef, objectName)); + } + } + + //if nothing to process, bail out + if (configCandidates.Count == 0) { return; } + + ConfigurationClassParser parser = new ConfigurationClassParser(_problemReporter); + foreach (ObjectDefinitionHolder holder in configCandidates) + { + IObjectDefinition bd = holder.ObjectDefinition; + try + { + if (bd is AbstractObjectDefinition && ((AbstractObjectDefinition)bd).HasObjectType) + { + parser.Parse(((AbstractObjectDefinition)bd).ObjectType, holder.ObjectName); + } + else + { + //parser.Parse(bd.ObjectTypeName, holder.ObjectName); + } + } + catch (ObjectDefinitionParsingException ex) + { + throw new ObjectDefinitionStoreException("Failed to load object class: " + bd.ObjectTypeName, ex); + } + } + parser.Validate(); + + // Read the model and create bean definitions based on its content + ConfigurationClassObjectDefinitionReader reader = new ConfigurationClassObjectDefinitionReader(registry, _problemReporter); + reader.LoadBeanDefinitions(parser.ConfigurationClasses); + } + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/DefinitionAttribute.cs b/src/Spring/Spring.Core/Context/Annotation/DefinitionAttribute.cs new file mode 100644 index 00000000..8f00d403 --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/DefinitionAttribute.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spring.Objects.Factory.Config; + +namespace Spring.Context.Annotation +{ + [AttributeUsage(AttributeTargets.Method)] + public class DefinitionAttribute : Attribute + { + private AutoWiringMode _autoWire = AutoWiringMode.No; + + private string _initMethod; + + private string[] _name; + + /// + /// Are dependencies to be injected via autowiring? + /// + /// The auto wire. + public AutoWiringMode AutoWire + { + get { return _autoWire; } + set + { + _autoWire = value; + } + } + private string _destroyMethod; + /// + /// The optional name of a method to call on the bean instance upon closing the + /// application context, for example a Close() method on a DataSource. + /// The method must have no arguments but may throw any exception. + /// + /// Note: Only invoked on objects whose lifecycle is under the full control of the + /// factory, which is always the case for singletons but not guaranteed + /// for any other scope. + /// + /// + /// + /// The destroy method. + public string DestroyMethod + { + get { return _destroyMethod; } + set + { + _destroyMethod = value; + } + } + + /// + /// The optional name of a method to call on the object instance during initialization. + /// Not commonly used, given that the method may be called programmatically directly + /// within the body of a Bean-annotated method. + /// + /// The init method. + public string InitMethod + { + get { return _initMethod; } + set + { + _initMethod = value; + } + } + + /// + /// The name of this object, or if plural, aliases for this object. If left unspecified + /// the name of the object is the name of the attributed method. If specified, the method + /// name is ignored. + /// + /// The name. + public string[] Name + { + get + { + return _name; + } + set + { + _name = value; + } + } + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/DependsOnAttribute.cs b/src/Spring/Spring.Core/Context/Annotation/DependsOnAttribute.cs new file mode 100644 index 00000000..94f46207 --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/DependsOnAttribute.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Spring.Context.Annotation +{ + /// + /// objects on which the current object depends. Any objects specified are guaranteed to be + /// created by the container before this object. Used infrequently in cases where a object + /// does not explicitly depend on another through properties or constructor arguments, + /// but rather depends on the side effects of another object's initialization. + /// Note: This attribute will not be inherited by child object definitions, + /// hence it needs to be specified per concrete object definition. + /// + /// Using at the class level has no effect unless component-scanning + /// is being used. If a -attributed class is declared via XML, + /// attribute metadata is ignored, and + /// <object depends-on="..."/> is respected instead. + /// + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] + public class DependsOnAttribute : Attribute + { + private string[] _name; + + /// + /// Initializes a new instance of the DependsOn class. + /// + /// + public DependsOnAttribute(string[] name) + { + _name = name; + } + + public string[] Name + { + get { return _name; } + set + { + _name = value; + } + } + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/ImportAttribute.cs b/src/Spring/Spring.Core/Context/Annotation/ImportAttribute.cs new file mode 100644 index 00000000..9f01c55d --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/ImportAttribute.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Spring.Context.Annotation +{ + /// + /// Indicates one or more classes to import. + /// + /// Provides functionality equivalent to the :lt;import/> element in Spring XML. + /// Only supported for actual -attributed classes. + /// + /// + /// definitions declared in imported classes + /// should be accessed by using injection. Either the object + /// itself can be autowired, or the configuration class instance declaring the object can be + /// autowired. The latter approach allows for explicit, IDE-friendly navigation between + /// class methods. + /// + /// + /// If XML or other non- object definition resources need to be + /// imported, use + /// + /// + [AttributeUsage(AttributeTargets.Class)] + public class ImportAttribute : Attribute + { + private Type[] _types; + + /// + /// Initializes a new instance of the Import class. + /// + /// + public ImportAttribute(Type[] types) + { + _types = types; + } + + /// + /// The class or classes to import. + /// + /// The type. + public Type[] Types + { + get { return _types; } + set + { + _types = value; + } + } + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/ImportResourceAttribute.cs b/src/Spring/Spring.Core/Context/Annotation/ImportResourceAttribute.cs new file mode 100644 index 00000000..1b798e32 --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/ImportResourceAttribute.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spring.Objects.Factory.Support; +using Spring.Objects.Factory.Xml; + +namespace Spring.Context.Annotation +{ + /// + /// + /// + [AttributeUsage(AttributeTargets.Class)] + public class ImportResourceAttribute : Attribute + { + private IObjectDefinitionReader _objectDefinitionReader; + + private string[] _resources; + + /// + /// Initializes a new instance of the ImportResource class. + /// + /// + /// + public ImportResourceAttribute(IObjectDefinitionReader objectDefinitionReader, string[] resources) + { + _objectDefinitionReader = objectDefinitionReader; + _resources = resources; + } + + /// + /// implementation to use when processing resources specified + /// by the attribute. + /// + /// The . + public IObjectDefinitionReader DefinitionReader + { + get { return _objectDefinitionReader; } + set + { + _objectDefinitionReader = value; + } + } + + /// + /// Resource paths to import. Resource-loading prefixes such as assembly:// and + /// file://, etc may be used. + /// + /// The resources. + public string[] Resources + { + get { return _resources; } + set + { + _resources = value; + } + } + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/LazyAttrribute.cs b/src/Spring/Spring.Core/Context/Annotation/LazyAttrribute.cs new file mode 100644 index 00000000..1eba0cf4 --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/LazyAttrribute.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Spring.Context.Annotation +{ + /// + /// Indicates whether a object is to be lazily initialized. + /// + /// If this annotation is not present on a Component or object definition, eager + /// initialization will occur. If present and set to true, the + /// object/Component will not be initialized until referenced by another object or + /// explicitly retrieved from the enclosing . + /// If present and set to false, the object will be instantiated on startup by object factories + /// that perform eager initialization of singletons. + /// + /// + /// If Lazy is present on a class, this indicates that all + /// methods within that should be lazily + /// initialized. If Lazy is present and false on a object method within a + /// Lazy-annotated Configuration class, this indicates overriding the 'default + /// lazy' behavior and that the object should be eagerly initialized. + /// + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] + public class LazyAttrribute : Attribute + { + private bool _lazyInitialize = true; + + /// + /// Initializes a new instance of the Lazy class. + /// + /// + public LazyAttrribute(bool lazyInitialize) + { + _lazyInitialize = lazyInitialize; + } + + /// + /// Whether lazy initialization should occur. + /// + /// true if [lazy initialize]; otherwise, false. + public bool LazyInitialize + { + get { return _lazyInitialize; } + set + { + _lazyInitialize = value; + } + } + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/PrimaryAttribute.cs b/src/Spring/Spring.Core/Context/Annotation/PrimaryAttribute.cs new file mode 100644 index 00000000..5e1b717f --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/PrimaryAttribute.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Spring.Context.Annotation +{ + /// + /// Indicates that an object should be given preference when multiple candidates + /// are qualified to autowire a single-valued dependency. If exactly one 'primary' + /// object exists among the candidates, it will be the autowired value. + /// + /// Using at the class level has no effect unless component-scanning + /// is being used. If a -attributed class is declared via XML, + /// attribute metadata is ignored, and + /// <object primary="true|false"/>> is respected instead. + /// + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public class PrimaryAttribute : Attribute + { + + } +} diff --git a/src/Spring/Spring.Core/Context/Annotation/ScopeAttribute.cs b/src/Spring/Spring.Core/Context/Annotation/ScopeAttribute.cs new file mode 100644 index 00000000..6ac5d81e --- /dev/null +++ b/src/Spring/Spring.Core/Context/Annotation/ScopeAttribute.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spring.Objects.Factory.Support; + +namespace Spring.Context.Annotation +{ + /// + /// When used as a type-level attribute, indicates the name of a scope to use + /// for instances of the attributed type. + /// + /// When used as a method-level attribute in conjunction with the + /// attribute, indicates the name of a scope to use for + /// the instance returned from the method. + /// + /// In this context, scope means the lifecycle of an instance, such as + /// singleton, prototype, and so forth. + /// + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public class ScopeAttribute : Attribute + { + private ObjectScope _scope = ObjectScope.Singleton; + + /// + /// Initializes a new instance of the Scope class. + /// + /// + public ScopeAttribute(ObjectScope scope) + { + _scope = scope; + } + + /// + /// Specifies the scope to use for the annotated object. + /// + /// The scope. + public ObjectScope ObjectScope + { + get { return _scope; } + set + { + _scope = value; + } + } + + } +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/FailFastProblemReporter.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/FailFastProblemReporter.cs new file mode 100644 index 00000000..54211e89 --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/FailFastProblemReporter.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Common.Logging; + +namespace Spring.Objects.Factory.Parsing +{ + public class FailFastProblemReporter : IProblemReporter + { + private ILog _logger = LogManager.GetLogger(typeof(FailFastProblemReporter)); + + public ILog Logger + { + get { return _logger; } + } + + public void Error(Problem problem) + { + _logger.Error(problem.Message); + throw new ObjectDefinitionParsingException(problem); + } + + public void Fatal(Problem problem) + { + _logger.Fatal(problem.Message); + throw new ObjectDefinitionParsingException(problem); + } + + public void Warning(Problem problem) + { + _logger.Warn(problem.Message); + + } + + } +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs new file mode 100644 index 00000000..48832944 --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spring.Core.IO; +using Spring.Util; + +namespace Spring.Objects.Factory.Parsing +{ + public class Location + { + private IResource resource; + private object source; + + /// + /// Initializes a new instance of the Location class. + /// + /// + /// + public Location(IResource resource, object source) + { + AssertUtils.ArgumentNotNull(resource, "resource"); + this.resource = resource; + this.source = source; + } + + /// + /// Initializes a new instance of the Location class. + /// + /// + public Location(IResource resource) + : this(resource, null) + { + + } + public IResource Resource + { + get + { + return resource; + } + } + public object Source + { + get + { + return source; + } + } + + + } +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/ObjectDefinitionParsingException.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/ObjectDefinitionParsingException.cs new file mode 100644 index 00000000..31c28370 --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/ObjectDefinitionParsingException.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.Serialization; + +namespace Spring.Objects.Factory.Parsing +{ + [Serializable] + public class ObjectDefinitionParsingException : ObjectDefinitionStoreException + { + protected ObjectDefinitionParsingException(SerializationInfo info, StreamingContext context) + { + } + /// + /// Initializes a new instance of the ObjectDefinitionParsingException class. + /// + public ObjectDefinitionParsingException(Problem problem) + : base(problem.Location.Resource, problem.ResourceDescription, problem.Message) + { + + } + } +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs new file mode 100644 index 00000000..0848261a --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spring.Core.IO; +using Spring.Util; + +namespace Spring.Objects.Factory.Parsing +{ + public class Problem + { + private string _message; + + private Location _location; + + private Exception _rootCause; + + /// + /// Initializes a new instance of the Problem class. + /// + /// + /// + public Problem(string message, Location location) + : this(message, location, null) + { + + } + + /// + /// Initializes a new instance of the Problem class. + /// + /// + /// + /// + public Problem(string message, Location location, Exception rootCause) + { + AssertUtils.ArgumentNotNull(message, "message"); + AssertUtils.ArgumentNotNull(location, "resource"); + + _message = message; + _location = location; + _rootCause = rootCause; + } + + public string Message + { + get + { + return _message; + } + } + + public Location Location + { + get + { + return _location; + } + } + + public string ResourceDescription + { + get { return _location.Resource.Description; } + } + + public override string ToString() + { + + StringBuilder sb = new StringBuilder(); + sb.Append("Configuration problem: "); + sb.Append(Message); + sb.Append("\nOffending resource: ").Append(ResourceDescription); + + return sb.ToString(); + + } + + } +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs new file mode 100644 index 00000000..f4898c0a --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Spring.Objects.Factory.Support +{ + public interface IObjectDefinitionRegistryPostProcessor + { + void PostProcessObjectDefinitionRegistry(IObjectDefinitionRegistry registry); + } +} diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionReaderUtils.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionReaderUtils.cs index 8140318b..e007f6cd 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionReaderUtils.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectDefinitionReaderUtils.cs @@ -143,7 +143,7 @@ namespace Spring.Objects.Factory.Support { if (objectDefinition is ChildObjectDefinition) { - generatedObjectName = ((ChildObjectDefinition) objectDefinition).ParentName + "$child"; + generatedObjectName = ((ChildObjectDefinition)objectDefinition).ParentName + "$child"; } else if (objectDefinition.FactoryObjectName != null) { @@ -157,7 +157,7 @@ namespace Spring.Objects.Factory.Support throw new ObjectDefinitionStoreException( objectDefinition.ResourceDescription, String.Empty, "Unnamed object definition specifies neither 'Type' nor 'Parent' " + - "nor 'FactoryObject' property values so a unique name cannot be generated."); + "nor 'FactoryObject' property values so a unique name cannot be generated."); } generatedObjectName = "$nested"; } @@ -166,14 +166,15 @@ namespace Spring.Objects.Factory.Support if (isInnerObject) { id = generatedObjectName + GENERATED_OBJECT_NAME_SEPARATOR + ObjectUtils.GetIdentityHexString(objectDefinition); - } else + } + else { int counter = -1; while (counter == -1 || registry.ContainsObjectDefinition(id)) { counter++; id = generatedObjectName + GENERATED_OBJECT_NAME_SEPARATOR + counter; - } + } } return id; @@ -257,6 +258,15 @@ namespace Spring.Objects.Factory.Support return myHandler; } + + public static String RegisterWithGeneratedName(AbstractObjectDefinition definition, IObjectDefinitionRegistry registry) + { + String generatedName = GenerateObjectName(definition, registry, false); + registry.RegisterObjectDefinition(generatedName, definition); + return generatedName; + } + + #region Constructor (s) / Destructor // CLOVER:OFF diff --git a/src/Spring/Spring.Web/Objects/Factory/Support/ObjectScope.cs b/src/Spring/Spring.Core/Objects/Factory/Support/ObjectScope.cs similarity index 100% rename from src/Spring/Spring.Web/Objects/Factory/Support/ObjectScope.cs rename to src/Spring/Spring.Core/Objects/Factory/Support/ObjectScope.cs diff --git a/src/Spring/Spring.Core/Spring.Core.2010.csproj b/src/Spring/Spring.Core/Spring.Core.2010.csproj index f67bb62c..1aab03b2 100644 --- a/src/Spring/Spring.Core/Spring.Core.2010.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2010.csproj @@ -125,7 +125,15 @@ Code + + + + + + + + Code @@ -163,6 +171,19 @@ Code + + + + + + + + + + + + + Code @@ -695,7 +716,14 @@ + + + + + + + diff --git a/src/Spring/Spring.Web/Spring.Web.2010.csproj b/src/Spring/Spring.Web/Spring.Web.2010.csproj index f6f041f2..4069813d 100644 --- a/src/Spring/Spring.Web/Spring.Web.2010.csproj +++ b/src/Spring/Spring.Web/Spring.Web.2010.csproj @@ -169,7 +169,6 @@ - From d5d35573d017a79b37b9776302d784bd3096a950 Mon Sep 17 00:00:00 2001 From: sbohlen Date: Wed, 10 Nov 2010 01:32:16 +0000 Subject: [PATCH 02/11] remove misc references to beans --- ...onfigurationClassObjectDefinitionReader.cs | 50 +++++++++---------- .../ConfigurationClassPostProcessor.cs | 21 +++++++- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs index 276b54ad..b6c47476 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs @@ -39,15 +39,15 @@ namespace Spring.Context.Annotation return false; } - public void LoadBeanDefinitions(ISet configurationModel) + public void LoadObjectDefinitions(ISet configurationModel) { foreach (ConfigurationClass configClass in configurationModel) { - LoadBeanDefinitionsForConfigurationClass(configClass); + LoadObjectDefinitionsForConfigurationClass(configClass); } } - private void LoadBeanDefinitionForConfigurationClassIfNecessary(ConfigurationClass configClass) + private void LoadObjectDefinitionForConfigurationClassIfNecessary(ConfigurationClass configClass) { if (configClass.ObjectName != null) { @@ -70,29 +70,29 @@ namespace Spring.Context.Annotation } } - private void LoadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass) + private void LoadObjectDefinitionsForConfigurationClass(ConfigurationClass configClass) { - LoadBeanDefinitionForConfigurationClassIfNecessary(configClass); + LoadObjectDefinitionForConfigurationClassIfNecessary(configClass); foreach (ConfigurationClassMethod method in configClass.Methods) { - LoadBeanDefinitionsForModelMethod(method); + LoadObjectDefinitionsForModelMethod(method); } - LoadBeanDefinitionsFromImportedResources(configClass.ImportedResources); + LoadObjectDefinitionsFromImportedResources(configClass.ImportedResources); } - private void LoadBeanDefinitionsForModelMethod(ConfigurationClassMethod method) + private void LoadObjectDefinitionsForModelMethod(ConfigurationClassMethod method) { ConfigurationClass configClass = method.ConfigurationClass; MethodInfo metadata = method.MethodMetadata; - RootObjectDefinition beanDef = new ConfigurationClassObjectDefinition(); + RootObjectDefinition objDef = new ConfigurationClassObjectDefinition(); //beanDef.Resource = configClass.Resource; //beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource())); - beanDef.FactoryObjectName = configClass.ObjectName; - beanDef.FactoryMethodName = metadata.Name; - beanDef.AutowireMode = Objects.Factory.Config.AutoWiringMode.Constructor; + objDef.FactoryObjectName = configClass.ObjectName; + objDef.FactoryMethodName = metadata.Name; + objDef.AutowireMode = Objects.Factory.Config.AutoWiringMode.Constructor; //beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE); // consider name and any aliases @@ -109,16 +109,16 @@ namespace Spring.Context.Annotation } - string beanName = (names.Count > 0 ? names[0] : method.MethodMetadata.Name); + string objectName = (names.Count > 0 ? names[0] : method.MethodMetadata.Name); for (int i = 1; i < names.Count; i++) { - _registry.RegisterAlias(beanName, names[i]); + _registry.RegisterAlias(objectName, names[i]); } // has this already been overridden (e.g. via XML)? - if (_registry.ContainsObjectDefinition(beanName)) + if (_registry.ContainsObjectDefinition(objectName)) { - IObjectDefinition existingBeanDef = _registry.GetObjectDefinition(beanName); + IObjectDefinition existingBeanDef = _registry.GetObjectDefinition(objectName); // is the existing bean definition one that was created from a configuration class? if (!(existingBeanDef is ConfigurationClassObjectDefinition)) { @@ -127,7 +127,7 @@ namespace Spring.Context.Annotation if (_logger.IsDebugEnabled) { _logger.Debug(String.Format("Skipping loading bean definition for {0}: a definition for object " + - "'{1}' already exists. This is likely due to an override in XML.", method, beanName)); + "'{1}' already exists. This is likely due to an override in XML.", method, objectName)); } return; } @@ -142,13 +142,12 @@ namespace Spring.Context.Annotation // is this bean to be instantiated lazily? if (Attribute.GetCustomAttribute(metadata, typeof(LazyAttrribute)) != null) { - beanDef.IsLazyInit = (Attribute.GetCustomAttribute(metadata, typeof(LazyAttrribute)) as LazyAttrribute).LazyInitialize; + objDef.IsLazyInit = (Attribute.GetCustomAttribute(metadata, typeof(LazyAttrribute)) as LazyAttrribute).LazyInitialize; } if (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) != null) { - DependsOnAttribute attrib = Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) as DependsOnAttribute; - beanDef.DependsOn = (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) as DependsOnAttribute).Name; + objDef.DependsOn = (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) as DependsOnAttribute).Name; } //Autowire autowire = (Autowire) beanAttributes.get("autowire"); @@ -169,19 +168,18 @@ namespace Spring.Context.Annotation // consider scoping if (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) != null) { - ScopeAttribute attrib = Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) as ScopeAttribute; - beanDef.Scope = (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) as ScopeAttribute).ObjectScope.ToString(); + objDef.Scope = (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) as ScopeAttribute).ObjectScope.ToString(); } if (_logger.IsDebugEnabled) { - _logger.Debug(String.Format("Registering bean definition for [Definition] method {0}.{1}()", configClass.ConfigurationClassType.Name, beanName)); + _logger.Debug(String.Format("Registering bean definition for [Definition] method {0}.{1}()", configClass.ConfigurationClassType.Name, objectName)); } - _registry.RegisterObjectDefinition(beanName, beanDef); + _registry.RegisterObjectDefinition(objectName, objDef); } - private void LoadBeanDefinitionsFromImportedResources(IDictionary importedResources) + private void LoadObjectDefinitionsFromImportedResources(IDictionary importedResources) { IDictionary readerInstanceCache = new Dictionary(); foreach (KeyValuePair entry in importedResources) @@ -198,7 +196,7 @@ namespace Spring.Context.Annotation readerInstanceCache.Add(readerClass, readerInstance); } - catch (Exception ex) + catch (Exception) { throw new InvalidOperationException(String.Format("Could not instantiate IObjectDefinitionReader class {0}", readerClass.FullName)); } diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs index 8c58bcf1..17a46adc 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs +++ b/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs @@ -44,6 +44,25 @@ namespace Spring.Context.Annotation ProcessConfigObjectDefinitions(registry); } + /* + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) + { + if (this.postProcessBeanFactoryCalled) + { + throw new IllegalStateException( + "postProcessBeanFactory already called for this post-processor"); + } + this.postProcessBeanFactoryCalled = true; + if (!this.postProcessBeanDefinitionRegistryCalled) + { + // BeanDefinitionRegistryPostProcessor hook apparently not supported... + // Simply call processConfigBeanDefinitions lazily at this point then. + processConfigBeanDefinitions((BeanDefinitionRegistry)beanFactory); + } + enhanceConfigurationClasses(beanFactory); + } + */ + private void ProcessConfigObjectDefinitions(IObjectDefinitionRegistry registry) { ISet configCandidates = new HashedSet(); @@ -83,7 +102,7 @@ namespace Spring.Context.Annotation // Read the model and create bean definitions based on its content ConfigurationClassObjectDefinitionReader reader = new ConfigurationClassObjectDefinitionReader(registry, _problemReporter); - reader.LoadBeanDefinitions(parser.ConfigurationClasses); + reader.LoadObjectDefinitions(parser.ConfigurationClasses); } } From 324486e86ac22557aef03c44ac3c1dcd55735bfe Mon Sep 17 00:00:00 2001 From: sbohlen Date: Wed, 10 Nov 2010 20:50:45 +0000 Subject: [PATCH 03/11] restructured into separate assembly to avoid Spring.Core needing a dependency on Spring.Aop --- Spring.Net.2010.sln | 24 +++++ .../Attributes}/ConfigurationAttribute.cs | 11 ++- .../Context/Attributes}/ConfigurationClass.cs | 2 +- .../Attributes}/ConfigurationClassMethod.cs | 2 +- ...onfigurationClassObjectDefinitionReader.cs | 12 ++- .../Attributes}/ConfigurationClassParser.cs | 2 +- .../ConfigurationClassPostProcessor.cs | 87 ++++++++++++++----- .../Attributes}/DefinitionAttribute.cs | 2 +- .../Context/Attributes}/DependsOnAttribute.cs | 2 +- .../Context/Attributes}/ImportAttribute.cs | 2 +- .../Attributes}/ImportResourceAttribute.cs | 2 +- .../Context/Attributes}/LazyAttrribute.cs | 2 +- .../Context/Attributes}/PrimaryAttribute.cs | 2 +- .../Context/Attributes}/ScopeAttribute.cs | 2 +- .../Properties/AssemblyInfo.cs | 36 ++++++++ .../Spring.Core.Configuration.2010.csproj | 76 ++++++++++++++++ .../IObjectDefinitionRegistryPostProcessor.cs | 3 +- .../Spring.Core/Spring.Core.2010.csproj | 14 +-- .../ConfigurationClassPostProcessorTests.cs | 84 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 36 ++++++++ ...pring.Core.Configuration.Tests.2010.csproj | 67 ++++++++++++++ 21 files changed, 419 insertions(+), 51 deletions(-) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/ConfigurationAttribute.cs (89%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/ConfigurationClass.cs (96%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/ConfigurationClassMethod.cs (95%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/ConfigurationClassObjectDefinitionReader.cs (93%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/ConfigurationClassParser.cs (96%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/ConfigurationClassPostProcessor.cs (56%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/DefinitionAttribute.cs (95%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/DependsOnAttribute.cs (95%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/ImportAttribute.cs (95%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/ImportResourceAttribute.cs (94%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/LazyAttrribute.cs (95%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/PrimaryAttribute.cs (93%) rename src/Spring/{Spring.Core/Context/Annotation => Spring.Core.Configuration/Context/Attributes}/ScopeAttribute.cs (94%) create mode 100644 src/Spring/Spring.Core.Configuration/Properties/AssemblyInfo.cs create mode 100644 src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj create mode 100644 test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs create mode 100644 test/Spring/Spring.Core.Configuration.Tests/Properties/AssemblyInfo.cs create mode 100644 test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj diff --git a/Spring.Net.2010.sln b/Spring.Net.2010.sln index b1bea551..eb88a143 100644 --- a/Spring.Net.2010.sln +++ b/Spring.Net.2010.sln @@ -74,6 +74,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Web.Mvc.2010", "src\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Web.Mvc.Tests.2010", "test\Spring\Spring.Web.Mvc.Tests\Spring.Web.Mvc.Tests.2010.csproj", "{D4032434-D9A8-437B-95E8-9D4DE0AD9932}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Core.Configuration.2010", "src\Spring\Spring.Core.Configuration\Spring.Core.Configuration.2010.csproj", "{7B65D538-E863-4F57-8DDC-2C38E4150045}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Core.Configuration.Tests.2010", "test\Spring\Spring.Core.Configuration.Tests\Spring.Core.Configuration.Tests.2010.csproj", "{4F1A206C-09A8-43FF-B791-FE956E99A120}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|.NET = Debug|.NET @@ -434,6 +438,26 @@ Global {D4032434-D9A8-437B-95E8-9D4DE0AD9932}.Release|Any CPU.Build.0 = Release|Any CPU {D4032434-D9A8-437B-95E8-9D4DE0AD9932}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {D4032434-D9A8-437B-95E8-9D4DE0AD9932}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7B65D538-E863-4F57-8DDC-2C38E4150045}.Debug|.NET.ActiveCfg = Debug|Any CPU + {7B65D538-E863-4F57-8DDC-2C38E4150045}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B65D538-E863-4F57-8DDC-2C38E4150045}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B65D538-E863-4F57-8DDC-2C38E4150045}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7B65D538-E863-4F57-8DDC-2C38E4150045}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7B65D538-E863-4F57-8DDC-2C38E4150045}.Release|.NET.ActiveCfg = Release|Any CPU + {7B65D538-E863-4F57-8DDC-2C38E4150045}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B65D538-E863-4F57-8DDC-2C38E4150045}.Release|Any CPU.Build.0 = Release|Any CPU + {7B65D538-E863-4F57-8DDC-2C38E4150045}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7B65D538-E863-4F57-8DDC-2C38E4150045}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4F1A206C-09A8-43FF-B791-FE956E99A120}.Debug|.NET.ActiveCfg = Debug|Any CPU + {4F1A206C-09A8-43FF-B791-FE956E99A120}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F1A206C-09A8-43FF-B791-FE956E99A120}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F1A206C-09A8-43FF-B791-FE956E99A120}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4F1A206C-09A8-43FF-B791-FE956E99A120}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4F1A206C-09A8-43FF-B791-FE956E99A120}.Release|.NET.ActiveCfg = Release|Any CPU + {4F1A206C-09A8-43FF-B791-FE956E99A120}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F1A206C-09A8-43FF-B791-FE956E99A120}.Release|Any CPU.Build.0 = Release|Any CPU + {4F1A206C-09A8-43FF-B791-FE956E99A120}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4F1A206C-09A8-43FF-B791-FE956E99A120}.Release|Mixed Platforms.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationAttribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationAttribute.cs similarity index 89% rename from src/Spring/Spring.Core/Context/Annotation/ConfigurationAttribute.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationAttribute.cs index 9b00778a..8bfdb6a4 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ConfigurationAttribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationAttribute.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { /// /// Indicates that a class declares one or more methods and may be processed @@ -27,6 +27,15 @@ namespace Spring.Context.Annotation [AttributeUsage(AttributeTargets.Class)] public class ConfigurationAttribute : Attribute { + + /// + /// Initializes a new instance of the ConfigurationAttribute class. + /// + public ConfigurationAttribute() + { + + } + private string _name; /// diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClass.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClass.cs similarity index 96% rename from src/Spring/Spring.Core/Context/Annotation/ConfigurationClass.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClass.cs index 53a594e7..8c22c382 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClass.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClass.cs @@ -5,7 +5,7 @@ using Spring.Core.IO; using Spring.Collections.Generic; using Spring.Objects.Factory.Parsing; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { public class ConfigurationClass { diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassMethod.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs similarity index 95% rename from src/Spring/Spring.Core/Context/Annotation/ConfigurationClassMethod.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs index 91fbe3fd..14a7aa78 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassMethod.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs @@ -25,7 +25,7 @@ using Spring.Core.IO; using System.Reflection; using Spring.Objects.Factory.Parsing; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { /** diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs similarity index 93% rename from src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs index b6c47476..e50b5a3e 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs @@ -8,7 +8,7 @@ using System.Reflection; using Spring.Objects.Factory.Config; using Common.Logging; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { public class ConfigurationClassObjectDefinitionReader { @@ -33,7 +33,7 @@ namespace Spring.Context.Annotation { if (type != null) { - return (Attribute.GetCustomAttribute(type.GetType(), typeof(ConfigurationAttribute)) != null); + return (Attribute.GetCustomAttribute(type, typeof(ConfigurationAttribute)) != null); } return false; @@ -58,14 +58,14 @@ namespace Spring.Context.Annotation // no bean definition exists yet -> this must be an imported configuration class (@Import). GenericObjectDefinition configBeanDef = new GenericObjectDefinition(); String className = configClass.ConfigurationClassType.Name; - configBeanDef.ObjectTypeName = className; + configBeanDef.ObjectType = configClass.GetType(); if (CheckConfigurationClassCandidate(configClass.ConfigurationClassType)) { String configObjectName = ObjectDefinitionReaderUtils.RegisterWithGeneratedName(configBeanDef, _registry); configClass.ObjectName = configObjectName; if (_logger.IsDebugEnabled) { - _logger.Debug(String.Format("Registered bean definition for imported [Configuration] class {0}", configObjectName)); + _logger.Debug(String.Format("Registered object definition for imported [Configuration] class {0}", configObjectName)); } } } @@ -102,6 +102,10 @@ namespace Spring.Context.Annotation for (int i = 0; i < objectAttributes.Length; i++) { string[] namesAndAliases = ((DefinitionAttribute)objectAttributes[i]).Name; + + if (namesAndAliases == null) + namesAndAliases = new[] { metadata.Name }; + for (int j = 0; j > namesAndAliases.Length; j++) { names.Add(namesAndAliases[j]); diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassParser.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassParser.cs similarity index 96% rename from src/Spring/Spring.Core/Context/Annotation/ConfigurationClassParser.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassParser.cs index 1a681a5a..04c907f4 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassParser.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassParser.cs @@ -6,7 +6,7 @@ using Spring.Collections.Generic; using Spring.Util; using System.Reflection; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { public class ConfigurationClassParser diff --git a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs similarity index 56% rename from src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs index 17a46adc..f21fb73d 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ConfigurationClassPostProcessor.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs @@ -7,10 +7,11 @@ using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Config; using Spring.Collections.Generic; using Spring.Objects.Factory; +using Spring.Core; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { - public class ConfigurationClassPostProcessor : IObjectDefinitionRegistryPostProcessor + public class ConfigurationClassPostProcessor : IObjectDefinitionRegistryPostProcessor, IOrdered { private ILog _logger = LogManager.GetLogger(typeof(ConfigurationClassPostProcessor)); @@ -25,10 +26,7 @@ namespace Spring.Context.Annotation set { _problemReporter = (value ?? new FailFastProblemReporter()); } } - //public int getOrder() - //{ - // return Ordered.HIGHEST_PRECEDENCE; - //} + public void PostProcessObjectDefinitionRegistry(IObjectDefinitionRegistry registry) { @@ -44,24 +42,64 @@ namespace Spring.Context.Annotation ProcessConfigObjectDefinitions(registry); } - /* - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) + + private Type GenerateProxyType(Type objectType) + { + /* + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.ProxyTargetAttributes = true; + proxyFactory.Interfaces = Type.EmptyTypes; + proxyFactory.TargetSource = new ObjectFactoryTargetSource(originalBeanName, owningObjectFactory); + SpringObjectMethodInterceptor methodInterceptor = new SpringObjectMethodInterceptor(owningObjectFactory, objectNamingStrategy); + proxyFactory.AddAdvice(methodInterceptor); + + //TODO check type of object isn't infrastructure type. + + InheritanceAopProxyTypeBuilder iaptb = new InheritanceAopProxyTypeBuilder(proxyFactory); + //iaptb.ProxyDeclaredMembersOnly = true; // make configurable. + Type type = iaptb.BuildProxyType(); + */ + + return null; + } + private void EnhanceConfigurationClasses(IConfigurableListableObjectFactory objectFactory) + { + string[] objectNames = objectFactory.GetObjectDefinitionNames(); + + for (int i = 0; i < objectNames.Length; i++) + { + IObjectDefinition objDef = objectFactory.GetObjectDefinition(objectNames[i]); + if (Attribute.GetCustomAttribute(objDef.ObjectType, typeof(ConfigurationAttribute)) != null) { - if (this.postProcessBeanFactoryCalled) - { - throw new IllegalStateException( - "postProcessBeanFactory already called for this post-processor"); - } - this.postProcessBeanFactoryCalled = true; - if (!this.postProcessBeanDefinitionRegistryCalled) - { - // BeanDefinitionRegistryPostProcessor hook apparently not supported... - // Simply call processConfigBeanDefinitions lazily at this point then. - processConfigBeanDefinitions((BeanDefinitionRegistry)beanFactory); - } - enhanceConfigurationClasses(beanFactory); + //configNames.Add(objectNames[i]); + + //ObjectType is READONLY :( + //objDef.ObjectType = GenerateProxyType(objDef.ObjectType); } - */ + } + + + + + } + public void PostProcessObjectFactory(IConfigurableListableObjectFactory objectFactory) + { + if (_postProcessObjectFactoryCalled) + { + throw new InvalidOperationException( + "PostProcessObjectFactory already called for this post-processor"); + } + _postProcessObjectFactoryCalled = true; + if (!_postProcessObjectDefinitionRegistryCalled) + { + // BeanDefinitionRegistryPostProcessor hook apparently not supported... + // Simply call processConfigBeanDefinitions lazily at this point then. + ProcessConfigObjectDefinitions((IObjectDefinitionRegistry)objectFactory); + } + + EnhanceConfigurationClasses(objectFactory); + } + private void ProcessConfigObjectDefinitions(IObjectDefinitionRegistry registry) { @@ -105,5 +143,10 @@ namespace Spring.Context.Annotation reader.LoadObjectDefinitions(parser.ConfigurationClasses); } + + public int Order + { + get { return int.MinValue; } + } } } diff --git a/src/Spring/Spring.Core/Context/Annotation/DefinitionAttribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/DefinitionAttribute.cs similarity index 95% rename from src/Spring/Spring.Core/Context/Annotation/DefinitionAttribute.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/DefinitionAttribute.cs index 8f00d403..39efce04 100644 --- a/src/Spring/Spring.Core/Context/Annotation/DefinitionAttribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/DefinitionAttribute.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Spring.Objects.Factory.Config; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { [AttributeUsage(AttributeTargets.Method)] public class DefinitionAttribute : Attribute diff --git a/src/Spring/Spring.Core/Context/Annotation/DependsOnAttribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/DependsOnAttribute.cs similarity index 95% rename from src/Spring/Spring.Core/Context/Annotation/DependsOnAttribute.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/DependsOnAttribute.cs index 94f46207..ff8c220f 100644 --- a/src/Spring/Spring.Core/Context/Annotation/DependsOnAttribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/DependsOnAttribute.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { /// /// objects on which the current object depends. Any objects specified are guaranteed to be diff --git a/src/Spring/Spring.Core/Context/Annotation/ImportAttribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ImportAttribute.cs similarity index 95% rename from src/Spring/Spring.Core/Context/Annotation/ImportAttribute.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/ImportAttribute.cs index 9f01c55d..fa381774 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ImportAttribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ImportAttribute.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { /// /// Indicates one or more classes to import. diff --git a/src/Spring/Spring.Core/Context/Annotation/ImportResourceAttribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ImportResourceAttribute.cs similarity index 94% rename from src/Spring/Spring.Core/Context/Annotation/ImportResourceAttribute.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/ImportResourceAttribute.cs index 1b798e32..83fdc689 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ImportResourceAttribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ImportResourceAttribute.cs @@ -4,7 +4,7 @@ using System.Text; using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { /// /// diff --git a/src/Spring/Spring.Core/Context/Annotation/LazyAttrribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/LazyAttrribute.cs similarity index 95% rename from src/Spring/Spring.Core/Context/Annotation/LazyAttrribute.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/LazyAttrribute.cs index 1eba0cf4..99ba99b1 100644 --- a/src/Spring/Spring.Core/Context/Annotation/LazyAttrribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/LazyAttrribute.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { /// /// Indicates whether a object is to be lazily initialized. diff --git a/src/Spring/Spring.Core/Context/Annotation/PrimaryAttribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/PrimaryAttribute.cs similarity index 93% rename from src/Spring/Spring.Core/Context/Annotation/PrimaryAttribute.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/PrimaryAttribute.cs index 5e1b717f..f52187f2 100644 --- a/src/Spring/Spring.Core/Context/Annotation/PrimaryAttribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/PrimaryAttribute.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { /// /// Indicates that an object should be given preference when multiple candidates diff --git a/src/Spring/Spring.Core/Context/Annotation/ScopeAttribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ScopeAttribute.cs similarity index 94% rename from src/Spring/Spring.Core/Context/Annotation/ScopeAttribute.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/ScopeAttribute.cs index 6ac5d81e..7f0370f7 100644 --- a/src/Spring/Spring.Core/Context/Annotation/ScopeAttribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ScopeAttribute.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using Spring.Objects.Factory.Support; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { /// /// When used as a type-level attribute, indicates the name of a scope to use diff --git a/src/Spring/Spring.Core.Configuration/Properties/AssemblyInfo.cs b/src/Spring/Spring.Core.Configuration/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..1aee5470 --- /dev/null +++ b/src/Spring/Spring.Core.Configuration/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Spring.Core.Configuration")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("Spring.Core.Configuration")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("aa7c95ac-e82f-4c33-a857-76b179c34166")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj b/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj new file mode 100644 index 00000000..62e04478 --- /dev/null +++ b/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj @@ -0,0 +1,76 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {7B65D538-E863-4F57-8DDC-2C38E4150045} + Library + Properties + Spring + Spring.Core.Configuration + v2.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\lib\Net\2.0\Common.Logging.dll + + + + + + + + + + + + + + + + + + + + + + + + + {3A3A4E65-45A6-4B20-B460-0BEDC302C02C} + Spring.Aop.2010 + + + {710961A3-0DF4-49E4-A26E-F5B9C044AC84} + Spring.Core.2010 + + + + + \ No newline at end of file diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs index f4898c0a..292d4fc2 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; using System.Text; +using Spring.Objects.Factory.Config; namespace Spring.Objects.Factory.Support { - public interface IObjectDefinitionRegistryPostProcessor + public interface IObjectDefinitionRegistryPostProcessor : IObjectFactoryPostProcessor { void PostProcessObjectDefinitionRegistry(IObjectDefinitionRegistry registry); } diff --git a/src/Spring/Spring.Core/Spring.Core.2010.csproj b/src/Spring/Spring.Core/Spring.Core.2010.csproj index 1aab03b2..82436338 100644 --- a/src/Spring/Spring.Core/Spring.Core.2010.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2010.csproj @@ -171,19 +171,6 @@ Code - - - - - - - - - - - - - Code @@ -1274,6 +1261,7 @@ true + rem $(ProjectDir)..\..\..\build-support\tools\antlr-2.7.6\antlr-2.7.6.exe -o $(ProjectDir)Expressions\Parser $(ProjectDir)Expressions\Expression.g diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs new file mode 100644 index 00000000..50351b9b --- /dev/null +++ b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs @@ -0,0 +1,84 @@ +using System; +using NUnit.Framework; +using Spring.Context.Support; +using Spring.Objects.Factory.Support; +using Spring.Context.Attributes; + +namespace Spring.Context.Annotation +{ + [TestFixture] + public class ConfigurationClassPostProcessorTests + { + private GenericApplicationContext _ctx; + + private ConfigurationClassPostProcessor _postProcessor; + + [SetUp] + public void _SetUp() + { + _ctx = new GenericApplicationContext(); + + var builder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(ObjectDefinitions)); + _ctx.RegisterObjectDefinition("whoCares", builder.ObjectDefinition); + + _postProcessor = new ConfigurationClassPostProcessor(); + _postProcessor.PostProcessObjectDefinitionRegistry(_ctx); + } + + [Test] + public void CanRegisterDefintions() + { + Assert.That(_ctx.ObjectDefinitionCount, Is.EqualTo(3)); + } + + [Test] + public void CanRetreiveActualObjectsFromContext() + { + Assert.That(_ctx[typeof(Parent).Name], Is.TypeOf()); + Assert.That(_ctx[typeof(Child).Name], Is.TypeOf()); + } + + [Test] + public void CanSatisfyDependenciesOfObjects() + { + Assert.That(((Parent)_ctx[typeof(Parent).Name]).Child, Is.Not.Null); + } + + } + + [Configuration] + public class ObjectDefinitions + { + [Definition] + public Parent Parent() + { + return new Parent(Child()); + } + + [Definition] + public Child Child() + { + return new Child(); + } + } + + public class Parent + { + private Child _child; + + public Parent(Child child) + { + _child = child; + } + + public Child Child + { + get + { + return _child; + } + } + + } + public class Child { } +} diff --git a/test/Spring/Spring.Core.Configuration.Tests/Properties/AssemblyInfo.cs b/test/Spring/Spring.Core.Configuration.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..a1c1539d --- /dev/null +++ b/test/Spring/Spring.Core.Configuration.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Spring.Core.Configuration.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("Spring.Core.Configuration.Tests")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("65e12092-0586-435f-b9ef-e4a35c302bef")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj b/test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj new file mode 100644 index 00000000..f8a5b557 --- /dev/null +++ b/test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj @@ -0,0 +1,67 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {4F1A206C-09A8-43FF-B791-FE956E99A120} + Library + Properties + Spring.Core.Configuration.Tests + Spring.Core.Configuration.Tests + v2.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\lib\Net\2.0\nunit.framework.dll + + + + + + + + + + + + {3A3A4E65-45A6-4B20-B460-0BEDC302C02C} + Spring.Aop.2010 + + + {7B65D538-E863-4F57-8DDC-2C38E4150045} + Spring.Core.Configuration.2010 + + + {710961A3-0DF4-49E4-A26E-F5B9C044AC84} + Spring.Core.2010 + + + + + \ No newline at end of file From 55b169d06ccff257f1394681658a671ab0083432 Mon Sep 17 00:00:00 2001 From: sbohlen Date: Mon, 15 Nov 2010 20:35:54 +0000 Subject: [PATCH 04/11] container refresh modifications to interact with ConfigurationClassPostProcessor as required --- .../Advice/SpringObjectMethodInterceptor.cs | 92 ++++++++++++ .../Attributes/ConfigurationClassMethod.cs | 5 +- ...onfigurationClassObjectDefinitionReader.cs | 7 + .../ConfigurationClassPostProcessor.cs | 138 ++++++++++++------ .../Spring.Core.Configuration.2010.csproj | 1 + .../Support/AbstractApplicationContext.cs | 102 ++++++++++--- .../Objects/Factory/Parsing/Location.cs | 3 +- .../Objects/Factory/Parsing/Problem.cs | 2 +- .../ConfigurationClassPostProcessorTests.cs | 65 ++++++--- 9 files changed, 320 insertions(+), 95 deletions(-) create mode 100644 src/Spring/Spring.Core.Configuration/Context/Advice/SpringObjectMethodInterceptor.cs diff --git a/src/Spring/Spring.Core.Configuration/Context/Advice/SpringObjectMethodInterceptor.cs b/src/Spring/Spring.Core.Configuration/Context/Advice/SpringObjectMethodInterceptor.cs new file mode 100644 index 00000000..d3f3a5f0 --- /dev/null +++ b/src/Spring/Spring.Core.Configuration/Context/Advice/SpringObjectMethodInterceptor.cs @@ -0,0 +1,92 @@ +#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 + +using System; +using System.Reflection; +using AopAlliance.Intercept; +using Common.Logging; +using Spring.Objects.Factory.Config; +using Spring.Context.Attributes; + +namespace Spring.Context.Advice +{ + /// + /// Intercepts calls to methods within the configuration object + /// + /// Mark Pollack + /// Erich Eichinger + public class SpringObjectMethodInterceptor : IMethodInterceptor + { + #region Logging Definition + + private static readonly ILog LOG = LogManager.GetLogger(typeof(SpringObjectMethodInterceptor)); + + #endregion + + private readonly IConfigurableListableObjectFactory _configurableListableObjectFactory; + + + public SpringObjectMethodInterceptor(IConfigurableListableObjectFactory configurableListableObjectFactory) + { + _configurableListableObjectFactory = configurableListableObjectFactory; + + } + + #region IMethodInterceptor Members + + public object Invoke(IMethodInvocation invocation) + { + MethodInfo m = invocation.Method; + if (m.Name.StartsWith("set_") || m.Name.StartsWith("get_")) + return invocation.Proceed(); + + string name = m.Name; + + object[] attribs = m.GetCustomAttributes(typeof(DefinitionAttribute), true); + if (attribs.Length > 0) + { + + } + + + if (IsCurrentlyInCreation(name)) + { + if (LOG.IsDebugEnabled) + { + LOG.Debug(name + " currently in creation, created one."); + } + return invocation.Proceed(); + } + if (LOG.IsDebugEnabled) + { + LOG.Debug(name + " not in creation, asked the application context for one"); + } + + return _configurableListableObjectFactory.GetObject(name); + } + + private bool IsCurrentlyInCreation(string name) + { + return _configurableListableObjectFactory.IsCurrentlyInCreation(name); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs index 14a7aa78..36d629e0 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs @@ -85,7 +85,8 @@ namespace Spring.Context.Attributes public void Validate(IProblemReporter problemReporter) { - if (Attribute.GetCustomAttribute(ConfigurationClass.GetType(), typeof(ConfigurationAttribute)) != null) + //TODO: shouldn't this be "if method has Definition attribute" instead of "if class has Configuration attribute" --???? + if (Attribute.GetCustomAttribute(ConfigurationClass.ConfigurationClassType, typeof(ConfigurationAttribute)) != null) { if (!MethodMetadata.IsVirtual) { @@ -113,7 +114,7 @@ namespace Spring.Context.Attributes private class NonVirtualMethodError : Problem { public NonVirtualMethodError(string methodName, Location location) - : base(String.Format("Method '{0}' must not be private, final or static; change the method's modifiers to continue", + : base(String.Format("Method '{0}' must be public virtual; change the method's modifiers to continue", methodName), location) { } } diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs index e50b5a3e..21fd0423 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs @@ -7,6 +7,7 @@ using Spring.Collections.Generic; using System.Reflection; using Spring.Objects.Factory.Config; using Common.Logging; +using Spring.Objects; namespace Spring.Context.Attributes { @@ -90,9 +91,14 @@ namespace Spring.Context.Attributes RootObjectDefinition objDef = new ConfigurationClassObjectDefinition(); //beanDef.Resource = configClass.Resource; //beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource())); + + // ???? if we don't do this here, how is the type supposed to be set? + //objDef.ObjectType = metadata.ReturnType; + objDef.FactoryObjectName = configClass.ObjectName; objDef.FactoryMethodName = metadata.Name; objDef.AutowireMode = Objects.Factory.Config.AutoWiringMode.Constructor; + //beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE); // consider name and any aliases @@ -214,6 +220,7 @@ namespace Spring.Context.Attributes private class ConfigurationClassObjectDefinition : RootObjectDefinition { + } } diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs index f21fb73d..a1e425cc 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs @@ -8,6 +8,10 @@ using Spring.Objects.Factory.Config; using Spring.Collections.Generic; using Spring.Objects.Factory; using Spring.Core; +using Spring.Aop.Framework; +using Spring.Context.Advice; +using Spring.Aop.Framework.DynamicProxy; +using Spring.Aop; namespace Spring.Context.Attributes { @@ -21,13 +25,16 @@ namespace Spring.Context.Attributes private IProblemReporter _problemReporter = new FailFastProblemReporter(); + public int Order + { + get { return int.MinValue; } + } + public IProblemReporter ProblemReporter { set { _problemReporter = (value ?? new FailFastProblemReporter()); } } - - public void PostProcessObjectDefinitionRegistry(IObjectDefinitionRegistry registry) { if (_postProcessObjectDefinitionRegistryCalled) @@ -42,46 +49,6 @@ namespace Spring.Context.Attributes ProcessConfigObjectDefinitions(registry); } - - private Type GenerateProxyType(Type objectType) - { - /* - ProxyFactory proxyFactory = new ProxyFactory(); - proxyFactory.ProxyTargetAttributes = true; - proxyFactory.Interfaces = Type.EmptyTypes; - proxyFactory.TargetSource = new ObjectFactoryTargetSource(originalBeanName, owningObjectFactory); - SpringObjectMethodInterceptor methodInterceptor = new SpringObjectMethodInterceptor(owningObjectFactory, objectNamingStrategy); - proxyFactory.AddAdvice(methodInterceptor); - - //TODO check type of object isn't infrastructure type. - - InheritanceAopProxyTypeBuilder iaptb = new InheritanceAopProxyTypeBuilder(proxyFactory); - //iaptb.ProxyDeclaredMembersOnly = true; // make configurable. - Type type = iaptb.BuildProxyType(); - */ - - return null; - } - private void EnhanceConfigurationClasses(IConfigurableListableObjectFactory objectFactory) - { - string[] objectNames = objectFactory.GetObjectDefinitionNames(); - - for (int i = 0; i < objectNames.Length; i++) - { - IObjectDefinition objDef = objectFactory.GetObjectDefinition(objectNames[i]); - if (Attribute.GetCustomAttribute(objDef.ObjectType, typeof(ConfigurationAttribute)) != null) - { - //configNames.Add(objectNames[i]); - - //ObjectType is READONLY :( - //objDef.ObjectType = GenerateProxyType(objDef.ObjectType); - } - } - - - - - } public void PostProcessObjectFactory(IConfigurableListableObjectFactory objectFactory) { if (_postProcessObjectFactoryCalled) @@ -96,10 +63,60 @@ namespace Spring.Context.Attributes // Simply call processConfigBeanDefinitions lazily at this point then. ProcessConfigObjectDefinitions((IObjectDefinitionRegistry)objectFactory); } - + EnhanceConfigurationClasses(objectFactory); } + private void EnhanceConfigurationClasses(IConfigurableListableObjectFactory objectFactory) + { + string[] objectNames = objectFactory.GetObjectDefinitionNames(); + + for (int i = 0; i < objectNames.Length; i++) + { + IObjectDefinition objDef = objectFactory.GetObjectDefinition(objectNames[i]); + + if (((AbstractObjectDefinition)objDef).HasObjectType) + { + if (Attribute.GetCustomAttribute(objDef.ObjectType, typeof(ConfigurationAttribute)) != null) + { + + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.ProxyTargetAttributes = true; + proxyFactory.Interfaces = Type.EmptyTypes; + proxyFactory.TargetSource = new ObjectFactoryTargetSource(objectNames[i], objectFactory); + SpringObjectMethodInterceptor methodInterceptor = new SpringObjectMethodInterceptor(objectFactory); + proxyFactory.AddAdvice(methodInterceptor); + + //TODO check type of object isn't infrastructure type. + + InheritanceAopProxyTypeBuilder iaptb = new InheritanceAopProxyTypeBuilder(proxyFactory); + //iaptb.ProxyDeclaredMembersOnly = true; // make configurable. + ((IConfigurableObjectDefinition)objDef).ObjectType = iaptb.BuildProxyType(); + + objDef.ConstructorArgumentValues.AddIndexedArgumentValue(objDef.ConstructorArgumentValues.ArgumentCount, proxyFactory); + + } + } + + } + + } + + private Type GenerateProxyType(string objectName, IConfigurableListableObjectFactory objectFactory) + { + ProxyFactory proxyFactory = new ProxyFactory(); + proxyFactory.ProxyTargetAttributes = true; + proxyFactory.Interfaces = Type.EmptyTypes; + proxyFactory.TargetSource = new ObjectFactoryTargetSource(objectName, objectFactory); + SpringObjectMethodInterceptor methodInterceptor = new SpringObjectMethodInterceptor(objectFactory); + proxyFactory.AddAdvice(methodInterceptor); + + //TODO check type of object isn't infrastructure type. + + InheritanceAopProxyTypeBuilder iaptb = new InheritanceAopProxyTypeBuilder(proxyFactory); + //iaptb.ProxyDeclaredMembersOnly = true; // make configurable. + return iaptb.BuildProxyType(); + } private void ProcessConfigObjectDefinitions(IObjectDefinitionRegistry registry) { @@ -143,10 +160,39 @@ namespace Spring.Context.Attributes reader.LoadObjectDefinitions(parser.ConfigurationClasses); } - - public int Order + public class ObjectFactoryTargetSource : ITargetSource { - get { return int.MinValue; } + private readonly string _objectName; + private readonly IConfigurableListableObjectFactory _objectFactory; + + public ObjectFactoryTargetSource(string objectName, IConfigurableListableObjectFactory objectFactory) + { + _objectName = objectName; + _objectFactory = objectFactory; + } + + #region ITargetSource Members + + public object GetTarget() + { + return _objectFactory.GetObject(_objectName); + } + + public bool IsStatic + { + get { return _objectFactory.IsSingleton(_objectName); } + } + + public void ReleaseTarget(object target) + { + } + + public Type TargetType + { + get { return _objectFactory.GetType(_objectName); } + } + + #endregion } } } diff --git a/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj b/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj index 62e04478..b5a72565 100644 --- a/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj +++ b/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj @@ -39,6 +39,7 @@ + diff --git a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs index ce8e612b..1f8dbc4d 100644 --- a/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs +++ b/src/Spring/Spring.Core/Context/Support/AbstractApplicationContext.cs @@ -406,7 +406,7 @@ namespace Spring.Context.Support if (exceptions.HasExceptions) { Delegate target = ContextEvent.GetInvocationList()[0]; - Exception exception = (Exception) exceptions[target]; + Exception exception = (Exception)exceptions[target]; throw new ApplicationContextException(string.Format("An unhandled exception occured during processing application event {0} in handler {1}", e.GetType(), target.Method), exception); } } @@ -487,33 +487,92 @@ namespace Spring.Context.Support /// /// /// In the case of errors. - private void InvokeObjectFactoryPostProcessors() + private void InvokeObjectFactoryPostProcessors(IConfigurableListableObjectFactory objectFactory) { - // Do NOT include IFactoryObjects; they (typically) need to be instantiated - // to determine the Type of object that they create, and if they are instantiated - // then we won't be able to do any factory post processin' on 'em... - ArrayList factoryProcessorNames = new ArrayList(); - string[] names = GetObjectNamesForType(typeof (IObjectFactoryPostProcessor), true, false); - foreach (string s in names) + // Invoke BeanDefinitionRegistryPostProcessors first, if any. + ArrayList processedObjects = new ArrayList(); + + if (objectFactory is IObjectDefinitionRegistry) { - factoryProcessorNames.Add(s); + IObjectDefinitionRegistry registry = (IObjectDefinitionRegistry)objectFactory; + ArrayList regularPostProcessors = new ArrayList(); + ArrayList registryPostProcessors = new ArrayList(); + + foreach (IObjectFactoryPostProcessor factoryProcessor in ObjectFactoryPostProcessors) + { + if (factoryProcessor is IObjectDefinitionRegistryPostProcessor) + { + ((IObjectDefinitionRegistryPostProcessor)factoryProcessor).PostProcessObjectDefinitionRegistry(registry); + registryPostProcessors.Add(factoryProcessor); + } + else + { + regularPostProcessors.Add(factoryProcessor); + } + } + + IDictionary objectMap = objectFactory.GetObjectsOfType(typeof(IObjectDefinitionRegistryPostProcessor), true, false); + + ArrayList registryPostProcessorObjects = new ArrayList(objectMap.Values); + registryPostProcessorObjects.Sort(new OrderComparator()); + + foreach (System.Object processor in registryPostProcessorObjects) + { + ((IObjectDefinitionRegistryPostProcessor)processor).PostProcessObjectDefinitionRegistry(registry); + } + + InvokeObjectFactoryPostProcessors(registryPostProcessors, objectFactory); + InvokeObjectFactoryPostProcessors(registryPostProcessorObjects, objectFactory); + InvokeObjectFactoryPostProcessors(regularPostProcessors, objectFactory); + + // processedObjects.Add(objectMap.Keys); + + foreach (DictionaryEntry entry in objectMap) + { + processedObjects.Add(entry.Key); + } + } - + else + { + foreach (IObjectFactoryPostProcessor factoryProcessor in ObjectFactoryPostProcessors) + { + // Invoke factory processors registered with the context instance. + factoryProcessor.PostProcessObjectFactory(objectFactory); + } + } + + // Do not initialize FactoryBeans here: We need to leave all regular beans + // uninitialized to let the bean factory post-processors apply to them! + ArrayList factoryProcessorNames = new ArrayList(); + string[] names = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false); + foreach (string name in names) + { + factoryProcessorNames.Add(name); + } + + // Separate between ObjectFactoryPostProcessors that implement PriorityOrdered, + // Ordered, and the rest. ArrayList priorityOrderedFactoryProcessors = new ArrayList(); ArrayList orderedFactoryProcessorsNames = new ArrayList(); ArrayList nonOrderedFactoryProcessorNames = new ArrayList(); - + for (int i = 0; i < factoryProcessorNames.Count; ++i) { - string processorName = (string) factoryProcessorNames[i]; - if (IsTypeMatch(processorName, typeof(IPriorityOrdered))) + string processorName = (string)factoryProcessorNames[i]; + if (processedObjects.Contains(processorName)) + { + //skip -- already processed in first phase above + Debug.WriteLine(""); + } + else if (IsTypeMatch(processorName, typeof(IPriorityOrdered))) { priorityOrderedFactoryProcessors.Add(ObjectFactory.GetObject(processorName, typeof(IObjectFactoryPostProcessor))); } else if (IsTypeMatch(processorName, typeof(IOrdered))) { orderedFactoryProcessorsNames.Add(processorName); - } + } else { nonOrderedFactoryProcessorNames.Add(processorName); @@ -527,17 +586,17 @@ namespace Spring.Context.Support foreach (string orderedFactoryProcessorsName in orderedFactoryProcessorsNames) { orderedFactoryProcessors.Add(ObjectFactory.GetObject(orderedFactoryProcessorsName, - typeof (IObjectFactoryPostProcessor))); + typeof(IObjectFactoryPostProcessor))); } orderedFactoryProcessors.Sort(new OrderComparator()); InvokeObjectFactoryPostProcessors(orderedFactoryProcessors, ObjectFactory); - + // and then the unordered ones... ArrayList nonOrderedPostProcessors = new ArrayList(); foreach (string nonOrderedFactoryProcessorName in nonOrderedFactoryProcessorNames) { nonOrderedPostProcessors.Add(ObjectFactory.GetObject(nonOrderedFactoryProcessorName, - typeof (IObjectFactoryPostProcessor))); + typeof(IObjectFactoryPostProcessor))); } InvokeObjectFactoryPostProcessors(nonOrderedPostProcessors, ObjectFactory); @@ -563,7 +622,7 @@ namespace Spring.Context.Support // Now will find any additional IObjectFactoryPostProcessors that implement IPriorityOrdered that may have been // resolved due to using TypeAlias string[] factoryProcessorNamesAfterTypeAlias = GetObjectNamesForType(typeof(IObjectFactoryPostProcessor), true, false); - priorityOrderedFactoryProcessors.Clear(); + priorityOrderedFactoryProcessors.Clear(); foreach (string factoryProcessorName in factoryProcessorNamesAfterTypeAlias) { if (!factoryProcessorNames.Contains(factoryProcessorName)) @@ -912,10 +971,7 @@ namespace Spring.Context.Support #endregion - foreach (IObjectFactoryPostProcessor factoryProcessor in ObjectFactoryPostProcessors) - { - factoryProcessor.PostProcessObjectFactory(objectFactory); - } + #region Instrumentation @@ -939,7 +995,7 @@ namespace Spring.Context.Support #endregion - InvokeObjectFactoryPostProcessors(); + InvokeObjectFactoryPostProcessors(objectFactory); RegisterObjectPostProcessors(objectFactory); InitEventRegistry(); diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs index 48832944..6ca9a321 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs @@ -18,7 +18,8 @@ namespace Spring.Objects.Factory.Parsing /// public Location(IResource resource, object source) { - AssertUtils.ArgumentNotNull(resource, "resource"); + //TODO: look into re-enabling this since resource *is* NULL when parsing config classes vs. acquiring IResources + //AssertUtils.ArgumentNotNull(resource, "resource"); this.resource = resource; this.source = source; } diff --git a/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs b/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs index 0848261a..7fa96f46 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs @@ -59,7 +59,7 @@ namespace Spring.Objects.Factory.Parsing public string ResourceDescription { - get { return _location.Resource.Description; } + get { return _location.Resource!=null ? _location.Resource.Description : string.Empty; } } public override string ToString() diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs index 50351b9b..b01740ff 100644 --- a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs +++ b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs @@ -11,67 +11,87 @@ namespace Spring.Context.Annotation { private GenericApplicationContext _ctx; - private ConfigurationClassPostProcessor _postProcessor; - [SetUp] public void _SetUp() { _ctx = new GenericApplicationContext(); - var builder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(ObjectDefinitions)); + var builder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(TheConfigurationClass)); _ctx.RegisterObjectDefinition("whoCares", builder.ObjectDefinition); - _postProcessor = new ConfigurationClassPostProcessor(); - _postProcessor.PostProcessObjectDefinitionRegistry(_ctx); + var b2 = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(ConfigurationClassPostProcessor)); + _ctx.RegisterObjectDefinition("ccpp", b2.ObjectDefinition); + + _ctx.Refresh(); } [Test] - public void CanRegisterDefintions() + public void Can_Parse_and_Register_Defintions() { - Assert.That(_ctx.ObjectDefinitionCount, Is.EqualTo(3)); + Assert.That(_ctx.ObjectDefinitionCount, Is.EqualTo(4)); } [Test] - public void CanRetreiveActualObjectsFromContext() + public void Can_Retreive_Actual_Objects_From_Context() { - Assert.That(_ctx[typeof(Parent).Name], Is.TypeOf()); - Assert.That(_ctx[typeof(Child).Name], Is.TypeOf()); + Assert.That(_ctx[typeof(SingletonParent).Name], Is.TypeOf()); + Assert.That(_ctx[typeof(PrototypeChild).Name], Is.TypeOf()); } [Test] - public void CanSatisfyDependenciesOfObjects() + public void Can_Satisfy_Dependencies_Of_Objects() { - Assert.That(((Parent)_ctx[typeof(Parent).Name]).Child, Is.Not.Null); + Assert.That(((SingletonParent)_ctx[typeof(SingletonParent).Name]).Child, Is.Not.Null); + } + + [Test] + public void Can_Respect_Default_Singleton_Scope() + { + var firstObject = (SingletonParent)_ctx[typeof(SingletonParent).Name]; + var secondObject = (SingletonParent)_ctx[typeof(SingletonParent).Name]; + + Assert.That(firstObject, Is.SameAs(secondObject)); + } + + [Test] + public void Can_Respect_Explicit_PrototypeScope() + { + var firstObject = (PrototypeChild)_ctx[typeof(PrototypeChild).Name]; + var secondObject = (PrototypeChild)_ctx[typeof(PrototypeChild).Name]; + + Assert.That(firstObject, Is.Not.SameAs(secondObject)); } } [Configuration] - public class ObjectDefinitions + public class TheConfigurationClass { [Definition] - public Parent Parent() + [Scope(ObjectScope.Prototype)] + public virtual PrototypeChild PrototypeChild() { - return new Parent(Child()); + return new PrototypeChild(); } [Definition] - public Child Child() + public virtual SingletonParent SingletonParent() { - return new Child(); + return new SingletonParent(PrototypeChild()); } + } - public class Parent + public class SingletonParent { - private Child _child; + private PrototypeChild _child; - public Parent(Child child) + public SingletonParent(PrototypeChild child) { _child = child; } - public Child Child + public PrototypeChild Child { get { @@ -80,5 +100,6 @@ namespace Spring.Context.Annotation } } - public class Child { } + + public class PrototypeChild { } } From 85af8a1d8fa321d7c66e90d5663a2159b96f413e Mon Sep 17 00:00:00 2001 From: sbohlen Date: Fri, 19 Nov 2010 14:40:12 +0000 Subject: [PATCH 05/11] additional tests introduced; minor mods to attribute classes to support better syntax for setting values --- .../Context/Attributes/ConfigurationClass.cs | 4 +- .../Attributes/ConfigurationClassMethod.cs | 4 +- ...onfigurationClassObjectDefinitionReader.cs | 81 +++++----- .../Attributes/ConfigurationClassParser.cs | 10 +- .../ConfigurationClassPostProcessor.cs | 6 +- .../Context/Attributes/DefinitionAttribute.cs | 27 +++- .../Attributes/ImportResourceAttribute.cs | 35 ++++- .../{LazyAttrribute.cs => LazyAttribute.cs} | 14 +- .../Context/Config/ContextNamespaceParser.cs | 46 ++++++ .../Spring.Core.Configuration.2010.csproj | 11 +- .../Spring.Aop.Tests.2010.csproj | 4 +- .../ConfigurationClassPostProcessorTests.cs | 138 ++++++++++++++++-- .../Attributes/DefinitionAttributeTests.cs | 38 +++++ .../ImportResourceAttributeTests.cs | 48 ++++++ .../Context/Attributes/ObjectDefinitions.xml | 5 + ...pring.Core.Configuration.Tests.2010.csproj | 20 ++- 16 files changed, 406 insertions(+), 85 deletions(-) rename src/Spring/Spring.Core.Configuration/Context/Attributes/{LazyAttrribute.cs => LazyAttribute.cs} (82%) create mode 100644 src/Spring/Spring.Core.Configuration/Context/Config/ContextNamespaceParser.cs create mode 100644 test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/DefinitionAttributeTests.cs create mode 100644 test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ImportResourceAttributeTests.cs create mode 100644 test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ObjectDefinitions.xml diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClass.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClass.cs index 8c22c382..3f0cade0 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClass.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClass.cs @@ -96,8 +96,8 @@ namespace Spring.Context.Attributes public void Validate(IProblemReporter problemReporter) { - // An @Bean method may only be overloaded through inheritance. No single - // @Configuration class may declare two @Bean methods with the same name. + // A [Definition] method may only be overloaded through inheritance. No single + // [Configuration] class may declare two [Definition] methods with the same name. char hashDelim = '#'; Dictionary methodNameCounts = new Dictionary(); foreach (ConfigurationClassMethod method in _methods) diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs index 36d629e0..ecb49b02 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassMethod.cs @@ -29,14 +29,14 @@ namespace Spring.Context.Attributes { /** - * Represents a {@link Configuration} class method marked with the {@link Bean} annotation. + * Represents a {@link Configuration} class method marked with the {@link Object} annotation. * * @author Chris Beams * @author Juergen Hoeller * @since 3.0 * @see ConfigurationClass * @see ConfigurationClassParser - * @see ConfigurationClassBeanDefinitionReader + * @see ConfigurationClassObjectDefinitionReader */ public class ConfigurationClassMethod diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs index 21fd0423..df7517b5 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassObjectDefinitionReader.cs @@ -8,6 +8,7 @@ using System.Reflection; using Spring.Objects.Factory.Config; using Common.Logging; using Spring.Objects; +using Spring.Util; namespace Spring.Context.Attributes { @@ -52,17 +53,17 @@ namespace Spring.Context.Attributes { if (configClass.ObjectName != null) { - // a bean definition already exists for this configuration class -> nothing to do + // a Object definition already exists for this configuration class -> nothing to do return; } - // no bean definition exists yet -> this must be an imported configuration class (@Import). - GenericObjectDefinition configBeanDef = new GenericObjectDefinition(); + // no Object definition exists yet -> this must be an imported configuration class (@Import). + GenericObjectDefinition configObjectDef = new GenericObjectDefinition(); String className = configClass.ConfigurationClassType.Name; - configBeanDef.ObjectType = configClass.GetType(); + configObjectDef.ObjectType = configClass.ConfigurationClassType; if (CheckConfigurationClassCandidate(configClass.ConfigurationClassType)) { - String configObjectName = ObjectDefinitionReaderUtils.RegisterWithGeneratedName(configBeanDef, _registry); + String configObjectName = ObjectDefinitionReaderUtils.RegisterWithGeneratedName(configObjectDef, _registry); configClass.ObjectName = configObjectName; if (_logger.IsDebugEnabled) { @@ -89,34 +90,38 @@ namespace Spring.Context.Attributes MethodInfo metadata = method.MethodMetadata; RootObjectDefinition objDef = new ConfigurationClassObjectDefinition(); - //beanDef.Resource = configClass.Resource; - //beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource())); - - // ???? if we don't do this here, how is the type supposed to be set? - //objDef.ObjectType = metadata.ReturnType; - + //ObjectDef.Resource = configClass.Resource; + //ObjectDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource())); + + + objDef.FactoryObjectName = configClass.ObjectName; objDef.FactoryMethodName = metadata.Name; objDef.AutowireMode = Objects.Factory.Config.AutoWiringMode.Constructor; - - //beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE); + + //ObjectDef.setAttribute(RequiredAnnotationObjectPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE); // consider name and any aliases - //Dictionary beanAttributes = metadata.getAnnotationAttributes(Bean.class.getName()); + //Dictionary ObjectAttributes = metadata.getAnnotationAttributes(Object.class.getName()); object[] objectAttributes = metadata.GetCustomAttributes(typeof(DefinitionAttribute), true); List names = new List(); for (int i = 0; i < objectAttributes.Length; i++) { - string[] namesAndAliases = ((DefinitionAttribute)objectAttributes[i]).Name; + string[] namesAndAliases = ((DefinitionAttribute)objectAttributes[i]).NamesToArray; - if (namesAndAliases == null) + if (namesAndAliases != null) + { + names.Add(metadata.Name); + } + else + { namesAndAliases = new[] { metadata.Name }; + } - for (int j = 0; j > namesAndAliases.Length; j++) + for (int j = 0; j < namesAndAliases.Length; j++) { names.Add(namesAndAliases[j]); } - } string objectName = (names.Count > 0 ? names[0] : method.MethodMetadata.Name); @@ -128,15 +133,15 @@ namespace Spring.Context.Attributes // has this already been overridden (e.g. via XML)? if (_registry.ContainsObjectDefinition(objectName)) { - IObjectDefinition existingBeanDef = _registry.GetObjectDefinition(objectName); - // is the existing bean definition one that was created from a configuration class? - if (!(existingBeanDef is ConfigurationClassObjectDefinition)) + IObjectDefinition existingObjectDef = _registry.GetObjectDefinition(objectName); + // is the existing Object definition one that was created from a configuration class? + if (!(existingObjectDef is ConfigurationClassObjectDefinition)) { // no -> then it's an external override, probably XML // overriding is legal, return immediately if (_logger.IsDebugEnabled) { - _logger.Debug(String.Format("Skipping loading bean definition for {0}: a definition for object " + + _logger.Debug(String.Format("Skipping loading Object definition for {0}: a definition for object " + "'{1}' already exists. This is likely due to an override in XML.", method, objectName)); } return; @@ -146,13 +151,13 @@ namespace Spring.Context.Attributes if (Attribute.GetCustomAttribute(metadata, typeof(PrimaryAttribute)) != null) { //TODO: determine how to respond to this attribute's presence - //beanDef.isPrimary = true; + //ObjectDef.isPrimary = true; } - // is this bean to be instantiated lazily? - if (Attribute.GetCustomAttribute(metadata, typeof(LazyAttrribute)) != null) + // is this Object to be instantiated lazily? + if (Attribute.GetCustomAttribute(metadata, typeof(LazyAttribute)) != null) { - objDef.IsLazyInit = (Attribute.GetCustomAttribute(metadata, typeof(LazyAttrribute)) as LazyAttrribute).LazyInitialize; + objDef.IsLazyInit = (Attribute.GetCustomAttribute(metadata, typeof(LazyAttribute)) as LazyAttribute).LazyInitialize; } if (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) != null) @@ -160,20 +165,16 @@ namespace Spring.Context.Attributes objDef.DependsOn = (Attribute.GetCustomAttribute(metadata, typeof(DependsOnAttribute)) as DependsOnAttribute).Name; } - //Autowire autowire = (Autowire) beanAttributes.get("autowire"); + //Autowire autowire = (Autowire) ObjectAttributes.get("autowire"); //if (autowire.isAutowire()) { - // beanDef.setAutowireMode(autowire.value()); + // ObjectDef.setAutowireMode(autowire.value()); //} - //String initMethodName = (String) beanAttributes.get("initMethod"); - //if (StringUtils.hasText(initMethodName)) { - // beanDef.setInitMethodName(initMethodName); - //} - - //String destroyMethodName = (String) beanAttributes.get("destroyMethod"); - //if (StringUtils.hasText(destroyMethodName)) { - // beanDef.setDestroyMethodName(destroyMethodName); - //} + if (Attribute.GetCustomAttribute(metadata, typeof(DefinitionAttribute)) != null) + { + objDef.InitMethodName = (Attribute.GetCustomAttribute(metadata, typeof(DefinitionAttribute)) as DefinitionAttribute).InitMethod; + objDef.DestroyMethodName = (Attribute.GetCustomAttribute(metadata, typeof(DefinitionAttribute)) as DefinitionAttribute).DestroyMethod; + } // consider scoping if (Attribute.GetCustomAttribute(metadata, typeof(ScopeAttribute)) != null) @@ -183,7 +184,7 @@ namespace Spring.Context.Attributes if (_logger.IsDebugEnabled) { - _logger.Debug(String.Format("Registering bean definition for [Definition] method {0}.{1}()", configClass.ConfigurationClassType.Name, objectName)); + _logger.Debug(String.Format("Registering Object definition for [Definition] method {0}.{1}()", configClass.ConfigurationClassType.Name, objectName)); } _registry.RegisterObjectDefinition(objectName, objDef); @@ -201,8 +202,8 @@ namespace Spring.Context.Attributes { try { - IObjectDefinitionReader readerInstance = - (IObjectDefinitionReader)Activator.CreateInstance(readerClass.GetType(), _registry); + IObjectDefinitionReader readerInstance = + (IObjectDefinitionReader)Activator.CreateInstance(readerClass, _registry); readerInstanceCache.Add(readerClass, readerInstance); } diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassParser.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassParser.cs index 04c907f4..c6091d96 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassParser.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassParser.cs @@ -31,9 +31,9 @@ namespace Spring.Context.Attributes get { return _configurationClasses; } } - //public void Parse(String className, String beanName) + //public void Parse(String className, String ObjectName) //{ - // ProcessConfigurationClass(new ConfigurationClass(className, beanName)); + // ProcessConfigurationClass(new ConfigurationClass(className, ObjectName)); //} public void Parse(Type type, string objectName) @@ -66,17 +66,17 @@ namespace Spring.Context.Attributes { if (Attribute.GetCustomAttribute(configurationClass.ConfigurationClassType, typeof(ImportAttribute)) != null) { - ImportAttribute attrib = Attribute.GetCustomAttribute(configurationClass.ConfigurationClassType.GetType(), typeof(ImportAttribute)) as ImportAttribute; + ImportAttribute attrib = Attribute.GetCustomAttribute(configurationClass.ConfigurationClassType, typeof(ImportAttribute)) as ImportAttribute; ProcessImport(configurationClass, attrib.Types); } if (Attribute.GetCustomAttribute(configurationClass.ConfigurationClassType, typeof(ImportResourceAttribute)) != null) { - ImportResourceAttribute attrib = Attribute.GetCustomAttribute(configurationClass.ConfigurationClassType.GetType(), typeof(ImportResourceAttribute)) as ImportResourceAttribute; + ImportResourceAttribute attrib = Attribute.GetCustomAttribute(configurationClass.ConfigurationClassType, typeof(ImportResourceAttribute)) as ImportResourceAttribute; foreach (string resource in attrib.Resources) { - configurationClass.AddImportedResource(resource, attrib.DefinitionReader.GetType()); + configurationClass.AddImportedResource(resource, attrib.DefinitionReader); } } diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs index a1e425cc..54210c4a 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ConfigurationClassPostProcessor.cs @@ -59,8 +59,8 @@ namespace Spring.Context.Attributes _postProcessObjectFactoryCalled = true; if (!_postProcessObjectDefinitionRegistryCalled) { - // BeanDefinitionRegistryPostProcessor hook apparently not supported... - // Simply call processConfigBeanDefinitions lazily at this point then. + // ObjectDefinitionRegistryPostProcessor hook apparently not supported... + // Simply call processConfigObjectDefinitions lazily at this point then. ProcessConfigObjectDefinitions((IObjectDefinitionRegistry)objectFactory); } @@ -155,7 +155,7 @@ namespace Spring.Context.Attributes } parser.Validate(); - // Read the model and create bean definitions based on its content + // Read the model and create Object definitions based on its content ConfigurationClassObjectDefinitionReader reader = new ConfigurationClassObjectDefinitionReader(registry, _problemReporter); reader.LoadObjectDefinitions(parser.ConfigurationClasses); } diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/DefinitionAttribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/DefinitionAttribute.cs index 39efce04..93086cec 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/DefinitionAttribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/DefinitionAttribute.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using Spring.Objects.Factory.Config; +using Spring.Util; namespace Spring.Context.Attributes { @@ -10,9 +11,11 @@ namespace Spring.Context.Attributes { private AutoWiringMode _autoWire = AutoWiringMode.No; + private string _destroyMethod; + private string _initMethod; - private string[] _name; + private string _names; /// /// Are dependencies to be injected via autowiring? @@ -26,9 +29,9 @@ namespace Spring.Context.Attributes _autoWire = value; } } - private string _destroyMethod; + /// - /// The optional name of a method to call on the bean instance upon closing the + /// The optional name of a method to call on the Object instance upon closing the /// application context, for example a Close() method on a DataSource. /// The method must have no arguments but may throw any exception. /// @@ -47,11 +50,11 @@ namespace Spring.Context.Attributes _destroyMethod = value; } } - + /// /// The optional name of a method to call on the object instance during initialization. /// Not commonly used, given that the method may be called programmatically directly - /// within the body of a Bean-annotated method. + /// within the body of a Object-annotated method. /// /// The init method. public string InitMethod @@ -69,15 +72,23 @@ namespace Spring.Context.Attributes /// name is ignored. /// /// The name. - public string[] Name + public string Names { get { - return _name; + return _names; } set { - _name = value; + _names = value; + } + } + + public string[] NamesToArray + { + get + { + return StringUtils.DelimitedListToStringArray(_names, ","); } } diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/ImportResourceAttribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/ImportResourceAttribute.cs index 83fdc689..241ace48 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/ImportResourceAttribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/ImportResourceAttribute.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Text; using Spring.Objects.Factory.Support; using Spring.Objects.Factory.Xml; +using Spring.Util; namespace Spring.Context.Attributes { @@ -12,31 +13,51 @@ namespace Spring.Context.Attributes [AttributeUsage(AttributeTargets.Class)] public class ImportResourceAttribute : Attribute { - private IObjectDefinitionReader _objectDefinitionReader; + private Type _objectDefinitionReader = typeof(XmlObjectDefinitionReader); private string[] _resources; /// - /// Initializes a new instance of the ImportResource class. + /// Initializes a new instance of the ImportResourceAttribute class. /// - /// /// - public ImportResourceAttribute(IObjectDefinitionReader objectDefinitionReader, string[] resources) + public ImportResourceAttribute(string[] resources) { - _objectDefinitionReader = objectDefinitionReader; + if (resources ==null || resources.Length ==0) + throw new ArgumentException("resources cannot be null or empty!"); + _resources = resources; } + + /// + /// Initializes a new instance of the ImportResourceAttribute class. + /// + /// + public ImportResourceAttribute(string resource) + { + if (StringUtils.IsNullOrEmpty(resource)) + throw new ArgumentException("resource cannot be null or empty!"); + + _resources = new[] { resource }; + } + /// /// implementation to use when processing resources specified /// by the attribute. /// /// The . - public IObjectDefinitionReader DefinitionReader + public Type DefinitionReader { - get { return _objectDefinitionReader; } + get + { + return _objectDefinitionReader; + } set { + if (!((typeof(IObjectDefinitionReader).IsAssignableFrom(value)))) + throw new ArgumentException(string.Format("DefinitionReader must be of type IObjectDefinitionReader but was of type {0}", value.Name)); + _objectDefinitionReader = value; } } diff --git a/src/Spring/Spring.Core.Configuration/Context/Attributes/LazyAttrribute.cs b/src/Spring/Spring.Core.Configuration/Context/Attributes/LazyAttribute.cs similarity index 82% rename from src/Spring/Spring.Core.Configuration/Context/Attributes/LazyAttrribute.cs rename to src/Spring/Spring.Core.Configuration/Context/Attributes/LazyAttribute.cs index 99ba99b1..229f4d72 100644 --- a/src/Spring/Spring.Core.Configuration/Context/Attributes/LazyAttrribute.cs +++ b/src/Spring/Spring.Core.Configuration/Context/Attributes/LazyAttribute.cs @@ -23,19 +23,27 @@ namespace Spring.Context.Attributes /// /// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] - public class LazyAttrribute : Attribute + public class LazyAttribute : Attribute { private bool _lazyInitialize = true; /// - /// Initializes a new instance of the Lazy class. + /// Initializes a new instance of the LazyAttribute class. /// /// - public LazyAttrribute(bool lazyInitialize) + public LazyAttribute(bool lazyInitialize) { _lazyInitialize = lazyInitialize; } + /// + /// Initializes a new instance of the LazyAttribute class. + /// + public LazyAttribute() + { + + } + /// /// Whether lazy initialization should occur. /// diff --git a/src/Spring/Spring.Core.Configuration/Context/Config/ContextNamespaceParser.cs b/src/Spring/Spring.Core.Configuration/Context/Config/ContextNamespaceParser.cs new file mode 100644 index 00000000..d385c84a --- /dev/null +++ b/src/Spring/Spring.Core.Configuration/Context/Config/ContextNamespaceParser.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spring.Objects.Factory.Xml; + +namespace Spring.Context.Config +{ + /// + /// NamespaceParser allowing for the configuration of + /// declarative transaction management using either XML or using attributes. + /// + /// This namespace handler is the central piece of functionality in the + /// Spring transaction management facilities and offers two appraoches + /// to declaratively manage transactions. + /// + /// One approach uses transaction semantics defined in XML using the + /// <tx:advice> elements, the other uses attributes + /// in combination with the <tx:annotation-driven> element. + /// Both approached are detailed in the Spring reference manual. + /// + [ + NamespaceParser( + Namespace = "http://www.springframework.net/context", + SchemaLocationAssemblyHint = typeof(ContextNamespaceParser), + SchemaLocation = "/Spring.Context.Config/spring-context-1.3.xsd" + ) + ] + public class ContextNamespaceParser : NamespaceParserSupport + { + + + /// + /// Register the for the 'advice' and + /// 'attribute-driven' tags. + /// + public override void Init() + { + + + RegisterObjectDefinitionParser("attribute-config", new AttributeConfigObjectDefinitionParser()); + + //RegisterObjectDefinitionParser("component-scan", new ComponentScanObjectDefinitionParser()); + + } + } +} diff --git a/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj b/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj index b5a72565..422d636c 100644 --- a/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj +++ b/src/Spring/Spring.Core.Configuration/Spring.Core.Configuration.2010.csproj @@ -50,12 +50,19 @@ - + + + + - + + + Designer + + {3A3A4E65-45A6-4B20-B460-0BEDC302C02C} diff --git a/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2010.csproj b/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2010.csproj index e697c97d..6f8972ab 100644 --- a/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2010.csproj +++ b/test/Spring/Spring.Aop.Tests/Spring.Aop.Tests.2010.csproj @@ -277,7 +277,9 @@ - + + Designer + diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs index b01740ff..d1894cf7 100644 --- a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs +++ b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs @@ -3,8 +3,10 @@ using NUnit.Framework; using Spring.Context.Support; using Spring.Objects.Factory.Support; using Spring.Context.Attributes; +using Spring.Objects.Factory.Config; +using Spring.Objects.Factory.Xml; -namespace Spring.Context.Annotation +namespace Spring.Context.Attributes { [TestFixture] public class ConfigurationClassPostProcessorTests @@ -17,31 +19,46 @@ namespace Spring.Context.Annotation _ctx = new GenericApplicationContext(); var builder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(TheConfigurationClass)); - _ctx.RegisterObjectDefinition("whoCares", builder.ObjectDefinition); + _ctx.RegisterObjectDefinition("theConfigClass", builder.ObjectDefinition); var b2 = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(ConfigurationClassPostProcessor)); - _ctx.RegisterObjectDefinition("ccpp", b2.ObjectDefinition); + _ctx.RegisterObjectDefinition("thePostProcessor", b2.ObjectDefinition); + + Assert.That(_ctx.ObjectDefinitionCount, Is.EqualTo(2)); _ctx.Refresh(); } [Test] - public void Can_Parse_and_Register_Defintions() + public void Can_Assign_Init_And_Destroy_Methods() { - Assert.That(_ctx.ObjectDefinitionCount, Is.EqualTo(4)); + IObjectDefinition def = _ctx.GetObjectDefinition(typeof(ObjectWithInitAndDestroyMethods).Name); + + Assert.That(def, Is.Not.Null); + Assert.That(def.InitMethodName, Is.EqualTo("CallToInit")); + Assert.That(def.DestroyMethodName, Is.EqualTo("CallToDestroy")); } [Test] - public void Can_Retreive_Actual_Objects_From_Context() + public void Can_Import_Configurations_From_Additional_Classes() { - Assert.That(_ctx[typeof(SingletonParent).Name], Is.TypeOf()); - Assert.That(_ctx[typeof(PrototypeChild).Name], Is.TypeOf()); + Assert.That(_ctx.GetObject(typeof(AnImportedType).Name), Is.Not.Null); } [Test] - public void Can_Satisfy_Dependencies_Of_Objects() + public void Can_Respect_Assigned_Aliases() { - Assert.That(((SingletonParent)_ctx[typeof(SingletonParent).Name]).Child, Is.Not.Null); + var firstObject = _ctx["TheFirstAlias"]; + var secondObject = _ctx["TheSecondAlias"]; + Assert.That(firstObject, Is.InstanceOf()); + Assert.That(secondObject, Is.InstanceOf()); + } + + [Test] + public void Can_Respect_Assigned_Name() + { + var result = _ctx["TheName"]; + Assert.That(result, Is.InstanceOf()); } [Test] @@ -62,11 +79,77 @@ namespace Spring.Context.Annotation Assert.That(firstObject, Is.Not.SameAs(secondObject)); } + [Test] + public void Can_Respect_Lazy_Attribute() + { + Assert.That(_ctx.GetObjectDefinition(typeof(ImplicitLazyInitObject).Name).IsLazyInit, Is.True); + Assert.That(_ctx.GetObjectDefinition(typeof(ExplicitLazyInitObject).Name).IsLazyInit, Is.True); + Assert.That(_ctx.GetObjectDefinition(typeof(ExplicitNonLazyInitObject).Name).IsLazyInit, Is.False); + } + + [Test] + public void Can_Retreive_Actual_Objects_From_Context() + { + Assert.That(_ctx[typeof(SingletonParent).Name], Is.TypeOf()); + Assert.That(_ctx[typeof(PrototypeChild).Name], Is.TypeOf()); + } + + [Test] + public void Can_Satisfy_Dependencies_Of_Objects() + { + Assert.That(((SingletonParent)_ctx[typeof(SingletonParent).Name]).Child, Is.Not.Null); + } + + + [Test] + public void Can_Respect_Imported_Resources() + { + Assert.That(_ctx["xmlRegisteredObject"], Is.Not.Null); + } + } + + public class ObjectWithInitAndDestroyMethods + { + public void CallToDestroy() { } + public void CallToInit() { } + } + + + + + [Configuration] + [ImportResource("assembly://Spring.Core.Configuration.Tests/Spring.Context.Attributes/ObjectDefinitions.xml", DefinitionReader = typeof(XmlObjectDefinitionReader))] + public class TheImportedConfigurationClass + { + [Definition] + public virtual AnImportedType AnImportedType() + { + return new AnImportedType(); + } } [Configuration] + [Import(new Type[] { typeof(TheImportedConfigurationClass) })] public class TheConfigurationClass { + [Definition(Names = "TheName")] + public virtual SingleNamedObject NamedObject() + { + return new SingleNamedObject(); + } + + [Definition(DestroyMethod = "CallToDestroy", InitMethod = "CallToInit")] + public virtual ObjectWithInitAndDestroyMethods ObjectWithInitAndDestroyMethods() + { + return new ObjectWithInitAndDestroyMethods(); + } + + [Definition(Names = "TheFirstAlias,TheSecondAlias")] + public virtual ObjectWithAnAlias ObjectWithAnAlias() + { + return new ObjectWithAnAlias(); + } + [Definition] [Scope(ObjectScope.Prototype)] public virtual PrototypeChild PrototypeChild() @@ -80,8 +163,43 @@ namespace Spring.Context.Annotation return new SingletonParent(PrototypeChild()); } + [Definition] + [Lazy] + public virtual ImplicitLazyInitObject ImplicitLazyInitObject() + { + return new ImplicitLazyInitObject(); + } + + [Definition] + [Lazy(true)] + public virtual ExplicitLazyInitObject ExplicitLazyInitObject() + { + return new ExplicitLazyInitObject(); + } + + [Definition] + [Lazy(false)] + public virtual ExplicitNonLazyInitObject ExplicitNonLazyInitObject() + { + return new ExplicitNonLazyInitObject(); + } + } + public class TypeRegisteredInXml { } + + public class AnImportedType { } + + public class ImplicitLazyInitObject { } + + public class ExplicitLazyInitObject { } + + public class ExplicitNonLazyInitObject { } + + public class ObjectWithAnAlias { } + + public class SingleNamedObject { } + public class SingletonParent { private PrototypeChild _child; diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/DefinitionAttributeTests.cs b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/DefinitionAttributeTests.cs new file mode 100644 index 00000000..673a3c85 --- /dev/null +++ b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/DefinitionAttributeTests.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using Spring.Context.Attributes; + +namespace Spring.Context.Attributes +{ + [TestFixture] + public class DefinitionAttributeTests + { + [Test] + public void Can_Accept_Single_Name() + { + var def = new DefinitionAttribute(); + + def.Names = "Steve"; + + Assert.That(def.NamesToArray[0], Is.EqualTo("Steve")); + } + + + [Test] + public void Can_Accept_Multiple_Names() + { + var def = new DefinitionAttribute(); + var names = "Name1,Name2,Name3"; + + def.Names = names; + Assert.That(def.NamesToArray[0], Is.EqualTo("Name1")); + Assert.That(def.NamesToArray[1], Is.EqualTo("Name2")); + Assert.That(def.NamesToArray[2], Is.EqualTo("Name3")); + + } + + + } +} diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ImportResourceAttributeTests.cs b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ImportResourceAttributeTests.cs new file mode 100644 index 00000000..21c83ae1 --- /dev/null +++ b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ImportResourceAttributeTests.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using Spring.Objects.Factory.Xml; +using Spring.Objects.Factory.Support; + +namespace Spring.Context.Attributes +{ + [TestFixture] + public class ImportResourceAttributeTests + { + [Test] + public void Uses_XmlObjectDefinitionReader_By_Default() + { + var attrib = new ImportResourceAttribute("the resource"); + + Assert.That(attrib.DefinitionReader, Is.EqualTo(typeof(XmlObjectDefinitionReader))); + } + + [Test] + public void Can_Assign_NonDefault_DefinitionReader() + { + var attrib = new ImportResourceAttribute("the resource"); + attrib.DefinitionReader = typeof(AbstractObjectDefinitionReader); + + Assert.That(attrib.DefinitionReader, Is.EqualTo(typeof(AbstractObjectDefinitionReader))); + } + + [Test] + public void DefinitionReader_Can_Prevent_Improper_Types() + { + ImportResourceAttribute attrib = new ImportResourceAttribute("the resource"); + + try + { + attrib.DefinitionReader = typeof(Assert);// <--need to use *anything* ensured *not* to implement IObjectDefinitionReader + Assert.Fail("Expected Exception of type ArgumentException not thrown!"); + } + catch (ArgumentException) + { + //swallow the expected exception + } + + + } + } +} diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ObjectDefinitions.xml b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ObjectDefinitions.xml new file mode 100644 index 00000000..5c7e700e --- /dev/null +++ b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ObjectDefinitions.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj b/test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj index f8a5b557..6a7f1d11 100644 --- a/test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj +++ b/test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj @@ -8,10 +8,11 @@ {4F1A206C-09A8-43FF-B791-FE956E99A120} Library Properties - Spring.Core.Configuration.Tests + Spring Spring.Core.Configuration.Tests - v2.0 + v4.0 512 + true @@ -40,6 +41,9 @@ + + + @@ -55,6 +59,18 @@ {710961A3-0DF4-49E4-A26E-F5B9C044AC84} Spring.Core.2010 + + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904} + Spring.Core.Tests.2010 + + + + + + + + Designer + - \ No newline at end of file diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/AssemblyTypeScannerTests.cs b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/AssemblyTypeScannerTests.cs deleted file mode 100644 index 0a72db8f..00000000 --- a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/AssemblyTypeScannerTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; -using Spring.Util; - -namespace Spring.Context.Attributes -{ - [TestFixture] - public class AssemblyTypeScannerTests - { - - private class Scanner : AssemblyTypeScanner - { - public Scanner(string folderScanPath) - : base(folderScanPath) - { } - - public Scanner() - : base(null) - { } - } - - private Scanner _scanner; - - private List> _excludePredicates - { - get - { - //get at the collection of excludePredicates from the private field - //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!) - return (List>)(ReflectionUtils.GetInstanceFieldValue(_scanner, "_excludePredicates")); - } - } - - private List> _includePredicates - { - get - { - //get at the collection of includePredicates from the private field - //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!) - return (List>)(ReflectionUtils.GetInstanceFieldValue(_scanner, "_includePredicates")); - } - } - - private List> _typeSources - { - get - { - //get at the collection of typeSources from the private field - //(yuck!-- test smell, but at least its wrapped up in a neat private property getter!) - return (List>)(ReflectionUtils.GetInstanceFieldValue(_scanner, "_typeSources")); - } - } - - [SetUp] - public void _TestSetup() - { - _scanner = new Scanner(); - } - - [Test] - public void AssemblyHavingType_T_Adds_Assembly() - { - _scanner.AssemblyHavingType(); - Assert.That(_typeSources.Any(t => t.Contains(typeof(Spring.Core.IOrdered)))); - } - - [Test] - public void IncludeType_T_Adds_Type() - { - _scanner.IncludeType(); - _scanner.IncludeType(); - - _includePredicates.Any(p => p(typeof(Spring.Core.IOrdered))); - _includePredicates.Any(p => p(typeof(Spring.Core.IPriorityOrdered))); - } - - [Test] - public void WithExcludeFilter_Excludes_Type() - { - _scanner.IncludeType(); - _scanner.IncludeType(); - _scanner.WithExcludeFilter(t => t.Name.StartsWith("TheImported")); - - Assert.That(_scanner.Scan(), Contains.Item((typeof(TheConfigurationClass)))); - Assert.False(_scanner.Scan().Contains(typeof(TheImportedConfigurationClass))); - } - - [Test] - public void WithIncludeFilter_Includes_Types() - { - _scanner.WithIncludeFilter(t => t.Name.Contains("ConfigurationClass")); - - Assert.That(_scanner.Scan(), Contains.Item((typeof(TheConfigurationClass)))); - Assert.That(_scanner.Scan(), Contains.Item((typeof(TheImportedConfigurationClass)))); - } - - } -} diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs deleted file mode 100644 index 5cb6190a..00000000 --- a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ConfigurationClassPostProcessorTests.cs +++ /dev/null @@ -1,223 +0,0 @@ -using System; -using NUnit.Framework; -using Spring.Context.Support; -using Spring.Objects.Factory.Support; -using Spring.Context.Attributes; -using Spring.Objects.Factory.Config; -using Spring.Objects.Factory.Xml; - -namespace Spring.Context.Attributes -{ - [TestFixture] - public class ConfigurationClassPostProcessorTests - { - private GenericApplicationContext _ctx; - - [SetUp] - public void _SetUp() - { - _ctx = new GenericApplicationContext(); - - var configDefinitionBuilder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(TheConfigurationClass)); - _ctx.RegisterObjectDefinition(configDefinitionBuilder.ObjectDefinition.ObjectTypeName, configDefinitionBuilder.ObjectDefinition); - - var postProcessorDefintionBuilder = ObjectDefinitionBuilder.GenericObjectDefinition(typeof(ConfigurationClassPostProcessor)); - _ctx.RegisterObjectDefinition(postProcessorDefintionBuilder.ObjectDefinition.ObjectTypeName, postProcessorDefintionBuilder.ObjectDefinition); - - Assert.That(_ctx.ObjectDefinitionCount, Is.EqualTo(2)); - - _ctx.Refresh(); - } - - [Test] - public void Can_Assign_Init_And_Destroy_Methods() - { - IObjectDefinition def = _ctx.GetObjectDefinition(typeof(ObjectWithInitAndDestroyMethods).Name); - - Assert.That(def, Is.Not.Null); - Assert.That(def.InitMethodName, Is.EqualTo("CallToInit")); - Assert.That(def.DestroyMethodName, Is.EqualTo("CallToDestroy")); - } - - [Test] - public void Can_Import_Configurations_From_Additional_Classes() - { - Assert.That(_ctx.GetObject(typeof(AnImportedType).Name), Is.Not.Null); - } - - [Test] - public void Can_Respect_Assigned_Aliases() - { - var firstObject = _ctx["TheFirstAlias"]; - var secondObject = _ctx["TheSecondAlias"]; - Assert.That(firstObject, Is.InstanceOf()); - Assert.That(secondObject, Is.InstanceOf()); - } - - [Test] - public void Can_Respect_Assigned_Name() - { - var result = _ctx["TheName"]; - Assert.That(result, Is.InstanceOf()); - } - - [Test] - public void Can_Respect_Default_Singleton_Scope() - { - var firstObject = (SingletonParent)_ctx[typeof(SingletonParent).Name]; - var secondObject = (SingletonParent)_ctx[typeof(SingletonParent).Name]; - - Assert.That(firstObject, Is.SameAs(secondObject)); - } - - [Test] - public void Can_Respect_Explicit_PrototypeScope() - { - var firstObject = (PrototypeChild)_ctx[typeof(PrototypeChild).Name]; - var secondObject = (PrototypeChild)_ctx[typeof(PrototypeChild).Name]; - - Assert.That(firstObject, Is.Not.SameAs(secondObject)); - } - - [Test] - public void Can_Respect_Lazy_Attribute() - { - Assert.That(_ctx.GetObjectDefinition(typeof(ImplicitLazyInitObject).Name).IsLazyInit, Is.True); - Assert.That(_ctx.GetObjectDefinition(typeof(ExplicitLazyInitObject).Name).IsLazyInit, Is.True); - Assert.That(_ctx.GetObjectDefinition(typeof(ExplicitNonLazyInitObject).Name).IsLazyInit, Is.False); - } - - [Test] - public void Can_Retreive_Actual_Objects_From_Context() - { - Assert.That(_ctx[typeof(SingletonParent).Name], Is.TypeOf()); - Assert.That(_ctx[typeof(PrototypeChild).Name], Is.TypeOf()); - } - - [Test] - public void Can_Satisfy_Dependencies_Of_Objects() - { - Assert.That(((SingletonParent)_ctx[typeof(SingletonParent).Name]).Child, Is.Not.Null); - } - - - [Test] - public void Can_Respect_Imported_Resources() - { - Assert.That(_ctx["xmlRegisteredObject"], Is.Not.Null); - } - } - - public class ObjectWithInitAndDestroyMethods - { - public void CallToDestroy() { } - public void CallToInit() { } - } - - - - - [Configuration] - [ImportResource("assembly://Spring.Core.Configuration.Tests/Spring.Context.Attributes/ObjectDefinitions.xml", DefinitionReader = typeof(XmlObjectDefinitionReader))] - public class TheImportedConfigurationClass - { - [Definition] - public virtual AnImportedType AnImportedType() - { - return new AnImportedType(); - } - } - - [Configuration] - [Import(new Type[] { typeof(TheImportedConfigurationClass) })] - public class TheConfigurationClass - { - [Definition(Names = "TheName")] - public virtual SingleNamedObject NamedObject() - { - return new SingleNamedObject(); - } - - [Definition(DestroyMethod = "CallToDestroy", InitMethod = "CallToInit")] - public virtual ObjectWithInitAndDestroyMethods ObjectWithInitAndDestroyMethods() - { - return new ObjectWithInitAndDestroyMethods(); - } - - [Definition(Names = "TheFirstAlias,TheSecondAlias")] - public virtual ObjectWithAnAlias ObjectWithAnAlias() - { - return new ObjectWithAnAlias(); - } - - [Definition] - [Scope(ObjectScope.Prototype)] - public virtual PrototypeChild PrototypeChild() - { - return new PrototypeChild(); - } - - [Definition] - public virtual SingletonParent SingletonParent() - { - return new SingletonParent(PrototypeChild()); - } - - [Definition] - [Lazy] - public virtual ImplicitLazyInitObject ImplicitLazyInitObject() - { - return new ImplicitLazyInitObject(); - } - - [Definition] - [Lazy(true)] - public virtual ExplicitLazyInitObject ExplicitLazyInitObject() - { - return new ExplicitLazyInitObject(); - } - - [Definition] - [Lazy(false)] - public virtual ExplicitNonLazyInitObject ExplicitNonLazyInitObject() - { - return new ExplicitNonLazyInitObject(); - } - - } - - public class TypeRegisteredInXml { } - - public class AnImportedType { } - - public class ImplicitLazyInitObject { } - - public class ExplicitLazyInitObject { } - - public class ExplicitNonLazyInitObject { } - - public class ObjectWithAnAlias { } - - public class SingleNamedObject { } - - public class SingletonParent - { - private PrototypeChild _child; - - public SingletonParent(PrototypeChild child) - { - _child = child; - } - - public PrototypeChild Child - { - get - { - return _child; - } - } - - } - - public class PrototypeChild { } -} diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/DefinitionAttributeTests.cs b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/DefinitionAttributeTests.cs deleted file mode 100644 index 673a3c85..00000000 --- a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/DefinitionAttributeTests.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using NUnit.Framework; -using Spring.Context.Attributes; - -namespace Spring.Context.Attributes -{ - [TestFixture] - public class DefinitionAttributeTests - { - [Test] - public void Can_Accept_Single_Name() - { - var def = new DefinitionAttribute(); - - def.Names = "Steve"; - - Assert.That(def.NamesToArray[0], Is.EqualTo("Steve")); - } - - - [Test] - public void Can_Accept_Multiple_Names() - { - var def = new DefinitionAttribute(); - var names = "Name1,Name2,Name3"; - - def.Names = names; - Assert.That(def.NamesToArray[0], Is.EqualTo("Name1")); - Assert.That(def.NamesToArray[1], Is.EqualTo("Name2")); - Assert.That(def.NamesToArray[2], Is.EqualTo("Name3")); - - } - - - } -} diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ImportResourceAttributeTests.cs b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ImportResourceAttributeTests.cs deleted file mode 100644 index 6f0d4018..00000000 --- a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ImportResourceAttributeTests.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using NUnit.Framework; -using Spring.Objects.Factory.Xml; -using Spring.Objects.Factory.Support; - -namespace Spring.Context.Attributes -{ - [TestFixture] - public class ImportResourceAttributeTests - { - [Test] - public void Uses_XmlObjectDefinitionReader_By_Default() - { - var attrib = new ImportResourceAttribute("the resource"); - - Assert.That(attrib.DefinitionReader, Is.EqualTo(typeof(XmlObjectDefinitionReader))); - } - - [Test] - public void Can_Assign_NonDefault_DefinitionReader() - { - var attrib = new ImportResourceAttribute("the resource"); - attrib.DefinitionReader = typeof(AbstractObjectDefinitionReader); - - Assert.That(attrib.DefinitionReader, Is.EqualTo(typeof(AbstractObjectDefinitionReader))); - } - - [Test] - public void DefinitionReader_Can_Prevent_Improper_Types() - { - ImportResourceAttribute attrib = new ImportResourceAttribute("the resource"); - - try - { - attrib.DefinitionReader = typeof(Object);// <--need to use *anything* ensured *not* to implement IObjectDefinitionReader - Assert.Fail("Expected Exception of type ArgumentException not thrown!"); - } - catch (ArgumentException) - { - //swallow the expected exception - } - - - } - } -} diff --git a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ObjectDefinitions.xml b/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ObjectDefinitions.xml deleted file mode 100644 index 5c7e700e..00000000 --- a/test/Spring/Spring.Core.Configuration.Tests/Context/Attributes/ObjectDefinitions.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/test/Spring/Spring.Core.Configuration.Tests/Objects/Factory/Support/AssemblyScanningExtensionMethodsTests.cs b/test/Spring/Spring.Core.Configuration.Tests/Objects/Factory/Support/AssemblyScanningExtensionMethodsTests.cs deleted file mode 100644 index c0e0a01f..00000000 --- a/test/Spring/Spring.Core.Configuration.Tests/Objects/Factory/Support/AssemblyScanningExtensionMethodsTests.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; -using System.Reflection; -using System.Diagnostics; -using Spring.Context.Config; -using Spring.Context.Support; -using Spring.Context.Attributes; - -namespace Spring.Objects.Factory.Support -{ - [TestFixture] - public class AssemblyScanningExtensionMethodsTests - { - private GenericApplicationContext _context; - - [SetUp] - public void _TestSetup() - { - _context = new GenericApplicationContext(); - } - - [Test] - public void Can_Filter_For_Assembly_Based_On_Assembly_Metadata() - { - _context.Scan(a => a.GetName().Name.StartsWith("Spring.Core.Configuration.")); - _context.Refresh(); - - AssertExpectedObjectsAreRegisteredWith(_context); - } - - [Test] - public void Can_Filter_For_Assembly_Containing_Specific_Type_But_Having_NO_Definitions() - { - //specifically filter assemblies for one that we *know* will result in NO [Configuration] types in it - _context.Scan(assy => assy.GetTypes().Any(type => type.FullName.Contains(typeof(Spring.Core.IOrdered).Name))); - _context.Refresh(); - - Assert.That(_context.DefaultListableObjectFactory.ObjectDefinitionCount, Is.EqualTo(0)); - } - - [Test] - public void Can_Filter_For_Assembly_Containing_Specific_Type() - { - _context.Scan(assy => assy.GetTypes().Any(type => type.FullName.Contains(typeof(MarkerTypeForScannerToFind).Name))); - _context.Refresh(); - - AssertExpectedObjectsAreRegisteredWith(_context); - } - - [Test] - public void Can_Filter_For_Specific_Type() - { - _context.Scan(type => ((Type)type).FullName.Contains(typeof(TheImportedConfigurationClass).Name)); - _context.Refresh(); - - Assert.That(_context.DefaultListableObjectFactory.ObjectDefinitionCount, Is.EqualTo(4)); - } - - [Test] - public void Can_Filter_For_Specific_Types_With_Compound_Predicate() - { - _context.Scan(type => ((Type)type).FullName.Contains(typeof(TheImportedConfigurationClass).Name) || ((Type)type).FullName.Contains(typeof(TheConfigurationClass).Name)); - _context.Refresh(); - - AssertExpectedObjectsAreRegisteredWith(_context); - } - - [Test] - public void Can_Filter_For_Specific_Types_With_Multiple_Include_Filters() - { - var scanner = new AssemblyObjectDefinitionScanner(); - scanner.WithIncludeFilter(type => ((Type)type).FullName.Contains(typeof(TheImportedConfigurationClass).Name)); - scanner.WithIncludeFilter(type => ((Type)type).FullName.Contains(typeof(TheConfigurationClass).Name)); - - _context.Scan(scanner); - _context.Refresh(); - - AssertExpectedObjectsAreRegisteredWith(_context); - } - - [Test] - public void Can_Perform_Scan_With_No_Filtering() - { - _context.Scan(); - _context.Refresh(); - - AssertExpectedObjectsAreRegisteredWith(_context); - } - - private void AssertExpectedObjectsAreRegisteredWith(GenericApplicationContext _context) - { - Assert.That(_context.DefaultListableObjectFactory.ObjectDefinitionCount, Is.EqualTo(13)); - } - - } - - public class MarkerTypeForScannerToFind - { - - } -} diff --git a/test/Spring/Spring.Core.Configuration.Tests/Properties/AssemblyInfo.cs b/test/Spring/Spring.Core.Configuration.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index a1c1539d..00000000 --- a/test/Spring/Spring.Core.Configuration.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Spring.Core.Configuration.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("Spring.Core.Configuration.Tests")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("65e12092-0586-435f-b9ef-e4a35c302bef")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj b/test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj deleted file mode 100644 index 859e1c50..00000000 --- a/test/Spring/Spring.Core.Configuration.Tests/Spring.Core.Configuration.Tests.2010.csproj +++ /dev/null @@ -1,85 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {4F1A206C-09A8-43FF-B791-FE956E99A120} - Library - Properties - Spring - Spring.Core.Configuration.Tests - v4.0 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\..\lib\Net\2.0\nunit.framework.dll - - - - - - - - - - - - - - - - - {3A3A4E65-45A6-4B20-B460-0BEDC302C02C} - Spring.Aop.2010 - - - {7B65D538-E863-4F57-8DDC-2C38E4150045} - Spring.Core.Configuration.2010 - - - {710961A3-0DF4-49E4-A26E-F5B9C044AC84} - Spring.Core.2010 - - - {44B16BAA-6DF8-447C-9D7F-3AD3D854D904} - Spring.Core.Tests.2010 - - - - - - - - Designer - - - - - \ No newline at end of file