From 5da0445c3234d8f9c5acd33bfd934ff82db27951 Mon Sep 17 00:00:00 2001 From: "shannon@ShandemVaio" Date: Tue, 31 Jul 2012 01:56:03 +0600 Subject: [PATCH] Updated TreeDefinitionCollection to use PluginTypeResolver and fixed its code to be thread safe. Updated restExtensions to use PluginTypeResolver and added unit test for resolving these types. Updated TypeFinder2 with a slight perf increase. --- src/Umbraco.Core/PluginTypeResolver.cs | 11 ++ src/Umbraco.Core/TypeFinder2.cs | 47 ++++--- src/Umbraco.Tests/PluginTypeResolverTests.cs | 28 +++- .../PluginTypeResolverExtensions.cs | 30 +++-- .../umbraco/Trees/TreeDefinitionCollection.cs | 122 ++++++++---------- .../umbracobase/restExtension.cs | 11 +- .../ApplicationTreeRegistrar.cs | 2 +- .../PluginTypeResolverExtensions.cs | 6 +- 8 files changed, 156 insertions(+), 101 deletions(-) diff --git a/src/Umbraco.Core/PluginTypeResolver.cs b/src/Umbraco.Core/PluginTypeResolver.cs index f2e5994f57..9255eac146 100644 --- a/src/Umbraco.Core/PluginTypeResolver.cs +++ b/src/Umbraco.Core/PluginTypeResolver.cs @@ -177,6 +177,17 @@ namespace Umbraco.Core return ResolveTypes(() => TypeFinder.FindClassesOfTypeWithAttribute(AssembliesToScan)); } + /// + /// Generic method to find any type that has the specified attribute + /// + /// + /// + internal IEnumerable ResolveAttributedTypes() + where TAttribute : Attribute + { + return ResolveTypes(() => TypeFinder.FindClassesWithAttribute(AssembliesToScan)); + } + /// /// Used for unit tests /// diff --git a/src/Umbraco.Core/TypeFinder2.cs b/src/Umbraco.Core/TypeFinder2.cs index 82360666a8..c38349690f 100644 --- a/src/Umbraco.Core/TypeFinder2.cs +++ b/src/Umbraco.Core/TypeFinder2.cs @@ -269,13 +269,19 @@ namespace Umbraco.Core { if (assemblies == null) throw new ArgumentNullException("assemblies"); - return (from a in assemblies - from t in GetTypesWithFormattedException(a) - where !t.IsInterface - && typeof(T).IsAssignableFrom(t) - && t.GetCustomAttributes(false).Any() - && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract)) - select t).ToList(); + var l = new List(); + foreach(var a in assemblies) + { + var types = from t in GetTypesWithFormattedException(a) + where !t.IsInterface + && typeof (T).IsAssignableFrom(t) + && t.GetCustomAttributes(false).Any() + && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract)) + select t; + l.AddRange(types); + } + + return l; } /// @@ -325,10 +331,16 @@ namespace Umbraco.Core { if (assemblies == null) throw new ArgumentNullException("assemblies"); - return (from a in assemblies - from t in GetTypesWithFormattedException(a) - where !t.IsInterface && t.GetCustomAttributes(false).Any() && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract)) - select t).ToList(); + var l = new List(); + foreach (var a in assemblies) + { + var types = from t in GetTypesWithFormattedException(a) + where !t.IsInterface && t.GetCustomAttributes(false).Any() && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract)) + select t; + l.AddRange(types); + } + + return l; } /// @@ -430,10 +442,15 @@ namespace Umbraco.Core private static IEnumerable GetTypes(Type assignTypeFrom, IEnumerable assemblies, bool onlyConcreteClasses) { - return (from a in assemblies - from t in GetTypesWithFormattedException(a) - where !t.IsInterface && assignTypeFrom.IsAssignableFrom(t) && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract)) - select t).ToList(); + var l = new List(); + foreach (var a in assemblies) + { + var types = from t in GetTypesWithFormattedException(a) + where !t.IsInterface && assignTypeFrom.IsAssignableFrom(t) && (!onlyConcreteClasses || (t.IsClass && !t.IsAbstract)) + select t; + l.AddRange(types); + } + return l; } private static IEnumerable GetTypesWithFormattedException(Assembly a) diff --git a/src/Umbraco.Tests/PluginTypeResolverTests.cs b/src/Umbraco.Tests/PluginTypeResolverTests.cs index e0fc8f60df..c071b956c9 100644 --- a/src/Umbraco.Tests/PluginTypeResolverTests.cs +++ b/src/Umbraco.Tests/PluginTypeResolverTests.cs @@ -9,6 +9,7 @@ using umbraco.MacroEngines.Iron; using umbraco.businesslogic; using umbraco.cms.businesslogic; using umbraco.editorControls; +using umbraco.presentation.umbracobase; using umbraco.uicontrols; using umbraco.cms; @@ -42,8 +43,7 @@ namespace Umbraco.Tests typeof(DLRScriptingEngine).Assembly, typeof(ICultureDictionary).Assembly, typeof(UmbracoContext).Assembly, - typeof(BaseDataType).Assembly, - typeof(DynamicNode).Assembly + typeof(BaseDataType).Assembly }; } @@ -62,6 +62,13 @@ namespace Umbraco.Tests Assert.AreEqual(2, foundTypes1.Count()); } + [Test] + public void Resolves_Attributed_Trees() + { + var trees = PluginTypeResolver.Current.ResolveAttributedTrees(); + Assert.AreEqual(26, trees.Count()); + } + [Test] public void Resolves_Trees() { @@ -87,14 +94,27 @@ namespace Umbraco.Tests public void Resolves_DataTypes() { var types = PluginTypeResolver.Current.ResolveDataTypes(); - Assert.AreEqual(33, types.Count()); + Assert.AreEqual(36, types.Count()); } [Test] public void Resolves_RazorDataTypeModels() { var types = PluginTypeResolver.Current.ResolveRazorDataTypeModels(); - Assert.AreEqual(3, types.Count()); + Assert.AreEqual(1, types.Count()); + } + + [Test] + public void Resolves_RestExtensions() + { + var types = PluginTypeResolver.Current.ResolveRestExtensions(); + Assert.AreEqual(1, types.Count()); + } + + [RestExtension("Blah")] + public class MyTestExtension + { + } public interface IFindMe diff --git a/src/Umbraco.Web/PluginTypeResolverExtensions.cs b/src/Umbraco.Web/PluginTypeResolverExtensions.cs index 3c02fdfeb5..0a3b4b4a09 100644 --- a/src/Umbraco.Web/PluginTypeResolverExtensions.cs +++ b/src/Umbraco.Web/PluginTypeResolverExtensions.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Threading; using Umbraco.Core; using Umbraco.Web.Routing; +using umbraco.interfaces; +using umbraco.presentation.umbracobase; namespace Umbraco.Web @@ -12,16 +14,24 @@ namespace Umbraco.Web /// public static class PluginTypeResolverExtensions { + /// + /// Returns all available ITrees in application + /// + /// + /// + internal static IEnumerable ResolveTrees(this PluginTypeResolver resolver) + { + return resolver.ResolveTypes(); + } - ///// - ///// Returns all IDocumentLookup types - ///// - ///// - ///// - //internal static IEnumerable ResolveLookups(this PluginTypeResolver resolver) - //{ - // return resolver.ResolveTypes(); - //} - + /// + /// Returns all classes attributed with RestExtension attribute + /// + /// + /// + internal static IEnumerable ResolveRestExtensions(this PluginTypeResolver resolver) + { + return resolver.ResolveAttributedTypes(); + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs index b771284ea3..fbe7ab5865 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/TreeDefinitionCollection.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Configuration; +using System.Threading; using System.Web; using System.Web.Security; using System.Web.UI; @@ -8,6 +9,8 @@ using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using System.Collections.Generic; +using Umbraco.Core; +using Umbraco.Web; using umbraco.interfaces; using umbraco.BusinessLogic.Utils; using umbraco.BusinessLogic; @@ -23,6 +26,9 @@ namespace umbraco.cms.presentation.Trees //create singleton private static readonly TreeDefinitionCollection instance = new TreeDefinitionCollection(); + + private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); + private TreeDefinitionCollection() { RegisterTrees(); @@ -42,12 +48,9 @@ namespace umbraco.cms.presentation.Trees /// public TreeDefinition FindTree(ITree tree) { - TreeDefinition foundTree = this.Find( - delegate(TreeDefinition t) - { - return t.TreeType.Equals(tree.GetType()); - } - ); + var foundTree = this.Find( + t => t.TreeType == tree.GetType() + ); if (foundTree != null) return foundTree; @@ -61,7 +64,7 @@ namespace umbraco.cms.presentation.Trees /// public TreeDefinition FindTree() where T : ITree { - TreeDefinition foundTree = this.Find( + var foundTree = this.Find( delegate(TreeDefinition t) { // zb-00002 #29929 : use IsAssignableFrom instead of Equal, otherwise you can't override build-in @@ -79,16 +82,12 @@ namespace umbraco.cms.presentation.Trees /// Return the TreeDefinition object based on the tree alias and application it belongs to /// /// - /// /// public TreeDefinition FindTree(string alias) { - TreeDefinition foundTree = this.Find( - delegate(TreeDefinition t) - { - return t.Tree.Alias.ToLower() == alias.ToLower(); - } - ); + var foundTree = this.Find( + t => t.Tree.Alias.ToLower() == alias.ToLower() + ); if (foundTree != null) return foundTree; @@ -103,11 +102,8 @@ namespace umbraco.cms.presentation.Trees public List FindTrees(string appAlias) { return this.FindAll( - delegate(TreeDefinition tree) - { - return (tree.App != null && tree.App.alias.ToLower() == appAlias.ToLower()); - } - ); + tree => (tree.App != null && tree.App.alias.ToLower() == appAlias.ToLower()) + ); } /// @@ -118,17 +114,13 @@ namespace umbraco.cms.presentation.Trees public List FindActiveTrees(string appAlias) { return this.FindAll( - delegate(TreeDefinition tree) - { - return (tree.App != null && tree.App.alias.ToLower() == appAlias.ToLower() && tree.Tree.Initialize); - } - ); + tree => (tree.App != null && tree.App.alias.ToLower() == appAlias.ToLower() && tree.Tree.Initialize) + ); } public void ReRegisterTrees() { - this.Clear(); - RegisterTrees(); + RegisterTrees(true); } /// @@ -137,57 +129,55 @@ namespace umbraco.cms.presentation.Trees /// This will also store an instance of each tree object in the TreeDefinition class which should be /// used when referencing all tree classes. /// - private void RegisterTrees() + private void RegisterTrees(bool clearFirst = false) { + using (var l = new UpgradeableReadLock(Lock)) + { + if (clearFirst) + { + this.Clear(); + } - if (this.Count > 0) - return; + //if we already have tree, exit + if (this.Count > 0) + return; - var typeFinder = new Umbraco.Core.TypeFinder2(); - var foundITrees = typeFinder.FindClassesOfType(); + l.UpgradeToWriteLock(); - ApplicationTree[] objTrees = ApplicationTree.getAll(); - var appTrees = new List(); - appTrees.AddRange(objTrees); - List apps = Application.getAll(); + var foundITrees = PluginTypeResolver.Current.ResolveTrees(); - foreach (Type type in foundITrees) - { + var objTrees = ApplicationTree.getAll(); + var appTrees = new List(); + appTrees.AddRange(objTrees); - //find the Application tree's who's combination of assembly name and tree type is equal to - //the Type that was found's full name. - //Since a tree can exist in multiple applications we'll need to register them all. - List appTreesForType = appTrees.FindAll( - delegate(ApplicationTree tree) - { - return (string.Format("{0}.{1}", tree.AssemblyName, tree.Type) == type.FullName); - } - ); - - if (appTreesForType != null) - { - foreach (ApplicationTree appTree in appTreesForType) - { - //find the Application object whos name is the same as our appTree ApplicationAlias - Application app = apps.Find( - delegate(Application a) - { - return (a.alias == appTree.ApplicationAlias); - } + var apps = Application.getAll(); + + foreach (var type in foundITrees) + { + + //find the Application tree's who's combination of assembly name and tree type is equal to + //the Type that was found's full name. + //Since a tree can exist in multiple applications we'll need to register them all. + var appTreesForType = appTrees.FindAll( + tree => (string.Format("{0}.{1}", tree.AssemblyName, tree.Type) == type.FullName) ); - TreeDefinition def = new TreeDefinition(type, appTree, app); + foreach (var appTree in appTreesForType) + { + //find the Application object whos name is the same as our appTree ApplicationAlias + var app = apps.Find( + a => (a.alias == appTree.ApplicationAlias) + ); + + var def = new TreeDefinition(type, appTree, app); this.Add(def); } - - } - } - //sort our trees with the sort order definition - this.Sort(delegate(TreeDefinition t1, TreeDefinition t2) - { - return t1.Tree.SortOrder.CompareTo(t2.Tree.SortOrder); - }); + } + //sort our trees with the sort order definition + this.Sort((t1, t2) => t1.Tree.SortOrder.CompareTo(t2.Tree.SortOrder)); + + } } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbracobase/restExtension.cs b/src/Umbraco.Web/umbraco.presentation/umbracobase/restExtension.cs index e687cdbe7c..45a8927c25 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbracobase/restExtension.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbracobase/restExtension.cs @@ -2,6 +2,8 @@ using System; using System.Linq; using System.Reflection; using System.Xml; +using Umbraco.Core; +using Umbraco.Web; using umbraco.BusinessLogic.Utils; using umbraco.cms.businesslogic.member; using umbraco.IO; @@ -95,8 +97,9 @@ namespace umbraco.presentation.umbracobase { //check for RestExtensionAttribute - var typeFinder = new Umbraco.Core.TypeFinder2(); - foreach (var t in typeFinder.FindClassesWithAttribute()) + var restExtensions = PluginTypeResolver.Current.ResolveRestExtensions(); + + foreach (var t in restExtensions) { var temp = t.GetCustomAttributes(typeof(RestExtension), false).OfType(); @@ -109,7 +112,9 @@ namespace umbraco.presentation.umbracobase if (mi != null) { //check allowed - var attributes = mi.GetCustomAttributes(typeof(RestExtensionMethod), false).OfType(); + var attributes = mi.GetCustomAttributes(typeof (RestExtensionMethod), false) + .OfType() + .ToArray(); //check to make sure the method was decorated properly if (attributes.Any()) diff --git a/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs b/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs index 5ba139a3ff..635a0af87d 100644 --- a/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs +++ b/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs @@ -31,7 +31,7 @@ namespace umbraco.BusinessLogic public ApplicationTreeRegistrar() { // Load all Trees by attribute and add them to the XML config - var types = PluginTypeResolver.Current.ResolveTrees(); + var types = PluginTypeResolver.Current.ResolveAttributedTrees(); var items = types .Select(x => diff --git a/src/umbraco.businesslogic/PluginTypeResolverExtensions.cs b/src/umbraco.businesslogic/PluginTypeResolverExtensions.cs index 724ad770ba..2398ac7b78 100644 --- a/src/umbraco.businesslogic/PluginTypeResolverExtensions.cs +++ b/src/umbraco.businesslogic/PluginTypeResolverExtensions.cs @@ -31,14 +31,16 @@ namespace umbraco.businesslogic } /// - /// Returns all available ITrees in application + /// Returns all available ITrees in application that are attribute with TreeAttribute /// /// /// - internal static IEnumerable ResolveTrees(this PluginTypeResolver resolver) + internal static IEnumerable ResolveAttributedTrees(this PluginTypeResolver resolver) { return resolver.ResolveTypesWithAttribute(); } + + } } \ No newline at end of file