From 6b4fff176a21e84b2184cfa5640293ebaef760c3 Mon Sep 17 00:00:00 2001 From: sgay Date: Thu, 26 Jul 2012 07:52:13 -0200 Subject: [PATCH 1/3] refactor resolution of components --- .../Resolving/ManyWeightedResolved.cs | 159 ++++++++++++++++++ .../Resolving/ManyWeightedResolverBase.cs | 66 ++++++++ src/Umbraco.Core/Resolving/Resolution.cs | 34 ++++ .../Resolving/ResolutionWeightAttribute.cs | 26 +++ src/Umbraco.Core/Resolving/ResolverBase.cs | 36 ++++ src/Umbraco.Core/Resolving/SingleResolved.cs | 48 ++++++ .../Resolving/SingleResolverBase.cs | 48 ++++++ src/Umbraco.Core/TypeExtensions.cs | 20 +++ src/Umbraco.Core/Umbraco.Core.csproj | 9 + src/Umbraco.Web/Routing/DocumentRequest.cs | 7 +- src/Umbraco.Web/Routing/IRoutesCache.cs | 8 + .../NiceUrlProvider.cs} | 33 +++- .../RequestDocumentResolverWeightAttribute.cs | 31 ---- .../RequestDocumentResolversResolver.cs | 48 ++++++ src/Umbraco.Web/Routing/ResolveByAlias.cs | 3 +- src/Umbraco.Web/Routing/ResolveById.cs | 3 +- src/Umbraco.Web/Routing/ResolveByNiceUrl.cs | 3 +- .../Routing/ResolveByNiceUrlAndTemplate.cs | 3 +- src/Umbraco.Web/Routing/ResolveByProfile.cs | 3 +- src/Umbraco.Web/Routing/RouteLookups.cs | 111 ------------ src/Umbraco.Web/Routing/RoutesCache.cs | 61 ------- .../Routing/RoutesCacheResolver.cs | 18 ++ src/Umbraco.Web/Routing/RoutingContext.cs | 19 +-- src/Umbraco.Web/Umbraco.Web.csproj | 11 +- src/Umbraco.Web/UmbracoApplication.cs | 7 +- src/Umbraco.Web/UmbracoContext.cs | 2 +- src/Umbraco.Web/UmbracoModule.cs | 7 +- .../umbraco.presentation/library.cs | 12 +- 28 files changed, 591 insertions(+), 245 deletions(-) create mode 100644 src/Umbraco.Core/Resolving/ManyWeightedResolved.cs create mode 100644 src/Umbraco.Core/Resolving/ManyWeightedResolverBase.cs create mode 100644 src/Umbraco.Core/Resolving/Resolution.cs create mode 100644 src/Umbraco.Core/Resolving/ResolutionWeightAttribute.cs create mode 100644 src/Umbraco.Core/Resolving/ResolverBase.cs create mode 100644 src/Umbraco.Core/Resolving/SingleResolved.cs create mode 100644 src/Umbraco.Core/Resolving/SingleResolverBase.cs create mode 100644 src/Umbraco.Core/TypeExtensions.cs rename src/Umbraco.Web/{NiceUrlResolver.cs => Routing/NiceUrlProvider.cs} (73%) delete mode 100644 src/Umbraco.Web/Routing/RequestDocumentResolverWeightAttribute.cs create mode 100644 src/Umbraco.Web/Routing/RequestDocumentResolversResolver.cs delete mode 100644 src/Umbraco.Web/Routing/RouteLookups.cs delete mode 100644 src/Umbraco.Web/Routing/RoutesCache.cs create mode 100644 src/Umbraco.Web/Routing/RoutesCacheResolver.cs 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 +