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/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/ContextClassDiagram.cd b/src/Spring/Spring.Core/ContextClassDiagram.cd new file mode 100644 index 00000000..7a48ca13 --- /dev/null +++ b/src/Spring/Spring.Core/ContextClassDiagram.cd @@ -0,0 +1,153 @@ + + + + + + SHQRYAEIiGBAtMBASYTEWAQkWBAiChEMaAACCAFBXMg= + Context\Support\AbstractApplicationContext.cs + + + + + + + AAQACAAAAABAAACBAAQAAQAAABAAAAAAABAAAAACAEA= + Context\Support\AbstractXmlApplicationContext.cs + + + + + + AAQAAAAAAAAAAAAAAAQAAAAAABAAIAAAAAAAAAAEAAA= + Context\Support\GenericApplicationContext.cs + + + + + + AAAACAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAIAEAAA= + Context\Support\XmlApplicationContext.cs + + + + + + AAEAAAAAAAAAAAAIAAQAAAAAAgAAAAAAAAAAAAAAAAA= + Context\Support\StaticApplicationContext.cs + + + + + + AAAAAAAAAAAAggAAAQAAAAAABAAAAAAAAAAASAAAAAA= + Core\IO\ConfigurableResourceLoader.cs + + + + + + + AAQAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEA= + Context\IConfigurableApplicationContext.cs + + + + + + AAAAAAAAAAAAEAAAAACAAAQAAAAAAAAAAAAAAAAACAA= + Context\IApplicationContext.cs + + + + + + AAAAAAAAACAAAAAAAAAAQAAAAAAAAAAAIAAAAAAAAAA= + Context\ILifecycle.cs + + + + + + ABAAAAAAAAAAIIAACIAACAAAAAAAAgEMAAAAAAAAAIA= + Objects\Factory\IObjectFactory.cs + + + + + + AAAAAAAAAAAAAACAAAAAAAAIAAQAAAAgEAAAAAAAAAA= + Objects\Factory\Config\IAutowireCapableObjectFactory.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAQAA= + Objects\Factory\IHierarchicalObjectFactory.cs + + + + + + CAAAAAAAAAAAAAAAQABAEAAAAAAAAAAACAAAAAAAAAA= + Objects\Factory\IListableObjectFactory.cs + + + + + + AAAAAAAAAAAAAIAAAIAEAAAgAAAAAAAAAAAACABAAAA= + Objects\Factory\Config\IConfigurableListableObjectFactory.cs + + + + + + AAAAAAAABCAAAAAAAAACAAAAQAAEAAAAAAAAAQAAEAA= + Objects\Factory\Config\IConfigurableObjectFactory.cs + + + + + + AAAAAAAAEAAAABAIAAAAAAAAAAAAAAAAAAAAAgAAAIA= + Objects\Factory\Config\ISingletonObjectRegistry.cs + + + + + + ACAAAAAAAAAAAAAAAAAAAAAACAAAABAAAAAAAAAAAAA= + Context\IMessageSource.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA= + Context\IApplicationEventPublisher.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAA= + Core\IO\IResourceLoader.cs + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAQAAAAAAAAIA= + Objects\Events\IEventRegistry.cs + + + + + + CBAAAAAAAAAAAAAAQAAEEAAgABAAAAAAAAAAAAAAEAA= + Objects\Factory\Support\IObjectDefinitionRegistry.cs + + + + \ No newline at end of file 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..6ca9a321 --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs @@ -0,0 +1,53 @@ +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) + { + //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; + } + + /// + /// 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..7fa96f46 --- /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!=null ? _location.Resource.Description : string.Empty; } + } + + 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..292d4fc2 --- /dev/null +++ b/src/Spring/Spring.Core/Objects/Factory/Support/IObjectDefinitionRegistryPostProcessor.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Spring.Objects.Factory.Config; + +namespace Spring.Objects.Factory.Support +{ + public interface IObjectDefinitionRegistryPostProcessor : IObjectFactoryPostProcessor + { + 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..dd761999 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 @@ -695,7 +703,14 @@ + + + + + + + @@ -1203,6 +1218,7 @@ Code + @@ -1246,6 +1262,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/src/Spring/Spring.Core/Util/ReflectionUtils.cs b/src/Spring/Spring.Core/Util/ReflectionUtils.cs index c30b7d97..1e85ac54 100644 --- a/src/Spring/Spring.Core/Util/ReflectionUtils.cs +++ b/src/Spring/Spring.Core/Util/ReflectionUtils.cs @@ -1417,6 +1417,65 @@ namespace Spring.Util MemberwiseCopyInternal(fromObject, toObject, smallerType); } + + /// + /// Convenience method that uses reflection to return the value of a non-public field of a given object. + /// + /// Useful in certain instances during testing to avoid the need to add protected properties, etc. to a class just to facilitate testing. + /// The instance of the object from which to retrieve the field value. + /// Name of the field on the object from which to retrieve the value. + /// + public static object GetInstanceFieldValue(object obj, string fieldName) + { + if (obj == null) + throw new ArgumentNullException("obj", "obj is null."); + if (String.IsNullOrEmpty(fieldName)) + throw new ArgumentException("fieldName is null or empty.", "fieldName"); + + FieldInfo f = obj.GetType().GetField(fieldName, BindingFlags.SetField | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + if (f != null) + return f.GetValue(obj); + else + { + throw new ArgumentException(string.Format("Non-public instance field '{0}' could not be found in class of type '{1}'", fieldName, obj.GetType().ToString())); + } + } + + /// + /// Convenience method that uses reflection to set the value of a non-public field of a given object. + /// + /// Useful in certain instances during testing to avoid the need to add protected properties, etc. to a class just to facilitate testing. + /// The instance of the object from which to set the field value. + /// Name of the field on the object to which to set the value. + /// The field value to set. + public static void SetInstanceFieldValue(object obj, string fieldName, object fieldValue) + { + + if (obj == null) + throw new ArgumentNullException("obj", "obj is null."); + if (String.IsNullOrEmpty(fieldName)) + throw new ArgumentException("fieldName is null or empty.", "fieldName"); + if (fieldValue == null) + throw new ArgumentNullException("fieldValue", "fieldValue is null."); + + FieldInfo f = obj.GetType().GetField(fieldName, BindingFlags.SetField | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + + if (f != null) + { + if (f.FieldType != fieldValue.GetType()) + throw new ArgumentException(string.Format("fieldValue for fieldName '{0}' of object type '{1}' must be of type '{2}' but was of type '{3}'", fieldName, obj.GetType().ToString(), f.FieldType.ToString(), fieldValue.GetType().ToString()), "fieldValue"); + + f.SetValue(obj, fieldValue); + } + else + { + throw new ArgumentException(string.Format("Non-public instance field '{0}' could not be found in class of type '{1}'", fieldName, obj.GetType().ToString())); + } + } + + + + #if NET_2_0 private static void MemberwiseCopyInternal(object fromObject, object toObject, Type smallerType) { 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 @@ -