diff --git a/src/Umbraco.Core/Resolving/ManyWeightedResolved.cs b/src/Umbraco.Core/Resolving/ManyWeightedResolved.cs new file mode 100644 index 0000000000..c8d56b8c67 --- /dev/null +++ b/src/Umbraco.Core/Resolving/ManyWeightedResolved.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Umbraco.Core.Resolving +{ + public class ManyWeightedResolved + { + List _resolved = new List(); + Dictionary _weights = new Dictionary(); + + public ManyWeightedResolved() + { + Resolution.Frozen += (sender, e) => + { + _resolved = _resolved.OrderBy(r => _weights[r.GetType()]).ToList(); + _weights = null; + }; + } + + public ManyWeightedResolved(IEnumerable resolved) + : this() + { + _resolved.AddRange(resolved); + foreach (var type in _resolved.Select(r => r.GetType())) + _weights.Add(type, ResolutionWeightAttribute.ReadWeight(type)); + } + + public IEnumerable Values + { + get { return _resolved; } + } + + #region Manage collection + + public void Add(TResolved value) + { + Resolution.EnsureNotFrozen(); + + var type = value.GetType(); + EnsureNotExists(type); + _resolved.Add(value); + _weights[type] = ResolutionWeightAttribute.ReadWeight(type); + } + + public void Add(TResolved value, int weight) + { + Resolution.EnsureNotFrozen(); + + var type = value.GetType(); + EnsureNotExists(type); + _resolved.Add(value); + _weights[type] = weight; + } + + public void AddRange(IEnumerable values) + { + Resolution.EnsureNotFrozen(); + + foreach (var value in values) + { + var type = value.GetType(); + EnsureNotExists(type); + _resolved.Add(value); + _weights[type] = ResolutionWeightAttribute.ReadWeight(type); + } + } + + //public void SetWeight(TResolved value, int weight) + //{ + // Resolution.EnsureNotFrozen(); + + // var type = value.GetType(); + // EnsureExists(type); + // _weights[type] = weight; + //} + + public void SetWeight(int weight) + { + Resolution.EnsureNotFrozen(); + + var type = typeof(TResolving); + EnsureExists(type); + _weights[type] = weight; + } + + //public int GetWeight(TResolved value) + //{ + // var type = value.GetType(); + // EnsureExists(type); + // return _weights[value.GetType()]; + //} + + public int GetWeight() + { + var type = typeof(TResolving); + EnsureExists(type); + return _weights[type]; + } + + //public void Remove(TResolved value) + //{ + // Resolution.EnsureNotFrozen(); + + // var type = value.GetType(); + // var remove = _resolved.SingleOrDefault(r => r.GetType() == type); + // if (remove != null) + // { + // _resolved.Remove(remove); + // _weights.Remove(remove.GetType()); + // } + //} + + public void Remove() + { + Resolution.EnsureNotFrozen(); + + var type = typeof(TResolving); + var remove = _resolved.SingleOrDefault(r => r.GetType() == type); + if (remove != null) + { + _resolved.Remove(remove); + _weights.Remove(remove.GetType()); + } + } + + public void Clear() + { + Resolution.EnsureNotFrozen(); + + _resolved = new List(); + _weights = new Dictionary(); + } + + #endregion + + #region Utilities + + public bool Exists(Type type) + { + return _resolved.Any(r => r.GetType() == type); + } + + void EnsureExists(Type type) + { + if (!Exists(type)) + throw new InvalidOperationException("There is not value of that type in the collection."); + } + + void EnsureNotExists(Type type) + { + if (Exists(type)) + throw new InvalidOperationException("A value of that type already exists in the collection."); + } + + #endregion + } +} diff --git a/src/Umbraco.Core/Resolving/ManyWeightedResolverBase.cs b/src/Umbraco.Core/Resolving/ManyWeightedResolverBase.cs new file mode 100644 index 0000000000..fb68db0d47 --- /dev/null +++ b/src/Umbraco.Core/Resolving/ManyWeightedResolverBase.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Umbraco.Core.Resolving +{ + public abstract class ManyWeightedResolverBase : ResolverBase + { + ManyWeightedResolved _resolved; + + protected ManyWeightedResolverBase() + { + _resolved = new ManyWeightedResolved(); + } + + protected ManyWeightedResolverBase(IEnumerable values) + { + _resolved = new ManyWeightedResolved(values); + } + + protected IEnumerable Values + { + get { return _resolved.Values; } + } + + #region Manage collection + + public void Add(TResolved value) + { + _resolved.Add(value); + } + + public void Add(TResolved value, int weight) + { + _resolved.Add(value, weight); + } + + public void AddRange(IEnumerable values) + { + _resolved.AddRange(values); + } + + public void SetWeight(int weight) + { + _resolved.SetWeight(weight); + } + + public int GetWeight() + { + return _resolved.GetWeight(); + } + + public void Remove() + { + _resolved.Remove(); + } + + public void Clear() + { + _resolved.Clear(); + } + + #endregion + } +} diff --git a/src/Umbraco.Core/Resolving/Resolution.cs b/src/Umbraco.Core/Resolving/Resolution.cs new file mode 100644 index 0000000000..96349d645b --- /dev/null +++ b/src/Umbraco.Core/Resolving/Resolution.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Umbraco.Core.Resolving +{ + // notes: nothing in Resolving is thread-safe because everything should happen when the app is starting + + public class Resolution + { + public static event EventHandler Freezing; + public static event EventHandler Frozen; + + public static bool IsFrozen { get; private set; } + + public static void EnsureNotFrozen() + { + if (Resolution.IsFrozen) + throw new InvalidOperationException("Resolution is frozen. It is not possible to modify resolvers once resolution is frozen."); + } + + public static void Freeze() + { + if (Resolution.IsFrozen) + throw new InvalidOperationException("Resolution is frozen. It is not possible to freeze it again."); + if (Freezing != null) + Freezing(null, null); + IsFrozen = true; + if (Frozen != null) + Frozen(null, null); + } + } +} diff --git a/src/Umbraco.Core/Resolving/ResolutionWeightAttribute.cs b/src/Umbraco.Core/Resolving/ResolutionWeightAttribute.cs new file mode 100644 index 0000000000..c31e0a6b66 --- /dev/null +++ b/src/Umbraco.Core/Resolving/ResolutionWeightAttribute.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Umbraco.Core.Resolving +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=false)] + public class ResolutionWeightAttribute : Attribute + { + public const int DefaultWeight = 100; + + public ResolutionWeightAttribute(int weight) + { + this.Weight = weight; + } + + public int Weight { get; private set; } + + public static int ReadWeight(Type type) + { + var attr = type.GetCustomAttribute(false); + return attr != null ? attr.Weight : DefaultWeight; + } + } +} diff --git a/src/Umbraco.Core/Resolving/ResolverBase.cs b/src/Umbraco.Core/Resolving/ResolverBase.cs new file mode 100644 index 0000000000..023eaecdc7 --- /dev/null +++ b/src/Umbraco.Core/Resolving/ResolverBase.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading; + +namespace Umbraco.Core.Resolving +{ + public abstract class ResolverBase + { + static TResolver _resolver; + static readonly ReaderWriterLockSlim ResolversLock = new ReaderWriterLockSlim(); + + public static TResolver Current + { + get + { + using (new ReadLock(ResolversLock)) + { + if (_resolver == null) + throw new InvalidOperationException("Current has not been initialized. You must initialize Current before trying to read it."); + return _resolver; + } + } + + set + { + using (new WriteLock(ResolversLock)) + { + if (value == null) + throw new ArgumentNullException("value"); + if (_resolver != null) + throw new InvalidOperationException("Current has already been initialized. It is not possible to re-initialize Current once it has been initialized."); + _resolver = value; + } + } + } + } +} diff --git a/src/Umbraco.Core/Resolving/SingleResolved.cs b/src/Umbraco.Core/Resolving/SingleResolved.cs new file mode 100644 index 0000000000..065ad30898 --- /dev/null +++ b/src/Umbraco.Core/Resolving/SingleResolved.cs @@ -0,0 +1,48 @@ +using System; + +namespace Umbraco.Core.Resolving +{ + public class SingleResolved + { + TResolved _resolved; + bool _canBeNull; + + public SingleResolved() + : this(false) + { } + + public SingleResolved(TResolved value) + : this(false) + { + _resolved = value; + } + + public SingleResolved(bool canBeNull) + { + _canBeNull = canBeNull; + } + + public SingleResolved(TResolved value, bool canBeNull) + { + _resolved = value; + _canBeNull = canBeNull; + } + + public TResolved Value + { + get + { + return _resolved; + } + + set + { + Resolution.EnsureNotFrozen(); + + if (!_canBeNull && value == null) + throw new ArgumentNullException("value"); + _resolved = value; + } + } + } +} diff --git a/src/Umbraco.Core/Resolving/SingleResolverBase.cs b/src/Umbraco.Core/Resolving/SingleResolverBase.cs new file mode 100644 index 0000000000..7ca86b1cb3 --- /dev/null +++ b/src/Umbraco.Core/Resolving/SingleResolverBase.cs @@ -0,0 +1,48 @@ +using System; + +namespace Umbraco.Core.Resolving +{ + public abstract class SingleResolverBase : ResolverBase + { + TResolved _resolved; + bool _canBeNull; + + protected SingleResolverBase() + : this(false) + { } + + protected SingleResolverBase(TResolved value) + : this(false) + { + _resolved = value; + } + + protected SingleResolverBase(bool canBeNull) + { + _canBeNull = canBeNull; + } + + protected SingleResolverBase(TResolved value, bool canBeNull) + { + _resolved = value; + _canBeNull = canBeNull; + } + + protected TResolved Value + { + get + { + return _resolved; + } + + set + { + Resolution.EnsureNotFrozen(); + + if (!_canBeNull && value == null) + throw new ArgumentNullException("value"); + _resolved = value; + } + } + } +} diff --git a/src/Umbraco.Core/TypeExtensions.cs b/src/Umbraco.Core/TypeExtensions.cs new file mode 100644 index 0000000000..4813f23243 --- /dev/null +++ b/src/Umbraco.Core/TypeExtensions.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Umbraco.Core +{ + public static class TypeExtensions + { + public static IEnumerable GetCustomAttributes(this Type type, bool inherit) + { + return type.GetCustomAttributes(typeof(T), inherit).Cast(); + } + + public static T GetCustomAttribute(this Type type, bool inherit) + { + return type.GetCustomAttributes(inherit).SingleOrDefault(); + } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 9c5101ff36..50e972ac1a 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -45,6 +45,14 @@ Properties\SolutionInfo.cs + + + + + + + + @@ -63,6 +71,7 @@ umbraco.businesslogic +