initial port of lower-level classes
This commit is contained in:
249
src/Spring/Spring.Core/Collections/Generic/DictionarySet.cs
Normal file
249
src/Spring/Spring.Core/Collections/Generic/DictionarySet.cs
Normal file
@@ -0,0 +1,249 @@
|
||||
/* Copyright <20> 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spring.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// <p><c>DictionarySet</c> is an abstract class that supports the creation of new <c>Set</c>
|
||||
/// types where the underlying data store is an <c>IDictionary</c> instance.</p>
|
||||
///
|
||||
/// <p>You can use any object that implements the <c>IDictionary</c> 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 <c>IDictionary</c> you choose will affect both the performance and the behavior
|
||||
/// of the <c>Set</c> using it. </p>
|
||||
///
|
||||
/// <p>To make a <c>Set</c> typed based on your own <c>IDictionary</c>, simply derive a
|
||||
/// new class with a constructor that takes no parameters. Some <c>Set</c> implmentations
|
||||
/// cannot be defined with a default constructor. If this is the case for your class,
|
||||
/// you will need to override <c>Clone()</c> as well.</p>
|
||||
///
|
||||
/// <p>It is also standard practice that at least one of your constructors takes an <c>ICollection</c> or
|
||||
/// an <c>ISet</c> as an argument.</p>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class DictionarySet<T> : Set<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the storage for elements in the <c>Set</c>, stored as the key-set
|
||||
/// of the <c>IDictionary</c> object. Set this object in the constructor
|
||||
/// if you create your own <c>Set</c> class.
|
||||
/// </summary>
|
||||
protected IDictionary<T, object> InternalDictionary = null;
|
||||
|
||||
private static readonly object PlaceholderObject = new object();
|
||||
|
||||
/// <summary>
|
||||
/// The placeholder object used as the value for the <c>IDictionary</c> instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// There is a single instance of this object globally, used for all <c>Sets</c>.
|
||||
/// </remarks>
|
||||
protected object Placeholder
|
||||
{
|
||||
get { return PlaceholderObject; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified element to this set if it is not already present.
|
||||
/// </summary>
|
||||
/// <param name="o">The <typeparamref name="T"/> to add to the set.</param>
|
||||
/// <returns><see langword="true" /> is the object was added, <see langword="false" /> if it was already present.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all the elements in the specified collection to the set if they are not already present.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of objects to add to the set.</param>
|
||||
/// <returns><see langword="true" /> is the set changed as a result of this operation, <see langword="false" /> if not.</returns>
|
||||
public override bool AddAll(ICollection<T> c)
|
||||
{
|
||||
bool changed = false;
|
||||
foreach (T o in c)
|
||||
{
|
||||
changed |= this.Add(o);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all objects from the set.
|
||||
/// </summary>
|
||||
public override void Clear()
|
||||
{
|
||||
InternalDictionary.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if this set contains the specified element.
|
||||
/// </summary>
|
||||
/// <param name="o">The element to look for.</param>
|
||||
/// <returns><see langword="true" /> if this set contains the specified element, <see langword="false" /> otherwise.</returns>
|
||||
public override bool Contains(T o)
|
||||
{
|
||||
return InternalDictionary.ContainsKey(o);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if the set contains all the elements in the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of objects.</param>
|
||||
/// <returns><see langword="true" /> if the set contains all the elements in the specified collection, <see langword="false" /> otherwise.</returns>
|
||||
public override bool ContainsAll(ICollection<T> c)
|
||||
{
|
||||
foreach (T o in c)
|
||||
{
|
||||
if (!this.Contains(o))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if this set contains no elements.
|
||||
/// </summary>
|
||||
public override bool IsEmpty
|
||||
{
|
||||
get { return InternalDictionary.Count == 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified element from the set.
|
||||
/// </summary>
|
||||
/// <param name="o">The element to be removed.</param>
|
||||
/// <returns><see langword="true" /> if the set contained the specified element, <see langword="false" /> otherwise.</returns>
|
||||
public override bool Remove(T o)
|
||||
{
|
||||
bool contained = this.Contains(o);
|
||||
if (contained)
|
||||
{
|
||||
InternalDictionary.Remove(o);
|
||||
}
|
||||
return contained;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all the specified elements from this set, if they exist in this set.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of elements to remove.</param>
|
||||
/// <returns><see langword="true" /> if the set was modified as a result of this operation.</returns>
|
||||
public override bool RemoveAll(ICollection<T> c)
|
||||
{
|
||||
bool changed = false;
|
||||
foreach (T o in c)
|
||||
{
|
||||
changed |= this.Remove(o);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retains only the elements in this set that are contained in the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="c">Collection that defines the set of elements to be retained.</param>
|
||||
/// <returns><see langword="true" /> if this set changed as a result of this operation.</returns>
|
||||
public override bool RetainAll(ICollection<T> c)
|
||||
{
|
||||
//Put data from C into a set so we can use the Contains() method.
|
||||
Set<T> cSet = new HashedSet<T>(c);
|
||||
|
||||
//We are going to build a set of elements to remove.
|
||||
Set<T> removeSet = new HashedSet<T>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements in the <c>Set</c> to an array of T. The type of array needs
|
||||
/// to be compatible with the objects in the <c>Set</c>, obviously.
|
||||
/// </summary>
|
||||
/// <param name="array">An array that will be the target of the copy operation.</param>
|
||||
/// <param name="index">The zero-based index where copying will start.</param>
|
||||
public override void CopyTo(T[] array, int index)
|
||||
{
|
||||
InternalDictionary.Keys.CopyTo(array, index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of elements contained in this collection.
|
||||
/// </summary>
|
||||
public override int Count
|
||||
{
|
||||
get { return InternalDictionary.Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// None of the objects based on <c>DictionarySet</c> are synchronized. Use the
|
||||
/// <c>SyncRoot</c> property instead.
|
||||
/// </summary>
|
||||
public override bool IsSynchronized
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an object that can be used to synchronize the <c>Set</c> between threads.
|
||||
/// </summary>
|
||||
public override object SyncRoot
|
||||
{
|
||||
get { return ((ICollection) InternalDictionary).SyncRoot; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enumerator for the elements in the <c>Set</c>.
|
||||
/// </summary>
|
||||
/// <returns>An <c>IEnumerator</c> over the elements in the <c>Set</c>.</returns>
|
||||
public override IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return InternalDictionary.Keys.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates wether the <c>Set</c> is read-only or not
|
||||
/// </summary>
|
||||
public override bool IsReadOnly
|
||||
{
|
||||
get { return InternalDictionary.IsReadOnly; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements in the <c>Set</c> to an array. The type of array needs
|
||||
/// to be compatible with the objects in the <c>Set</c>, obviously. Needed for
|
||||
/// non-generic ISet methods implementation
|
||||
/// </summary>
|
||||
/// <param name="array">An array that will be the target of the copy operation.</param>
|
||||
/// <param name="index">The zero-based index where copying will start.</param>
|
||||
protected override void NonGenericCopyTo(Array array, int index)
|
||||
{
|
||||
((ICollection) InternalDictionary.Keys).CopyTo(array, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/Spring/Spring.Core/Collections/Generic/HashedSet.cs
Normal file
33
src/Spring/Spring.Core/Collections/Generic/HashedSet.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/* Copyright <20> 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spring.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a <c>Set</c> based on a Dictionary (which is equivalent of
|
||||
/// non-genric <c>HashTable</c>) This will give the best lookup, add, and remove
|
||||
/// performance for very large data-sets, but iteration will occur in no particular order.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class HashedSet<T> : DictionarySet<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new set instance based on a Dictinary.
|
||||
/// </summary>
|
||||
public HashedSet()
|
||||
{
|
||||
InternalDictionary = new Dictionary<T, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new set instance based on a Dictinary and
|
||||
/// initializes it based on a collection of elements.
|
||||
/// </summary>
|
||||
/// <param name="initialValues">A collection of elements that defines the initial set contents.</param>
|
||||
public HashedSet(ICollection<T> initialValues) : this()
|
||||
{
|
||||
this.AddAll(initialValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
139
src/Spring/Spring.Core/Collections/Generic/ISet.cs
Normal file
139
src/Spring/Spring.Core/Collections/Generic/ISet.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spring.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// <p>A collection that contains no duplicate elements. This interface models the mathematical
|
||||
/// <c>Set</c> abstraction.
|
||||
/// The order of elements in a set is dependant on (a)the data-structure implementation, and
|
||||
/// (b)the implementation of the various <c>Set</c> methods, and thus is not guaranteed.</p>
|
||||
///
|
||||
/// <p>None of the <c>Set</c> implementations in this library are guranteed to be thread-safe
|
||||
/// in any way unless wrapped in a <c>SynchronizedSet</c>.</p>
|
||||
///
|
||||
/// <p>The following table summarizes the binary operators that are supported by the <c>Set</c> class.</p>
|
||||
/// <list type="table">
|
||||
/// <listheader>
|
||||
/// <term>Operation</term>
|
||||
/// <term>Description</term>
|
||||
/// <term>Method</term>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>Union (OR)</term>
|
||||
/// <term>Element included in result if it exists in either <c>A</c> OR <c>B</c>.</term>
|
||||
/// <term><c>Union()</c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Intersection (AND)</term>
|
||||
/// <term>Element included in result if it exists in both <c>A</c> AND <c>B</c>.</term>
|
||||
/// <term><c>InterSect()</c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Exclusive Or (XOR)</term>
|
||||
/// <term>Element included in result if it exists in one, but not both, of <c>A</c> and <c>B</c>.</term>
|
||||
/// <term><c>ExclusiveOr()</c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Minus (n/a)</term>
|
||||
/// <term>Take all the elements in <c>A</c>. Now, if any of them exist in <c>B</c>, remove
|
||||
/// them. Note that unlike the other operators, <c>A - B</c> is not the same as <c>B - A</c>.</term>
|
||||
/// <term><c>Minus()</c></term>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public interface ISet<T> : ICollection<T>, IEnumerable<T>, IEnumerable, ICloneable
|
||||
{
|
||||
// Clear is declared in ICollection<T>, but not in ICollection
|
||||
// void Clear();
|
||||
|
||||
// Remove is declared in ICollection<T>, but not in ICollection
|
||||
// bool Remove(T o);
|
||||
|
||||
// Contains is declared in ICollection<T>, but not in ICollection
|
||||
// bool Contains(T o);
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>a</c> or <c>b</c>.
|
||||
/// Neither this set nor the input set are modified during the operation. The return value
|
||||
/// is a <c>Clone()</c> of this set with the extra elements added in.
|
||||
/// </summary>
|
||||
/// <param name="a">A collection of elements.</param>
|
||||
/// <returns>A new <c>Set</c> containing the union of this <c>Set</c> with the specified collection.
|
||||
/// Neither of the input objects is modified by the union.</returns>
|
||||
ISet<T> Union(ISet<T> a);
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>Intersect()</c> operation does not modify the input sets. It returns
|
||||
/// a <c>Clone()</c> of this set with the appropriate elements removed.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <returns>The intersection of this set with <c>a</c>.</returns>
|
||||
ISet<T> Intersect(ISet<T> a);
|
||||
|
||||
/// <summary>
|
||||
/// Performs a "minus" of set <c>b</c> from set <c>a</c>. This returns a set of all
|
||||
/// the elements in set <c>a</c>, removing the elements that are also in set <c>b</c>.
|
||||
/// The original sets are not modified during this operation. The result set is a <c>Clone()</c>
|
||||
/// of this <c>Set</c> containing the elements from the operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <returns>A set containing the elements from this set with the elements in <c>a</c> removed.</returns>
|
||||
ISet<T> Minus(ISet<T> a);
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>Clone()</c> of this set containing
|
||||
/// the elements from the exclusive-or operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <returns>A set containing the result of <c>a ^ b</c>.</returns>
|
||||
ISet<T> ExclusiveOr(ISet<T> a);
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if the set contains all the elements in the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of objects.</param>
|
||||
/// <returns><see langword="true" /> if the set contains all the elements in the specified collection, <see langword="false" /> otherwise.</returns>
|
||||
bool ContainsAll(ICollection<T> c);
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if this set contains no elements.
|
||||
/// </summary>
|
||||
bool IsEmpty { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified element to this set if it is not already present.
|
||||
/// </summary>
|
||||
/// <param name="o">The object to add to the set.</param>
|
||||
/// <returns><see langword="true" /> is the object was added, <see langword="false" /> if it was already present.</returns>
|
||||
new bool Add(T o);
|
||||
|
||||
/// <summary>
|
||||
/// Adds all the elements in the specified collection to the set if they are not already present.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of objects to add to the set.</param>
|
||||
/// <returns><see langword="true" /> is the set changed as a result of this operation, <see langword="false" /> if not.</returns>
|
||||
bool AddAll(ICollection<T> c);
|
||||
|
||||
/// <summary>
|
||||
/// Remove all the specified elements from this set, if they exist in this set.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of elements to remove.</param>
|
||||
/// <returns><see langword="true" /> if the set was modified as a result of this operation.</returns>
|
||||
bool RemoveAll(ICollection<T> c);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retains only the elements in this set that are contained in the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="c">Collection that defines the set of elements to be retained.</param>
|
||||
/// <returns><see langword="true" /> if this set changed as a result of this operation.</returns>
|
||||
bool RetainAll(ICollection<T> c);
|
||||
}
|
||||
}
|
||||
308
src/Spring/Spring.Core/Collections/Generic/ImmutableSet.cs
Normal file
308
src/Spring/Spring.Core/Collections/Generic/ImmutableSet.cs
Normal file
@@ -0,0 +1,308 @@
|
||||
/* Copyright <20> 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spring.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// <p>Implements an immutable (read-only) <c>Set</c> wrapper.</p>
|
||||
/// <p>Although this is advertised as immutable, it really isn't. Anyone with access to the
|
||||
/// <c>basisSet</c> can still change the data-set. So <c>GetHashCode()</c> is not implemented
|
||||
/// for this <c>Set</c>, as is the case for all <c>Set</c> implementations in this library.
|
||||
/// This design decision was based on the efficiency of not having to <c>Clone()</c> the
|
||||
/// <c>basisSet</c> every time you wrap a mutable <c>Set</c>.</p>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class ImmutableSet<T> : Set<T>
|
||||
{
|
||||
private const string ERROR_MESSAGE = "Object is immutable.";
|
||||
private ISet<T> mBasisSet;
|
||||
|
||||
internal ISet<T> BasisSet
|
||||
{
|
||||
get { return mBasisSet; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an immutable (read-only) <c>Set</c> wrapper.
|
||||
/// </summary>
|
||||
/// <param name="basisSet">The <c>Set</c> that is wrapped.</param>
|
||||
public ImmutableSet(ISet<T> basisSet)
|
||||
{
|
||||
mBasisSet = basisSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified element to this set if it is not already present.
|
||||
/// </summary>
|
||||
/// <param name="o">The object to add to the set.</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="NotSupportedException"> is always thrown</exception>
|
||||
public override sealed bool Add(T o)
|
||||
{
|
||||
throw new NotSupportedException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all the elements in the specified collection to the set if they are not already present.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of objects to add to the set.</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="NotSupportedException"> is always thrown</exception>
|
||||
public override sealed bool AddAll(ICollection<T> c)
|
||||
{
|
||||
throw new NotSupportedException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all objects from the set.
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException"> is always thrown</exception>
|
||||
public override sealed void Clear()
|
||||
{
|
||||
throw new NotSupportedException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if this set contains the specified element.
|
||||
/// </summary>
|
||||
/// <param name="o">The element to look for.</param>
|
||||
/// <returns><see langword="true" /> if this set contains the specified element, <see langword="false" /> otherwise.</returns>
|
||||
public override sealed bool Contains(T o)
|
||||
{
|
||||
return mBasisSet.Contains(o);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if the set contains all the elements in the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of objects.</param>
|
||||
/// <returns><see langword="true" /> if the set contains all the elements in the specified collection, <see langword="false" /> otherwise.</returns>
|
||||
public override sealed bool ContainsAll(ICollection<T> c)
|
||||
{
|
||||
return mBasisSet.ContainsAll(c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if this set contains no elements.
|
||||
/// </summary>
|
||||
public override sealed bool IsEmpty
|
||||
{
|
||||
get { return mBasisSet.IsEmpty; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified element from the set.
|
||||
/// </summary>
|
||||
/// <param name="o">The element to be removed.</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="NotSupportedException"> is always thrown</exception>
|
||||
public override sealed bool Remove(T o)
|
||||
{
|
||||
throw new NotSupportedException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all the specified elements from this set, if they exist in this set.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of elements to remove.</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="NotSupportedException"> is always thrown</exception>
|
||||
public override sealed bool RemoveAll(ICollection<T> c)
|
||||
{
|
||||
throw new NotSupportedException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retains only the elements in this set that are contained in the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="c">Collection that defines the set of elements to be retained.</param>
|
||||
/// <returns>nothing</returns>
|
||||
/// <exception cref="NotSupportedException"> is always thrown</exception>
|
||||
public override sealed bool RetainAll(ICollection<T> c)
|
||||
{
|
||||
throw new NotSupportedException(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements in the <c>Set</c> to an array of T. The type of array needs
|
||||
/// to be compatible with the objects in the <c>Set</c>, obviously.
|
||||
/// </summary>
|
||||
/// <param name="array">An array that will be the target of the copy operation.</param>
|
||||
/// <param name="index">The zero-based index where copying will start.</param>
|
||||
public override sealed void CopyTo(T[] array, int index)
|
||||
{
|
||||
mBasisSet.CopyTo(array, index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of elements contained in this collection.
|
||||
/// </summary>
|
||||
public override sealed int Count
|
||||
{
|
||||
get { return mBasisSet.Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an object that can be used to synchronize use of the <c>Set</c> across threads.
|
||||
/// </summary>
|
||||
public override sealed bool IsSynchronized
|
||||
{
|
||||
get { return ((ICollection) mBasisSet).IsSynchronized; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an object that can be used to synchronize the <c>Set</c> between threads.
|
||||
/// </summary>
|
||||
public override sealed object SyncRoot
|
||||
{
|
||||
get { return ((ICollection) mBasisSet).SyncRoot; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enumerator for the elements in the <c>Set</c>.
|
||||
/// </summary>
|
||||
/// <returns>An <c>IEnumerator</c> over the elements in the <c>Set</c>.</returns>
|
||||
public override sealed IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return mBasisSet.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a clone of the <c>Set</c> instance.
|
||||
/// </summary>
|
||||
/// <returns>A clone of this object.</returns>
|
||||
public override sealed object Clone()
|
||||
{
|
||||
return new ImmutableSet<T>(mBasisSet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>a</c> or <c>b</c>.
|
||||
/// Neither this set nor the input set are modified during the operation. The return value
|
||||
/// is a <c>Clone()</c> of this set with the extra elements added in.
|
||||
/// </summary>
|
||||
/// <param name="a">A collection of elements.</param>
|
||||
/// <returns>A new <c>Set</c> containing the union of this <c>Set</c> with the specified collection.
|
||||
/// Neither of the input objects is modified by the union.</returns>
|
||||
public override sealed ISet<T> Union(ISet<T> a)
|
||||
{
|
||||
ISet<T> m = GetUltimateBasisSet();
|
||||
return new ImmutableSet<T>(m.Union(a));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>Intersect()</c> operation does not modify the input sets. It returns
|
||||
/// a <c>Clone()</c> of this set with the appropriate elements removed.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <returns>The intersection of this set with <c>a</c>.</returns>
|
||||
public override sealed ISet<T> Intersect(ISet<T> a)
|
||||
{
|
||||
ISet<T> m = GetUltimateBasisSet();
|
||||
return new ImmutableSet<T>(m.Intersect(a));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a "minus" of set <c>b</c> from set <c>a</c>. This returns a set of all
|
||||
/// the elements in set <c>a</c>, removing the elements that are also in set <c>b</c>.
|
||||
/// The original sets are not modified during this operation. The result set is a <c>Clone()</c>
|
||||
/// of this <c>Set</c> containing the elements from the operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <returns>A set containing the elements from this set with the elements in <c>a</c> removed.</returns>
|
||||
public override sealed ISet<T> Minus(ISet<T> a)
|
||||
{
|
||||
ISet<T> m = GetUltimateBasisSet();
|
||||
return new ImmutableSet<T>(m.Minus(a));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>Clone()</c> of this set containing
|
||||
/// the elements from the exclusive-or operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <returns>A set containing the result of <c>a ^ b</c>.</returns>
|
||||
public override sealed ISet<T> ExclusiveOr(ISet<T> a)
|
||||
{
|
||||
ISet<T> m = GetUltimateBasisSet();
|
||||
return new ImmutableSet<T>(m.ExclusiveOr(a));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the given instance is read-only
|
||||
/// </summary>
|
||||
public override sealed bool IsReadOnly
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs CopyTo when called trhough non-generic ISet (ICollection) interface
|
||||
/// </summary>
|
||||
/// <param name="array"></param>
|
||||
/// <param name="index"></param>
|
||||
protected override void NonGenericCopyTo(Array array, int index)
|
||||
{
|
||||
((ICollection) this.BasisSet).CopyTo(array, index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs Union when called trhough non-generic ISet interface
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
protected override sealed ISet NonGenericUnion(ISet a)
|
||||
{
|
||||
ISet<T> m = GetUltimateBasisSet();
|
||||
return new ImmutableSet(((ISet) m).Union(a));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs Minus when called trhough non-generic ISet interface
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
protected override sealed ISet NonGenericMinus(ISet a)
|
||||
{
|
||||
ISet<T> m = GetUltimateBasisSet();
|
||||
return new ImmutableSet(((ISet) m).Minus(a));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs Intersect when called trhough non-generic ISet interface
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
protected override sealed ISet NonGenericIntersect(ISet a)
|
||||
{
|
||||
ISet<T> m = GetUltimateBasisSet();
|
||||
return new ImmutableSet(((ISet) m).Intersect(a));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs ExclusiveOr when called trhough non-generic ISet interface
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
protected override sealed ISet NonGenericExclusiveOr(ISet a)
|
||||
{
|
||||
ISet<T> m = GetUltimateBasisSet();
|
||||
return new ImmutableSet(((ISet) m).ExclusiveOr(a));
|
||||
}
|
||||
|
||||
private ISet<T> GetUltimateBasisSet()
|
||||
{
|
||||
ISet<T> m = this.mBasisSet;
|
||||
while (m is ImmutableSet<T>)
|
||||
m = ((ImmutableSet<T>) m).mBasisSet;
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/Spring/Spring.Core/Collections/Generic/OrderedSet.cs
Normal file
30
src/Spring/Spring.Core/Collections/Generic/OrderedSet.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spring.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements an ordered <c>Set</c> based on a dictionary.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class OrderedSet<T> : DictionarySet<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OrderedSet{T}" /> class.
|
||||
/// </summary>
|
||||
public OrderedSet()
|
||||
{
|
||||
InternalDictionary = new Dictionary<T, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OrderedSet{T}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="initialValues">A collection of elements that defines the initial set contents.</param>
|
||||
public OrderedSet(ICollection<T> initialValues)
|
||||
: this()
|
||||
{
|
||||
AddAll(initialValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
561
src/Spring/Spring.Core/Collections/Generic/Set.cs
Normal file
561
src/Spring/Spring.Core/Collections/Generic/Set.cs
Normal file
@@ -0,0 +1,561 @@
|
||||
/* Copyright <20> 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spring.Collections.Generic
|
||||
{
|
||||
/// <summary><p>A collection that contains no duplicate elements. This class models the mathematical
|
||||
/// <c>Set</c> abstraction, and is the base class for all other <c>Set</c> implementations.
|
||||
/// The order of elements in a set is dependant on (a)the data-structure implementation, and
|
||||
/// (b)the implementation of the various <c>Set</c> methods, and thus is not guaranteed.</p>
|
||||
///
|
||||
/// <p>None of the <c>Set</c> implementations in this library are guranteed to be thread-safe
|
||||
/// in any way unless wrapped in a <c>SynchronizedSet</c>.</p>
|
||||
///
|
||||
/// <p>The following table summarizes the binary operators that are supported by the <c>Set</c> class.</p>
|
||||
/// <list type="table">
|
||||
/// <listheader>
|
||||
/// <term>Operation</term>
|
||||
/// <term>Description</term>
|
||||
/// <term>Method</term>
|
||||
/// <term>Operator</term>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>Union (OR)</term>
|
||||
/// <term>Element included in result if it exists in either <c>A</c> OR <c>B</c>.</term>
|
||||
/// <term><c>Union()</c></term>
|
||||
/// <term><c>|</c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Intersection (AND)</term>
|
||||
/// <term>Element included in result if it exists in both <c>A</c> AND <c>B</c>.</term>
|
||||
/// <term><c>InterSect()</c></term>
|
||||
/// <term><c>&</c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Exclusive Or (XOR)</term>
|
||||
/// <term>Element included in result if it exists in one, but not both, of <c>A</c> and <c>B</c>.</term>
|
||||
/// <term><c>ExclusiveOr()</c></term>
|
||||
/// <term><c>^</c></term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Minus (n/a)</term>
|
||||
/// <term>Take all the elements in <c>A</c>. Now, if any of them exist in <c>B</c>, remove
|
||||
/// them. Note that unlike the other operators, <c>A - B</c> is not the same as <c>B - A</c>.</term>
|
||||
/// <term><c>Minus()</c></term>
|
||||
/// <term><c>-</c></term>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class Set<T> : ISet<T>, ICollection<T>, IEnumerable<T>,
|
||||
ISet, ICollection, IEnumerable, ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// 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 <c>a</c> or <c>b</c>.
|
||||
/// Neither this set nor the input set are modified during the operation. The return value
|
||||
/// is a <c>Clone()</c> of this set with the extra elements added in.
|
||||
/// </summary>
|
||||
/// <param name="a">A collection of elements.</param>
|
||||
/// <returns>A new <c>Set</c> containing the union of this <c>Set</c> with the specified collection.
|
||||
/// Neither of the input objects is modified by the union.</returns>
|
||||
public virtual ISet<T> Union(ISet<T> a)
|
||||
{
|
||||
ISet<T> resultSet = (ISet<T>) this.Clone();
|
||||
if (a != null)
|
||||
{
|
||||
resultSet.AddAll(a);
|
||||
}
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>a</c> or <c>b</c>.
|
||||
/// The return value is a <c>Clone()</c> of one of the sets (<c>a</c> if it is not <see langword="null" />) with elements of the other set
|
||||
/// added in. Neither of the input sets is modified by the operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <param name="b">A set of elements.</param>
|
||||
/// <returns>A set containing the union of the input sets. <see langword="null" /> if both sets are <see langword="null" />.</returns>
|
||||
public static ISet<T> Union(ISet<T> a, ISet<T> b)
|
||||
{
|
||||
if (a == null && b == null)
|
||||
return null;
|
||||
else if (a == null)
|
||||
return (ISet<T>) b.Clone();
|
||||
else if (b == null)
|
||||
return (ISet<T>) a.Clone();
|
||||
else
|
||||
return a.Union(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>a</c> or <c>b</c>.
|
||||
/// The return value is a <c>Clone()</c> of one of the sets (<c>a</c> if it is not <see langword="null" />) with elements of the other set
|
||||
/// added in. Neither of the input sets is modified by the operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <param name="b">A set of elements.</param>
|
||||
/// <returns>A set containing the union of the input sets. <see langword="null" /> if both sets are <see langword="null" />.</returns>
|
||||
public static Set<T> operator |(Set<T> a, Set<T> b)
|
||||
{
|
||||
return (Set<T>) Union(a, b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>Intersect()</c> operation does not modify the input sets. It returns
|
||||
/// a <c>Clone()</c> of this set with the appropriate elements removed.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <returns>The intersection of this set with <c>a</c>.</returns>
|
||||
public virtual ISet<T> Intersect(ISet<T> a)
|
||||
{
|
||||
ISet<T> resultSet = (ISet<T>) this.Clone();
|
||||
if (a != null)
|
||||
resultSet.RetainAll(a);
|
||||
else
|
||||
resultSet.Clear();
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>a</c> and <c>b</c>. Neither input object is modified by the operation.
|
||||
/// The result object is a <c>Clone()</c> of one of the input objects (<c>a</c> if it is not <see langword="null" />) containing the
|
||||
/// elements from the intersect operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <param name="b">A set of elements.</param>
|
||||
/// <returns>The intersection of the two input sets. <see langword="null" /> if both sets are <see langword="null" />.</returns>
|
||||
public static ISet<T> Intersect(ISet<T> a, ISet<T> b)
|
||||
{
|
||||
if (a == null && b == null)
|
||||
return null;
|
||||
else if (a == null)
|
||||
{
|
||||
return b.Intersect(a);
|
||||
}
|
||||
else
|
||||
return a.Intersect(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>a</c> and <c>b</c>. Neither input object is modified by the operation.
|
||||
/// The result object is a <c>Clone()</c> of one of the input objects (<c>a</c> if it is not <see langword="null" />) containing the
|
||||
/// elements from the intersect operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <param name="b">A set of elements.</param>
|
||||
/// <returns>The intersection of the two input sets. <see langword="null" /> if both sets are <see langword="null" />.</returns>
|
||||
public static Set<T> operator &(Set<T> a, Set<T> b)
|
||||
{
|
||||
return (Set<T>) Intersect(a, b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a "minus" of set <c>b</c> from set <c>a</c>. This returns a set of all
|
||||
/// the elements in set <c>a</c>, removing the elements that are also in set <c>b</c>.
|
||||
/// The original sets are not modified during this operation. The result set is a <c>Clone()</c>
|
||||
/// of this <c>Set</c> containing the elements from the operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <returns>A set containing the elements from this set with the elements in <c>a</c> removed.</returns>
|
||||
public virtual ISet<T> Minus(ISet<T> a)
|
||||
{
|
||||
ISet<T> resultSet = (ISet<T>) this.Clone();
|
||||
if (a != null)
|
||||
resultSet.RemoveAll(a);
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a "minus" of set <c>b</c> from set <c>a</c>. This returns a set of all
|
||||
/// the elements in set <c>a</c>, removing the elements that are also in set <c>b</c>.
|
||||
/// The original sets are not modified during this operation. The result set is a <c>Clone()</c>
|
||||
/// of set <c>a</c> containing the elements from the operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <param name="b">A set of elements.</param>
|
||||
/// <returns>A set containing <c>A - B</c> elements. <see langword="null" /> if <c>a</c> is <see langword="null" />.</returns>
|
||||
public static ISet<T> Minus(ISet<T> a, ISet<T> b)
|
||||
{
|
||||
if (a == null)
|
||||
return null;
|
||||
else
|
||||
return a.Minus(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a "minus" of set <c>b</c> from set <c>a</c>. This returns a set of all
|
||||
/// the elements in set <c>a</c>, removing the elements that are also in set <c>b</c>.
|
||||
/// The original sets are not modified during this operation. The result set is a <c>Clone()</c>
|
||||
/// of set <c>a</c> containing the elements from the operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <param name="b">A set of elements.</param>
|
||||
/// <returns>A set containing <c>A - B</c> elements. <see langword="null" /> if <c>a</c> is <see langword="null" />.</returns>
|
||||
public static Set<T> operator -(Set<T> a, Set<T> b)
|
||||
{
|
||||
return (Set<T>) Minus(a, b);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>Clone()</c> of this set containing
|
||||
/// the elements from the exclusive-or operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <returns>A set containing the result of <c>a ^ b</c>.</returns>
|
||||
public virtual ISet<T> ExclusiveOr(ISet<T> a)
|
||||
{
|
||||
ISet<T> resultSet = (ISet<T>) this.Clone();
|
||||
foreach (T element in a)
|
||||
{
|
||||
if (resultSet.Contains(element))
|
||||
resultSet.Remove(element);
|
||||
else
|
||||
resultSet.Add(element);
|
||||
}
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>Clone()</c> of one of the sets
|
||||
/// (<c>a</c> if it is not <see langword="null" />) containing
|
||||
/// the elements from the exclusive-or operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <param name="b">A set of elements.</param>
|
||||
/// <returns>A set containing the result of <c>a ^ b</c>. <see langword="null" /> if both sets are <see langword="null" />.</returns>
|
||||
public static ISet<T> ExclusiveOr(ISet<T> a, ISet<T> b)
|
||||
{
|
||||
if (a == null && b == null)
|
||||
return null;
|
||||
else if (a == null)
|
||||
return (ISet<T>) b.Clone();
|
||||
else if (b == null)
|
||||
return (ISet<T>) a.Clone();
|
||||
else
|
||||
return a.ExclusiveOr(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>Clone()</c> of one of the sets
|
||||
/// (<c>a</c> if it is not <see langword="null" />) containing
|
||||
/// the elements from the exclusive-or operation.
|
||||
/// </summary>
|
||||
/// <param name="a">A set of elements.</param>
|
||||
/// <param name="b">A set of elements.</param>
|
||||
/// <returns>A set containing the result of <c>a ^ b</c>. <see langword="null" /> if both sets are <see langword="null" />.</returns>
|
||||
public static Set<T> operator ^(Set<T> a, Set<T> b)
|
||||
{
|
||||
return (Set<T>) ExclusiveOr(a, b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified element to this set if it is not already present.
|
||||
/// </summary>
|
||||
/// <param name="o">The object to add to the set.</param>
|
||||
/// <returns><see langword="true" /> is the object was added, <see langword="false" /> if it was already present.</returns>
|
||||
public abstract bool Add(T o);
|
||||
|
||||
/// <summary>
|
||||
/// Adds all the elements in the specified collection to the set if they are not already present.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of objects to add to the set.</param>
|
||||
/// <returns><see langword="true" /> is the set changed as a result of this operation, <see langword="false" /> if not.</returns>
|
||||
public abstract bool AddAll(ICollection<T> c);
|
||||
|
||||
/// <summary>
|
||||
/// Removes all objects from the set.
|
||||
/// </summary>
|
||||
public abstract void Clear();
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if this set contains the specified element.
|
||||
/// </summary>
|
||||
/// <param name="o">The element to look for.</param>
|
||||
/// <returns><see langword="true" /> if this set contains the specified element, <see langword="false" /> otherwise.</returns>
|
||||
public abstract bool Contains(T o);
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if the set contains all the elements in the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of objects.</param>
|
||||
/// <returns><see langword="true" /> if the set contains all the elements in the specified collection, <see langword="false" /> otherwise.</returns>
|
||||
public abstract bool ContainsAll(ICollection<T> c);
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if this set contains no elements.
|
||||
/// </summary>
|
||||
public abstract bool IsEmpty { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified element from the set.
|
||||
/// </summary>
|
||||
/// <param name="o">The element to be removed.</param>
|
||||
/// <returns><see langword="true" /> if the set contained the specified element, <see langword="false" /> otherwise.</returns>
|
||||
public abstract bool Remove(T o);
|
||||
|
||||
/// <summary>
|
||||
/// Remove all the specified elements from this set, if they exist in this set.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of elements to remove.</param>
|
||||
/// <returns><see langword="true" /> if the set was modified as a result of this operation.</returns>
|
||||
public abstract bool RemoveAll(ICollection<T> c);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retains only the elements in this set that are contained in the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="c">Collection that defines the set of elements to be retained.</param>
|
||||
/// <returns><see langword="true" /> if this set changed as a result of this operation.</returns>
|
||||
public abstract bool RetainAll(ICollection<T> c);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a clone of the <c>Set</c> instance. This will work for derived <c>Set</c>
|
||||
/// classes if the derived class implements a constructor that takes no arguments.
|
||||
/// </summary>
|
||||
/// <returns>A clone of this object.</returns>
|
||||
public virtual object Clone()
|
||||
{
|
||||
Set<T> newSet = (Set<T>) Activator.CreateInstance(this.GetType());
|
||||
newSet.AddAll(this);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements in the <c>Set</c> to an array. The type of array needs
|
||||
/// to be compatible with the objects in the <c>Set</c>, obviously.
|
||||
/// </summary>
|
||||
/// <param name="array">An array that will be the target of the copy operation.</param>
|
||||
/// <param name="index">The zero-based index where copying will start.</param>
|
||||
public abstract void CopyTo(T[] array, int index);
|
||||
|
||||
/// <summary>
|
||||
/// The number of elements currently contained in this collection.
|
||||
/// </summary>
|
||||
public abstract int Count { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if the <c>Set</c> is synchronized across threads. Note that
|
||||
/// enumeration is inherently not thread-safe. Use the <c>SyncRoot</c> to lock the
|
||||
/// object during enumeration.
|
||||
/// </summary>
|
||||
public abstract bool IsSynchronized { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 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 <c>IDictionary</c>,
|
||||
/// or anything that has a <c>SyncRoot</c>, return that object instead of "<c>this</c>".
|
||||
/// </summary>
|
||||
public abstract object SyncRoot { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enumerator for the elements in the <c>Set</c>.
|
||||
/// </summary>
|
||||
/// <returns>An <c>IEnumerator</c> over the elements in the <c>Set</c>.</returns>
|
||||
public abstract IEnumerator<T> GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the given instance is read-only or not
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <see langword="true" /> if the ISet is read-only; otherwise, <see langword="false" />.
|
||||
/// In the default implementation of Set, this property always returns false.
|
||||
/// </value>
|
||||
public virtual bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
void ICollection<T>.Add(T item)
|
||||
{
|
||||
this.Add(item);
|
||||
}
|
||||
|
||||
#region Protected helpers
|
||||
|
||||
/// <summary>
|
||||
/// Performs CopyTo when called trhough non-generic ISet (ICollection) interface
|
||||
/// </summary>
|
||||
/// <param name="array"></param>
|
||||
/// <param name="index"></param>
|
||||
protected abstract void NonGenericCopyTo(Array array, int index);
|
||||
|
||||
/// <summary>
|
||||
/// Performs Union when called trhough non-generic ISet interface
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual ISet NonGenericUnion(ISet a)
|
||||
{
|
||||
ISet resultSet = (ISet) this.Clone();
|
||||
if (a != null)
|
||||
resultSet.AddAll(a);
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs Minus when called trhough non-generic ISet interface
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual ISet NonGenericMinus(ISet a)
|
||||
{
|
||||
ISet resultSet = (ISet) this.Clone();
|
||||
if (a != null)
|
||||
resultSet.RemoveAll(a);
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs Intersect when called trhough non-generic ISet interface
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual ISet NonGenericIntersect(ISet a)
|
||||
{
|
||||
ISet resultSet = (ISet) this.Clone();
|
||||
if (a != null)
|
||||
resultSet.RetainAll(a);
|
||||
else
|
||||
resultSet.Clear();
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs ExclusiveOr when called trhough non-generic ISet interface
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <returns></returns>
|
||||
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<T> col = new List<T>(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<T> col = new List<T>(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<T> col = new List<T>(c.Count);
|
||||
foreach (object o in c)
|
||||
{
|
||||
if (o is T)
|
||||
col.Add((T) o);
|
||||
}
|
||||
return this.RetainAll(col);
|
||||
}
|
||||
|
||||
#endregion ISet implementation
|
||||
}
|
||||
}
|
||||
69
src/Spring/Spring.Core/Collections/Generic/SortedSet.cs
Normal file
69
src/Spring/Spring.Core/Collections/Generic/SortedSet.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
/* Copyright <20> 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spring.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a <c>Set</c> based on a sorted tree. This gives good performance for operations on very
|
||||
/// large data-sets, though not as good - asymptotically - as a <c>HashedSet</c>. However, iteration
|
||||
/// occurs in order. Elements that you put into this type of collection must implement <c>IComparable</c>,
|
||||
/// and they must actually be comparable. You can't mix <c>string</c> and <c>int</c> values, for example.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SortedSet<T> : DictionarySet<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new set instance based on a sorted tree.
|
||||
/// </summary>
|
||||
public SortedSet()
|
||||
{
|
||||
InternalDictionary = new SortedDictionary<T, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new set instance based on a sorted tree.
|
||||
/// </summary>
|
||||
/// <param name="comparer">The <see cref="IComparer<T>"/> to use for sorting.</param>
|
||||
public SortedSet(IComparer<T> comparer)
|
||||
{
|
||||
InternalDictionary = new SortedList<T, object>(comparer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new set instance based on a sorted tree and
|
||||
/// initializes it based on a collection of elements.
|
||||
/// </summary>
|
||||
/// <param name="initialValues">A collection of elements that defines the initial set contents.</param>
|
||||
public SortedSet(ICollection<T> initialValues)
|
||||
: this()
|
||||
{
|
||||
this.AddAll(initialValues);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new set instance based on a sorted tree and
|
||||
/// initializes it based on a collection of elements.
|
||||
/// </summary>
|
||||
/// <param name="initialValues">A collection of elements that defines the initial set contents.</param>
|
||||
public SortedSet(ICollection initialValues)
|
||||
: this()
|
||||
{
|
||||
((ISet) this).AddAll(initialValues);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new set instance based on a sorted tree and
|
||||
/// initializes it based on a collection of elements.
|
||||
/// </summary>
|
||||
/// <param name="initialValues">A collection of elements that defines the initial set contents.</param>
|
||||
/// <param name="comparer">The <see cref="IComparer<T>"/> to use for sorting.</param>
|
||||
public SortedSet(ICollection<T> initialValues, IComparer<T> comparer)
|
||||
: this(comparer)
|
||||
{
|
||||
this.AddAll(initialValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
262
src/Spring/Spring.Core/Collections/Generic/SynchronizedSet.cs
Normal file
262
src/Spring/Spring.Core/Collections/Generic/SynchronizedSet.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
/* Copyright <20> 2002-2004 by Aidant Systems, Inc., and by Jason Smith. */
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spring.Collections.Generic
|
||||
{
|
||||
/// <summary>
|
||||
/// <p>Implements a thread-safe <c>Set</c> 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 <c>lock</c> the <c>SyncRoot</c> object for the duration of the enumeration.</p>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class SynchronizedSet<T> : Set<T>
|
||||
{
|
||||
private ISet<T> mBasisSet;
|
||||
private object mSyncRoot;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a thread-safe <c>Set</c> wrapper.
|
||||
/// </summary>
|
||||
/// <param name="basisSet">The <c>Set</c> object that this object will wrap.</param>
|
||||
public SynchronizedSet(ISet<T> basisSet)
|
||||
{
|
||||
mBasisSet = basisSet;
|
||||
mSyncRoot = ((ICollection) basisSet).SyncRoot;
|
||||
if (mSyncRoot == null)
|
||||
throw new NullReferenceException("The Set you specified returned a null SyncRoot.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified element to this set if it is not already present.
|
||||
/// </summary>
|
||||
/// <param name="o">The object to add to the set.</param>
|
||||
/// <returns><see langword="true" /> is the object was added, <see langword="false" /> if it was already present.</returns>
|
||||
public override sealed bool Add(T o)
|
||||
{
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
return mBasisSet.Add(o);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all the elements in the specified collection to the set if they are not already present.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of objects to add to the set.</param>
|
||||
/// <returns><see langword="true" /> is the set changed as a result of this operation, <see langword="false" /> if not.</returns>
|
||||
public override sealed bool AddAll(ICollection<T> c)
|
||||
{
|
||||
Set<T> temp;
|
||||
lock (((ICollection) c).SyncRoot)
|
||||
{
|
||||
temp = new HashedSet<T>(c);
|
||||
}
|
||||
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
return mBasisSet.AddAll(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all objects from the set.
|
||||
/// </summary>
|
||||
public override sealed void Clear()
|
||||
{
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
mBasisSet.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if this set contains the specified element.
|
||||
/// </summary>
|
||||
/// <param name="o">The element to look for.</param>
|
||||
/// <returns><see langword="true" /> if this set contains the specified element, <see langword="false" /> otherwise.</returns>
|
||||
public override sealed bool Contains(T o)
|
||||
{
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
return mBasisSet.Contains(o);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if the set contains all the elements in the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of objects.</param>
|
||||
/// <returns><see langword="true" /> if the set contains all the elements in the specified collection, <see langword="false" /> otherwise.</returns>
|
||||
public override sealed bool ContainsAll(ICollection<T> c)
|
||||
{
|
||||
Set<T> temp;
|
||||
lock (((ICollection) c).SyncRoot)
|
||||
{
|
||||
temp = new HashedSet<T>(c);
|
||||
}
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
return mBasisSet.ContainsAll(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" /> if this set contains no elements.
|
||||
/// </summary>
|
||||
public override sealed bool IsEmpty
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
return mBasisSet.IsEmpty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified element from the set.
|
||||
/// </summary>
|
||||
/// <param name="o">The element to be removed.</param>
|
||||
/// <returns><see langword="true" /> if the set contained the specified element, <see langword="false" /> otherwise.</returns>
|
||||
public override sealed bool Remove(T o)
|
||||
{
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
return mBasisSet.Remove(o);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all the specified elements from this set, if they exist in this set.
|
||||
/// </summary>
|
||||
/// <param name="c">A collection of elements to remove.</param>
|
||||
/// <returns><see langword="true" /> if the set was modified as a result of this operation.</returns>
|
||||
public override sealed bool RemoveAll(ICollection<T> c)
|
||||
{
|
||||
Set<T> temp;
|
||||
lock (((ICollection) c).SyncRoot)
|
||||
{
|
||||
temp = new HashedSet<T>(c);
|
||||
}
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
return mBasisSet.RemoveAll(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retains only the elements in this set that are contained in the specified collection.
|
||||
/// </summary>
|
||||
/// <param name="c">Collection that defines the set of elements to be retained.</param>
|
||||
/// <returns><see langword="true" /> if this set changed as a result of this operation.</returns>
|
||||
public override sealed bool RetainAll(ICollection<T> c)
|
||||
{
|
||||
Set<T> temp;
|
||||
lock (((ICollection) c).SyncRoot)
|
||||
{
|
||||
temp = new HashedSet<T>(c);
|
||||
}
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
return mBasisSet.RetainAll(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements in the <c>Set</c> to an array. The type of array needs
|
||||
/// to be compatible with the objects in the <c>Set</c>, obviously.
|
||||
/// </summary>
|
||||
/// <param name="array">An array that will be the target of the copy operation.</param>
|
||||
/// <param name="index">The zero-based index where copying will start.</param>
|
||||
public override sealed void CopyTo(T[] array, int index)
|
||||
{
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
mBasisSet.CopyTo(array, index);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of elements contained in this collection.
|
||||
/// </summary>
|
||||
public override sealed int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
return mBasisSet.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true" />, indicating that this object is thread-safe. The exception to this
|
||||
/// is enumeration, which is inherently not thread-safe. Use the <c>SyncRoot</c> object to
|
||||
/// lock this object for the entire duration of the enumeration.
|
||||
/// </summary>
|
||||
public override sealed bool IsSynchronized
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an object that can be used to synchronize the <c>Set</c> between threads.
|
||||
/// </summary>
|
||||
public override sealed object SyncRoot
|
||||
{
|
||||
get { return mSyncRoot; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumeration is, by definition, not thread-safe. Use a <c>lock</c> on the <c>SyncRoot</c>
|
||||
/// to synchronize the entire enumeration process.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override sealed IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return mBasisSet.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a clone of the <c>Set</c> instance.
|
||||
/// </summary>
|
||||
/// <returns>A clone of this object.</returns>
|
||||
public override object Clone()
|
||||
{
|
||||
return new SynchronizedSet((ISet) mBasisSet.Clone());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether given instace is read-only or not
|
||||
/// </summary>
|
||||
public override bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
return mBasisSet.IsReadOnly;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs CopyTo when called trhough non-generic ISet (ICollection) interface
|
||||
/// </summary>
|
||||
/// <param name="array"></param>
|
||||
/// <param name="index"></param>
|
||||
protected override void NonGenericCopyTo(Array array, int index)
|
||||
{
|
||||
lock (mSyncRoot)
|
||||
{
|
||||
((ICollection) this.mBasisSet).CopyTo(array, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Spring.Context.Annotation
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a class declares one or more <see cref="Definition"/> methods and may be processed
|
||||
/// by the Spring container to generate object definitions and service requests for those objects
|
||||
/// at runtime.
|
||||
///
|
||||
/// <para>Configuration is meta-annotated as a {@link Component}, therefore Configuration
|
||||
/// classes are candidates for component-scanning and may also take advantage of
|
||||
/// <see cref="AutoWired"/> at the field and method but not at the constructor level.
|
||||
/// </para>
|
||||
/// <para>May be used in conjunction with the <see cref="Lazy"/> attribute to indicate that all object
|
||||
/// methods declared within this class are by default lazily initialized.
|
||||
///</para>
|
||||
/// <h3>Constraints</h3>
|
||||
/// <ul>
|
||||
/// <li>Configuration classes must be non-final</li>
|
||||
/// <li>Configuration classes must be non-local (may not be declared within a method)</li>
|
||||
/// <li>Configuration classes must have a default/no-arg constructor and may not use
|
||||
/// {@link Autowired} constructor parameters</li>
|
||||
/// </ul>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ConfigurationAttribute : Attribute
|
||||
{
|
||||
private string _name;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Configuration class.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
public ConfigurationAttribute(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
///
|
||||
/// <para>The custom name applies only if the Configuration class is picked up via
|
||||
/// component scanning or supplied directly to a <see cref="AnnotationConfigApplicationContext"/>.
|
||||
/// If the Configuration class is registered as a traditional XML object definition,
|
||||
/// the name/id of the object element will take precedence.
|
||||
/// </para>
|
||||
/// <see cref="Spring.Objects.Factory.Support.DefaultObjectNameGenerator"/>
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
163
src/Spring/Spring.Core/Context/Annotation/ConfigurationClass.cs
Normal file
163
src/Spring/Spring.Core/Context/Annotation/ConfigurationClass.cs
Normal file
@@ -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<string, Type> _importedResources = new Dictionary<string, Type>();
|
||||
|
||||
private ISet<ConfigurationClassMethod> _methods = new HashedSet<ConfigurationClassMethod>();
|
||||
|
||||
private string _objectName;
|
||||
|
||||
private IResource _resource;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ConfigurationClass class.
|
||||
/// </summary>
|
||||
/// <param name="objectName"></param>
|
||||
/// <param name="type"></param>
|
||||
public ConfigurationClass(string objectName, Type type)
|
||||
{
|
||||
this._objectName = objectName;
|
||||
this._configurationClassType = type;
|
||||
}
|
||||
|
||||
public Type ConfigurationClassType
|
||||
{
|
||||
get
|
||||
{
|
||||
return _configurationClassType;
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionary<string, Type> ImportedResources
|
||||
{
|
||||
get
|
||||
{
|
||||
return _importedResources;
|
||||
}
|
||||
}
|
||||
|
||||
public ISet<ConfigurationClassMethod> 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<String, int> methodNameCounts = new Dictionary<String, int>();
|
||||
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))
|
||||
{ }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ConfigurationClassMethod class.
|
||||
/// </summary>
|
||||
/// <param name="methodInfo"></param>
|
||||
/// <param name="configurationClass"></param>
|
||||
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)
|
||||
{ }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ConfigurationClassObjectDefinitionReader class.
|
||||
/// </summary>
|
||||
/// <param name="registry"></param>
|
||||
/// <param name="problemReporter"></param>
|
||||
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<ConfigurationClass> 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<String, Object> beanAttributes = metadata.getAnnotationAttributes(Bean.class.getName());
|
||||
object[] objectAttributes = metadata.GetCustomAttributes(typeof(DefinitionAttribute), true);
|
||||
List<string> names = new List<string>();
|
||||
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<string, Type> importedResources)
|
||||
{
|
||||
IDictionary<Type, IObjectDefinitionReader> readerInstanceCache = new Dictionary<Type, IObjectDefinitionReader>();
|
||||
foreach (KeyValuePair<string, Type> 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
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<ConfigurationClass> _configurationClasses = new HashedSet<ConfigurationClass>();
|
||||
|
||||
private Stack<ConfigurationClass> _importStack = new Stack<ConfigurationClass>();
|
||||
|
||||
private IProblemReporter _problemReporter;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ConfigurationClassParser class.
|
||||
/// </summary>
|
||||
/// <param name="problemReporter"></param>
|
||||
public ConfigurationClassParser(IProblemReporter problemReporter)
|
||||
{
|
||||
_problemReporter = problemReporter;
|
||||
}
|
||||
|
||||
public ISet<ConfigurationClass> 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<MethodInfo> definitionMethods = GetAllMethodsWithCustomAttributeForClass(configurationClass.ConfigurationClassType, typeof(DefinitionAttribute));
|
||||
foreach (MethodInfo definitionMethod in definitionMethods)
|
||||
{
|
||||
configurationClass.Methods.Add(new ConfigurationClassMethod(definitionMethod, configurationClass));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private ISet<MethodInfo> GetAllMethodsWithCustomAttributeForClass(Type theClass, Type customAttribute)
|
||||
{
|
||||
ISet<MethodInfo> methods = new HashedSet<MethodInfo>();
|
||||
|
||||
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<ConfigurationClass> 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)
|
||||
)
|
||||
{ }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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<ObjectDefinitionHolder> configCandidates = new HashedSet<ObjectDefinitionHolder>();
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Are dependencies to be injected via autowiring?
|
||||
/// </summary>
|
||||
/// <value>The auto wire.</value>
|
||||
public AutoWiringMode AutoWire
|
||||
{
|
||||
get { return _autoWire; }
|
||||
set
|
||||
{
|
||||
_autoWire = value;
|
||||
}
|
||||
}
|
||||
private string _destroyMethod;
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// <para>
|
||||
/// 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.
|
||||
/// </para>
|
||||
/// <see cref="Spring.Context.IConfigurableApplicationContext"/>
|
||||
/// </summary>
|
||||
/// <value>The destroy method.</value>
|
||||
public string DestroyMethod
|
||||
{
|
||||
get { return _destroyMethod; }
|
||||
set
|
||||
{
|
||||
_destroyMethod = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <value>The init method.</value>
|
||||
public string InitMethod
|
||||
{
|
||||
get { return _initMethod; }
|
||||
set
|
||||
{
|
||||
_initMethod = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
public string[] Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Spring.Context.Annotation
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// <para>Note: This attribute will not be inherited by child object definitions,
|
||||
/// hence it needs to be specified per concrete object definition.
|
||||
/// </para>
|
||||
/// <para>Using <see cref="DependsOn"/> at the class level has no effect unless component-scanning
|
||||
/// is being used. If a <see cref="DependsOn"/>-attributed class is declared via XML,
|
||||
/// <see cref="DependsOn"/> attribute metadata is ignored, and
|
||||
/// <object depends-on="..."/> is respected instead.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
|
||||
public class DependsOnAttribute : Attribute
|
||||
{
|
||||
private string[] _name;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the DependsOn class.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
public DependsOnAttribute(string[] name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public string[] Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
53
src/Spring/Spring.Core/Context/Annotation/ImportAttribute.cs
Normal file
53
src/Spring/Spring.Core/Context/Annotation/ImportAttribute.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Spring.Context.Annotation
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates one or more <see cref="Configuration"/> classes to import.
|
||||
///
|
||||
/// <para>Provides functionality equivalent to the :lt;import/> element in Spring XML.
|
||||
/// Only supported for actual <see cref="Configuration"/>-attributed classes.
|
||||
/// </para>
|
||||
///
|
||||
/// <para><see cref="Definition"/> definitions declared in imported <see cref="Configuration"/> classes
|
||||
/// should be accessed by using <see cref="AutoWired"/> 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
|
||||
/// <see cref="Configuration"/> class methods.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>If XML or other non-<see cref="Configuration"/> object definition resources need to be
|
||||
/// imported, use <see cref="ImportResource"/>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ImportAttribute : Attribute
|
||||
{
|
||||
private Type[] _types;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Import class.
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
public ImportAttribute(Type[] types)
|
||||
{
|
||||
_types = types;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Configuration"/> class or classes to import.
|
||||
/// </summary>
|
||||
/// <value>The type.</value>
|
||||
public Type[] Types
|
||||
{
|
||||
get { return _types; }
|
||||
set
|
||||
{
|
||||
_types = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ImportResourceAttribute : Attribute
|
||||
{
|
||||
private IObjectDefinitionReader _objectDefinitionReader;
|
||||
|
||||
private string[] _resources;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ImportResource class.
|
||||
/// </summary>
|
||||
/// <param name="objectDefinitionReader"></param>
|
||||
/// <param name="resources"></param>
|
||||
public ImportResourceAttribute(IObjectDefinitionReader objectDefinitionReader, string[] resources)
|
||||
{
|
||||
_objectDefinitionReader = objectDefinitionReader;
|
||||
_resources = resources;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="IObjectDefinitionReader"/> implementation to use when processing resources specified
|
||||
/// by the <see cref="Resources"/> attribute.
|
||||
/// </summary>
|
||||
/// <value>The <see cref="IObjectDefinitionReader"/>.</value>
|
||||
public IObjectDefinitionReader DefinitionReader
|
||||
{
|
||||
get { return _objectDefinitionReader; }
|
||||
set
|
||||
{
|
||||
_objectDefinitionReader = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resource paths to import. Resource-loading prefixes such as <code>assembly://</code> and
|
||||
/// <code>file://</code>, etc may be used.
|
||||
/// </summary>
|
||||
/// <value>The resources.</value>
|
||||
public string[] Resources
|
||||
{
|
||||
get { return _resources; }
|
||||
set
|
||||
{
|
||||
_resources = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
53
src/Spring/Spring.Core/Context/Annotation/LazyAttrribute.cs
Normal file
53
src/Spring/Spring.Core/Context/Annotation/LazyAttrribute.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Spring.Context.Annotation
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether a object is to be lazily initialized.
|
||||
///
|
||||
/// <para>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 <see cref="Spring.Objects.Factory.IObjectFactory"/>.
|
||||
/// If present and set to false, the object will be instantiated on startup by object factories
|
||||
/// that perform eager initialization of singletons.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If Lazy is present on a <see cref="Configuration"/> class, this indicates that all
|
||||
/// <see cref="Definition"/> methods within that <see cref="Configuration"/> 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.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
|
||||
public class LazyAttrribute : Attribute
|
||||
{
|
||||
private bool _lazyInitialize = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Lazy class.
|
||||
/// </summary>
|
||||
/// <param name="lazyInitialize"></param>
|
||||
public LazyAttrribute(bool lazyInitialize)
|
||||
{
|
||||
_lazyInitialize = lazyInitialize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether lazy initialization should occur.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [lazy initialize]; otherwise, <c>false</c>.</value>
|
||||
public bool LazyInitialize
|
||||
{
|
||||
get { return _lazyInitialize; }
|
||||
set
|
||||
{
|
||||
_lazyInitialize = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Spring.Context.Annotation
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
///
|
||||
/// <para>Using <see cref="Primary"/> at the class level has no effect unless component-scanning
|
||||
/// is being used. If a <see cref="Primary"/>-attributed class is declared via XML,
|
||||
/// <see cref="Primary"/> attribute metadata is ignored, and
|
||||
/// <code><object primary="true|false"/>></code> is respected instead.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class PrimaryAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
48
src/Spring/Spring.Core/Context/Annotation/ScopeAttribute.cs
Normal file
48
src/Spring/Spring.Core/Context/Annotation/ScopeAttribute.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Spring.Objects.Factory.Support;
|
||||
|
||||
namespace Spring.Context.Annotation
|
||||
{
|
||||
/// <summary>
|
||||
/// When used as a type-level attribute, indicates the name of a scope to use
|
||||
/// for instances of the attributed type.
|
||||
///
|
||||
/// <para>When used as a method-level attribute in conjunction with the
|
||||
/// <see cref="Definition"/> attribute, indicates the name of a scope to use for
|
||||
/// the instance returned from the method.
|
||||
/// </para>
|
||||
/// <para>In this context, scope means the lifecycle of an instance, such as
|
||||
/// <code>singleton</code>, <code>prototype</code>, and so forth.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class ScopeAttribute : Attribute
|
||||
{
|
||||
private ObjectScope _scope = ObjectScope.Singleton;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Scope class.
|
||||
/// </summary>
|
||||
/// <param name="scope"></param>
|
||||
public ScopeAttribute(ObjectScope scope)
|
||||
{
|
||||
_scope = scope;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the scope to use for the annotated object.
|
||||
/// </summary>
|
||||
/// <value>The scope.</value>
|
||||
public ObjectScope ObjectScope
|
||||
{
|
||||
get { return _scope; }
|
||||
set
|
||||
{
|
||||
_scope = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
52
src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs
Normal file
52
src/Spring/Spring.Core/Objects/Factory/Parsing/Location.cs
Normal file
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Location class.
|
||||
/// </summary>
|
||||
/// <param name="resource"></param>
|
||||
/// <param name="source"></param>
|
||||
public Location(IResource resource, object source)
|
||||
{
|
||||
AssertUtils.ArgumentNotNull(resource, "resource");
|
||||
this.resource = resource;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Location class.
|
||||
/// </summary>
|
||||
/// <param name="resource"></param>
|
||||
public Location(IResource resource)
|
||||
: this(resource, null)
|
||||
{
|
||||
|
||||
}
|
||||
public IResource Resource
|
||||
{
|
||||
get
|
||||
{
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
public object Source
|
||||
{
|
||||
get
|
||||
{
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ObjectDefinitionParsingException class.
|
||||
/// </summary>
|
||||
public ObjectDefinitionParsingException(Problem problem)
|
||||
: base(problem.Location.Resource, problem.ResourceDescription, problem.Message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
78
src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs
Normal file
78
src/Spring/Spring.Core/Objects/Factory/Parsing/Problem.cs
Normal file
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Problem class.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="resource"></param>
|
||||
public Problem(string message, Location location)
|
||||
: this(message, location, null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Problem class.
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="location"></param>
|
||||
/// <param name="rootCause"></param>
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -125,7 +125,15 @@
|
||||
<Compile Include="Collections\DictionarySet.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Collections\Generic\DictionarySet.cs" />
|
||||
<Compile Include="Collections\Generic\HashedSet.cs" />
|
||||
<Compile Include="Collections\Generic\ImmutableSet.cs" />
|
||||
<Compile Include="Collections\Generic\ISet.cs" />
|
||||
<Compile Include="Collections\Generic\OrderedSet.cs" />
|
||||
<Compile Include="Collections\Generic\ReadOnlyDictionary.cs" />
|
||||
<Compile Include="Collections\Generic\Set.cs" />
|
||||
<Compile Include="Collections\Generic\SortedSet.cs" />
|
||||
<Compile Include="Collections\Generic\SynchronizedSet.cs" />
|
||||
<Compile Include="Collections\HashedSet.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
@@ -163,6 +171,19 @@
|
||||
<Compile Include="Collections\SynchronizedSet.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Context\Annotation\ConfigurationAttribute.cs" />
|
||||
<Compile Include="Context\Annotation\ConfigurationClass.cs" />
|
||||
<Compile Include="Context\Annotation\ConfigurationClassMethod.cs" />
|
||||
<Compile Include="Context\Annotation\ConfigurationClassObjectDefinitionReader.cs" />
|
||||
<Compile Include="Context\Annotation\ConfigurationClassParser.cs" />
|
||||
<Compile Include="Context\Annotation\ConfigurationClassPostProcessor.cs" />
|
||||
<Compile Include="Context\Annotation\DefinitionAttribute.cs" />
|
||||
<Compile Include="Context\Annotation\DependsOnAttribute.cs" />
|
||||
<Compile Include="Context\Annotation\ImportAttribute.cs" />
|
||||
<Compile Include="Context\Annotation\ImportResourceAttribute.cs" />
|
||||
<Compile Include="Context\Annotation\LazyAttrribute.cs" />
|
||||
<Compile Include="Context\Annotation\PrimaryAttribute.cs" />
|
||||
<Compile Include="Context\Annotation\ScopeAttribute.cs" />
|
||||
<Compile Include="Context\ApplicationContextException.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
@@ -695,7 +716,14 @@
|
||||
<Compile Include="Objects\Factory\Config\IVariableSource.cs" />
|
||||
<Compile Include="Objects\Factory\Config\VariableAccessor.cs" />
|
||||
<Compile Include="Objects\Factory\Config\VariablePlaceholderConfigurer.cs" />
|
||||
<Compile Include="Objects\Factory\Parsing\FailFastProblemReporter.cs" />
|
||||
<Compile Include="Objects\Factory\Parsing\IProblemReporter.cs" />
|
||||
<Compile Include="Objects\Factory\Parsing\Location.cs" />
|
||||
<Compile Include="Objects\Factory\Parsing\ObjectDefinitionParsingException.cs" />
|
||||
<Compile Include="Objects\Factory\Parsing\Problem.cs" />
|
||||
<Compile Include="Objects\Factory\Parsing\ReaderContext.cs" />
|
||||
<Compile Include="Objects\Factory\Support\IObjectDefinitionRegistryPostProcessor.cs" />
|
||||
<Compile Include="Objects\Factory\Support\ObjectScope.cs" />
|
||||
<Compile Include="Util\ConstructorInstantiationInfo.cs" />
|
||||
<Compile Include="Objects\Factory\Support\GenericObjectDefinition.cs" />
|
||||
<Compile Include="Objects\Factory\Support\IAutowireCandidateResolver.cs" />
|
||||
|
||||
@@ -169,7 +169,6 @@
|
||||
</Compile>
|
||||
<Compile Include="Objects\Factory\Support\ChildWebObjectDefinition.cs" />
|
||||
<Compile Include="Objects\Factory\Support\IWebObjectDefinition.cs" />
|
||||
<Compile Include="Objects\Factory\Support\ObjectScope.cs" />
|
||||
<Compile Include="Objects\Factory\Support\RootWebObjectDefinition.cs" />
|
||||
<Compile Include="Objects\Factory\Support\WebInstantiationStrategy.cs" />
|
||||
<Compile Include="Objects\Factory\Support\WebObjectDefinitionFactory.cs" />
|
||||
|
||||
Reference in New Issue
Block a user