diff --git a/src/Umbraco.Core/PluginTypeResolver.cs b/src/Umbraco.Core/PluginTypeResolver.cs index 426029de61..8440aadb02 100644 --- a/src/Umbraco.Core/PluginTypeResolver.cs +++ b/src/Umbraco.Core/PluginTypeResolver.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using System.Threading; @@ -9,7 +10,7 @@ namespace Umbraco.Core { /// - /// Used to resolve all plugin types + /// Used to resolve all plugin types and cache them /// /// /// @@ -49,17 +50,41 @@ namespace Umbraco.Core internal readonly TypeFinder2 TypeFinder = new TypeFinder2(); private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); private readonly HashSet _types = new HashSet(); + private IEnumerable _assemblies; + + /// + /// Gets/sets which assemblies to scan when type finding, generally used for unit testing, if not explicitly set + /// this will search all assemblies known to have plugins and exclude ones known to not have them. + /// + internal IEnumerable AssembliesToScan + { + get { return _assemblies ?? (_assemblies = TypeFinder2.GetAssembliesWithKnownExclusions()); } + set { _assemblies = value; } + } + + /// + /// Used to resolve and create instances of the specified type based on the resolved/cached plugin types + /// + /// + /// set to true if an exception is to be thrown if there is an error during instantiation + /// + internal IEnumerable FindAndCreateInstances(bool throwException = false) + { + var types = ResolveTypes(); + return CreateInstances(types, throwException); + } /// /// Used to create instances of the specified type based on the resolved/cached plugin types /// /// + /// + /// set to true if an exception is to be thrown if there is an error during instantiation /// - internal IEnumerable CreateInstances() + internal IEnumerable CreateInstances(IEnumerable types, bool throwException = false) { - var types = ResolveTypes(); var instances = new List(); - foreach(var t in types) + foreach (var t in types) { try { @@ -70,17 +95,29 @@ namespace Umbraco.Core { //TODO: Need to fix logging so this doesn't bork if no SQL connection //Log.Add(LogTypes.Error, -1, "Error loading ILookup: " + ex.ToString()); + if (throwException) + { + throw ex; + } } } return instances; - } + } /// - /// Generic method to find the specified type and cache the result + /// Used to create an instance of the specified type based on the resolved/cached plugin types /// /// + /// + /// /// - internal IEnumerable ResolveTypes() + internal T CreateInstance(Type type, bool throwException = false) + { + var instances = CreateInstances(new[] {type}, throwException); + return instances.FirstOrDefault(); + } + + private IEnumerable ResolveTypes(Func> finder) { using (var readLock = new UpgradeableReadLock(_lock)) { @@ -93,7 +130,7 @@ namespace Umbraco.Core typeList = new TypeList(); - foreach (var t in TypeFinder.FindClassesOfType()) + foreach (var t in finder()) { typeList.AddType(t); } @@ -103,8 +140,28 @@ namespace Umbraco.Core } return typeList.GetTypes(); } + } + /// + /// Generic method to find the specified type and cache the result + /// + /// + /// + internal IEnumerable ResolveTypes() + { + return ResolveTypes(() => TypeFinder.FindClassesOfType(AssembliesToScan)); + } + /// + /// Generic method to find the specified type that has an attribute and cache the result + /// + /// + /// + /// + internal IEnumerable ResolveTypesWithAttribute() + where TAttribute : Attribute + { + return ResolveTypes(() => TypeFinder.FindClassesOfTypeWithAttribute(AssembliesToScan)); } /// @@ -116,6 +173,8 @@ namespace Umbraco.Core return _types; } + + #region Private classes internal abstract class TypeList { diff --git a/src/Umbraco.Core/Properties/AssemblyInfo.cs b/src/Umbraco.Core/Properties/AssemblyInfo.cs index 49c9f88d05..229c77c8d8 100644 --- a/src/Umbraco.Core/Properties/AssemblyInfo.cs +++ b/src/Umbraco.Core/Properties/AssemblyInfo.cs @@ -21,4 +21,6 @@ using System.Runtime.InteropServices; [assembly: InternalsVisibleTo("umbraco")] [assembly: InternalsVisibleTo("Umbraco.Tests")] [assembly: InternalsVisibleTo("businesslogic")] +[assembly: InternalsVisibleTo("cms")] +[assembly: InternalsVisibleTo("umbraco.editorControls")] diff --git a/src/Umbraco.Core/Resolving/MultipleResolverBase.cs b/src/Umbraco.Core/Resolving/MultipleResolverBase.cs index 77c892f93c..01e4c861f8 100644 --- a/src/Umbraco.Core/Resolving/MultipleResolverBase.cs +++ b/src/Umbraco.Core/Resolving/MultipleResolverBase.cs @@ -3,6 +3,9 @@ using System.Threading; namespace Umbraco.Core.Resolving { + //NOTE: This class should also support creating instances of the object and managing their lifespan, + // for example, some resolvers would want to return new object each time, per request or per application lifetime. + /// /// A Resolver which manages an ordered list of objects. /// diff --git a/src/Umbraco.Core/TypeFinder2.cs b/src/Umbraco.Core/TypeFinder2.cs index 8f9f67b4bc..d5641be4a5 100644 --- a/src/Umbraco.Core/TypeFinder2.cs +++ b/src/Umbraco.Core/TypeFinder2.cs @@ -16,6 +16,9 @@ using System.Web.Hosting; namespace Umbraco.Core { + + //TODO: Get the App_Code stuff in here from the old one + /// /// A utility class to find all classes of a certain type by reflection in the current bin folder /// of the web application. @@ -252,6 +255,32 @@ namespace Umbraco.Core return FindClassesOfType(new[] { assembly }); } + public IEnumerable FindClassesOfTypeWithAttribute() + where TAttribute : Attribute + { + return FindClassesOfTypeWithAttribute(GetAssembliesWithKnownExclusions(), true); + } + + public IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies) + where TAttribute : Attribute + { + return FindClassesOfTypeWithAttribute(assemblies, true); + } + + public IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses) + where TAttribute : Attribute + { + 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(); + } + /// /// Searches all filtered local assemblies specified for classes of the type passed in. /// @@ -262,32 +291,6 @@ namespace Umbraco.Core return FindClassesOfType(GetAssembliesWithKnownExclusions(), true); } - /// - /// Searches all assemblies specified for classes of the type passed in. - /// - /// - /// - /// - public IEnumerable FindClassesOfType(IEnumerable assemblyFiles) - { - return FindClassesOfType(assemblyFiles, true); - } - - /// - /// Searches all assemblies specified for classes of the type passed in. - /// - /// - /// - /// Only resolve concrete classes that can be instantiated - /// - public IEnumerable FindClassesOfType(IEnumerable assemblyFiles, bool onlyConcreteClasses) - { - if (assemblyFiles == null) throw new ArgumentNullException("assemblyFiles"); - - var typeAndAssembly = GetAssignablesFromType(assemblyFiles, onlyConcreteClasses); - return GetTypesFromResult(typeAndAssembly); - } - /// /// Returns all types found of in the assemblies specified of type T /// @@ -354,40 +357,6 @@ namespace Umbraco.Core return FindClassesWithAttribute(GetAssembliesWithKnownExclusions()); } - #region Internal Methods - For testing - /// - /// Used to find all types in all assemblies in the specified folder - /// - /// - /// - /// - /// - /// - /// This has potential cost alot in performance so it is marked internal and should ONLY be used - /// where absolutely necessary (i.e. Tests) - /// - internal IEnumerable FindClassesOfType(DirectoryInfo folder, bool onlyConcreteClasses) - { - var types = new List(); - types.AddRange(FindClassesOfType(folder.GetFiles("*.dll").Select(x => x.FullName))); - return types; - } - - /// - /// Used to find all types in all assemblies in the specified folder - /// - /// - /// - /// - /// - /// This has potential cost alot in performance so it is marked internal and should ONLY be used - /// where absolutely necessary (i.e. Tests) - /// - internal IEnumerable FindClassesOfType(DirectoryInfo folder) - { - return FindClassesOfType(folder, true); - } - #endregion #region Internal Attributed Assembly class diff --git a/src/Umbraco.Tests/DataTypeFactoryTests.cs b/src/Umbraco.Tests/DataTypeFactoryTests.cs new file mode 100644 index 0000000000..d8f4a22546 --- /dev/null +++ b/src/Umbraco.Tests/DataTypeFactoryTests.cs @@ -0,0 +1,106 @@ +using System; +using NUnit.Framework; +using SqlCE4Umbraco; +using Umbraco.Core; +using Umbraco.Web; +using umbraco.DataLayer; +using umbraco.MacroEngines; +using umbraco.MacroEngines.Iron; +using umbraco.businesslogic; +using umbraco.cms.businesslogic; +using umbraco.cms.businesslogic.datatype; +using umbraco.interfaces; +using umbraco.uicontrols; +using System.Linq; +using BaseDataType = umbraco.editorControls.BaseDataType; + +namespace Umbraco.Tests +{ + [TestFixture] + public class DataTypeFactoryTests + { + [SetUp] + public void Initialize() + { + //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver + PluginTypeResolver.Current.AssembliesToScan = new[] + { + this.GetType().Assembly + }; + } + + [Test] + public void Find_All_DataTypes() + { + umbraco.cms.businesslogic.datatype.controls.Factory.Initialize(); + Assert.AreEqual(2, umbraco.cms.businesslogic.datatype.controls.Factory._controls.Count); + } + + [Test] + public void Get_All_Instances() + { + umbraco.cms.businesslogic.datatype.controls.Factory.Initialize(); + var factory = new umbraco.cms.businesslogic.datatype.controls.Factory(); + Assert.AreEqual(2, factory.GetAll().Count()); + } + + #region Classes for tests + public class DataType1 : AbstractDataEditor + { + public override Guid Id + { + get { return new Guid("FBAEA49B-F704-44FE-B725-6C8FE0767CF2"); } + } + + public override string DataTypeName + { + get { return "DataType1"; } + } + + public override IDataEditor DataEditor + { + get { throw new NotImplementedException(); } + } + + public override IDataPrevalue PrevalueEditor + { + get { throw new NotImplementedException(); } + } + + public override IData Data + { + get { throw new NotImplementedException(); } + } + } + + public class DataType2 : AbstractDataEditor + { + public override Guid Id + { + get { return new Guid("3F58099B-96AC-415E-B3F9-BA273F51E681"); } + } + + public override string DataTypeName + { + get { return "DataType2"; } + } + + public override IDataEditor DataEditor + { + get { throw new NotImplementedException(); } + } + + public override IDataPrevalue PrevalueEditor + { + get { throw new NotImplementedException(); } + } + + public override IData Data + { + get { throw new NotImplementedException(); } + } + } + #endregion + + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/EnumerableExtensionsTests.cs b/src/Umbraco.Tests/EnumerableExtensionsTests.cs index 9bacfeb39a..c13cee8ea9 100644 --- a/src/Umbraco.Tests/EnumerableExtensionsTests.cs +++ b/src/Umbraco.Tests/EnumerableExtensionsTests.cs @@ -8,7 +8,6 @@ using Umbraco.Core.Resolving; namespace Umbraco.Tests { - [TestFixture] public class EnumerableExtensionsTests { diff --git a/src/Umbraco.Tests/MacroControlFactoryTests.cs b/src/Umbraco.Tests/MacroControlFactoryTests.cs new file mode 100644 index 0000000000..c70e24a599 --- /dev/null +++ b/src/Umbraco.Tests/MacroControlFactoryTests.cs @@ -0,0 +1,61 @@ +using System; +using System.Linq; +using System.Web.UI; +using NUnit.Framework; +using Umbraco.Core; +using umbraco.editorControls.macrocontainer; +using umbraco.interfaces; + +namespace Umbraco.Tests +{ + [TestFixture] + public class MacroControlFactoryTests + { + [SetUp] + public void Initialize() + { + //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver + PluginTypeResolver.Current.AssembliesToScan = new[] + { + this.GetType().Assembly + }; + } + + [Test] + public void Find_Types() + { + var found = MacroControlFactory.MacroControlTypes; + Assert.AreEqual(2, found.Count()); + } + + #region Classes for tests + public class ControlMacroRendering : Control, IMacroGuiRendering + { + public string Value + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public bool ShowCaption + { + get { throw new NotImplementedException(); } + } + } + + public class NonControlMacroRendering : IMacroGuiRendering + { + public string Value + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public bool ShowCaption + { + get { throw new NotImplementedException(); } + } + } + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/MacroEngineFactoryTests.cs b/src/Umbraco.Tests/MacroEngineFactoryTests.cs new file mode 100644 index 0000000000..5c761d5291 --- /dev/null +++ b/src/Umbraco.Tests/MacroEngineFactoryTests.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Umbraco.Core; +using umbraco.cms.businesslogic.macro; +using umbraco.interfaces; + +namespace Umbraco.Tests +{ + [TestFixture] + public class MacroEngineFactoryTests + { + [SetUp] + public void Initialize() + { + //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver + PluginTypeResolver.Current.AssembliesToScan = new[] + { + this.GetType().Assembly + }; + } + + [Test] + public void Get_All() + { + var engines = MacroEngineFactory.GetAll(); + Assert.AreEqual(2, engines.Count()); + } + + [Test] + public void Get_Engine() + { + var engine1 = MacroEngineFactory.GetEngine("MacroEngine1"); + Assert.IsNotNull(engine1); + } + + [Test] + public void Get_By_Filename() + { + var engine1 = MacroEngineFactory.GetByFilename("test.me1"); + var engine2 = MacroEngineFactory.GetByFilename("test.me2"); + Assert.IsNotNull(engine1); + Assert.IsNotNull(engine2); + Assert.Throws(() => MacroEngineFactory.GetByFilename("test.blah")); + + } + + [Test] + public void Get_By_Extension() + { + var engine1 = MacroEngineFactory.GetByExtension("me1"); + var engine2 = MacroEngineFactory.GetByExtension("me2"); + Assert.IsNotNull(engine1); + Assert.IsNotNull(engine2); + Assert.Throws(() => MacroEngineFactory.GetByExtension("blah")); + } + + #region Classes for tests + public class MacroEngine1 : IMacroEngine + { + public string Name + { + get { return "MacroEngine1"; } + } + + public IEnumerable SupportedExtensions + { + get { return new[] {"me1"}; } + } + + public IEnumerable SupportedUIExtensions + { + get { throw new NotImplementedException(); } + } + + public Dictionary SupportedProperties + { + get { throw new NotImplementedException(); } + } + + public bool Validate(string code, string tempFileName, INode currentPage, out string errorMessage) + { + throw new NotImplementedException(); + } + + public string Execute(MacroModel macro, INode currentPage) + { + throw new NotImplementedException(); + } + } + + public class MacroEngine2 : IMacroEngine + { + public string Name + { + get { return "MacroEngine2"; } + } + + public IEnumerable SupportedExtensions + { + get { return new[] { "me2" }; } + } + + public IEnumerable SupportedUIExtensions + { + get { throw new NotImplementedException(); } + } + + public Dictionary SupportedProperties + { + get { throw new NotImplementedException(); } + } + + public bool Validate(string code, string tempFileName, INode currentPage, out string errorMessage) + { + throw new NotImplementedException(); + } + + public string Execute(MacroModel macro, INode currentPage) + { + throw new NotImplementedException(); + } + } + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/MediaFactoryTests.cs b/src/Umbraco.Tests/MediaFactoryTests.cs new file mode 100644 index 0000000000..b989ac8a28 --- /dev/null +++ b/src/Umbraco.Tests/MediaFactoryTests.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Umbraco.Core; +using umbraco.BusinessLogic; +using umbraco.cms.businesslogic.media; + +namespace Umbraco.Tests +{ + [TestFixture] + public class MediaFactoryTests + { + [SetUp] + public void Initialize() + { + //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver + PluginTypeResolver.Current.AssembliesToScan = new[] + { + this.GetType().Assembly + }; + } + + /// + /// Ensures that the media factory finds the correct number of IMediaFactory + /// + [Test] + public void Find_Media_Factories() + { + var factories = MediaFactory.Factories; + Assert.AreEqual(2, factories.Count()); + } + + #region Classes for tests + public class MediaFactory1 : IMediaFactory + { + public List Extensions + { + get { throw new NotImplementedException(); } + } + + public int Priority + { + get { return 1; } + } + + public bool CanHandleMedia(int parentNodeId, PostedMediaFile postedFile, User user) + { + throw new NotImplementedException(); + } + + public Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user) + { + throw new NotImplementedException(); + } + + public Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user, bool replaceExisting) + { + throw new NotImplementedException(); + } + } + + public class MediaFactory2 : IMediaFactory + { + public List Extensions + { + get { throw new NotImplementedException(); } + } + + public int Priority + { + get { return 2; } + } + + public bool CanHandleMedia(int parentNodeId, PostedMediaFile postedFile, User user) + { + throw new NotImplementedException(); + } + + public Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user) + { + throw new NotImplementedException(); + } + + public Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user, bool replaceExisting) + { + throw new NotImplementedException(); + } + } + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/PackageActionFactoryTests.cs b/src/Umbraco.Tests/PackageActionFactoryTests.cs new file mode 100644 index 0000000000..a05e9764bb --- /dev/null +++ b/src/Umbraco.Tests/PackageActionFactoryTests.cs @@ -0,0 +1,82 @@ +using System; +using System.Linq; +using System.Xml; +using NUnit.Framework; +using Umbraco.Core; +using umbraco.cms.businesslogic.packager; +using umbraco.interfaces; + +namespace Umbraco.Tests +{ + [TestFixture] + public class PackageActionFactoryTests + { + [SetUp] + public void Initialize() + { + //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver + PluginTypeResolver.Current.AssembliesToScan = new[] + { + this.GetType().Assembly + }; + } + + /// + /// Ensures all IPackageActions are found + /// + [Test] + public void Find_Package_Actions() + { + var actions = PackageAction.PackageActions; + Assert.AreEqual(2, actions.Count()); + } + + #region Classes for tests + public class PackageAction1 : IPackageAction + { + public bool Execute(string packageName, XmlNode xmlData) + { + throw new NotImplementedException(); + } + + public string Alias() + { + return "pa1"; + } + + public bool Undo(string packageName, XmlNode xmlData) + { + throw new NotImplementedException(); + } + + public XmlNode SampleXml() + { + throw new NotImplementedException(); + } + } + + public class PackageAction2 : IPackageAction + { + public bool Execute(string packageName, XmlNode xmlData) + { + throw new NotImplementedException(); + } + + public string Alias() + { + return "pa2"; + } + + public bool Undo(string packageName, XmlNode xmlData) + { + throw new NotImplementedException(); + } + + public XmlNode SampleXml() + { + throw new NotImplementedException(); + } + } + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/PluginTypeResolverTests.cs b/src/Umbraco.Tests/PluginTypeResolverTests.cs index b9538191b7..058c71cb31 100644 --- a/src/Umbraco.Tests/PluginTypeResolverTests.cs +++ b/src/Umbraco.Tests/PluginTypeResolverTests.cs @@ -1,12 +1,51 @@ using System.Linq; using NUnit.Framework; +using SqlCE4Umbraco; using Umbraco.Core; +using Umbraco.Web; +using umbraco.DataLayer; +using umbraco.MacroEngines; +using umbraco.MacroEngines.Iron; +using umbraco.businesslogic; +using umbraco.cms.businesslogic; +using umbraco.editorControls; +using umbraco.uicontrols; +using umbraco.cms; namespace Umbraco.Tests { + + [TestFixture] public class PluginTypeResolverTests { + [SetUp] + public void Initialize() + { + //for testing, we'll specify which assemblies are scanned for the PluginTypeResolver + PluginTypeResolver.Current.AssembliesToScan = new[] + { + this.GetType().Assembly, + typeof(ApplicationStartupHandler).Assembly, + typeof(SqlCEHelper).Assembly, + typeof(CMSNode).Assembly, + typeof(System.Guid).Assembly, + typeof(NUnit.Framework.Assert).Assembly, + typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly, + typeof(System.Xml.NameTable).Assembly, + typeof(System.Configuration.GenericEnumConverter).Assembly, + typeof(System.Web.SiteMap).Assembly, + typeof(TabPage).Assembly, + typeof(System.Web.Mvc.ActionResult).Assembly, + typeof(TypeFinder2).Assembly, + typeof(ISqlHelper).Assembly, + typeof(DLRScriptingEngine).Assembly, + typeof(ICultureDictionary).Assembly, + typeof(UmbracoContext).Assembly, + typeof(BaseDataType).Assembly + }; + } + [Test] public void Ensure_Only_One_Type_List_Created() { @@ -22,6 +61,34 @@ namespace Umbraco.Tests Assert.AreEqual(2, foundTypes1.Count()); } + [Test] + public void Resolves_Trees() + { + var trees = PluginTypeResolver.Current.ResolveTrees(); + Assert.AreEqual(26, trees.Count()); + } + + [Test] + public void Resolves_Applications() + { + var apps = PluginTypeResolver.Current.ResolveApplications(); + Assert.AreEqual(7, apps.Count()); + } + + [Test] + public void Resolves_Actions() + { + var types = PluginTypeResolver.Current.ResolveActions(); + Assert.AreEqual(1, types.Count()); + } + + [Test] + public void Resolves_DataTypes() + { + var types = PluginTypeResolver.Current.ResolveDataTypes(); + Assert.AreEqual(33, types.Count()); + } + public interface IFindMe { diff --git a/src/Umbraco.Tests/TypeFinderBenchmarkTests.cs b/src/Umbraco.Tests/TypeFinderTests.cs similarity index 85% rename from src/Umbraco.Tests/TypeFinderBenchmarkTests.cs rename to src/Umbraco.Tests/TypeFinderTests.cs index 7ad7277ca6..2c61502a78 100644 --- a/src/Umbraco.Tests/TypeFinderBenchmarkTests.cs +++ b/src/Umbraco.Tests/TypeFinderTests.cs @@ -16,16 +16,15 @@ using umbraco.businesslogic; using umbraco.cms.businesslogic; using umbraco.uicontrols; -[assembly: TypeFinderBenchmarkTests.AssemblyContainsPluginsAttribute] +[assembly: TypeFinderTests.AssemblyContainsPluginsAttribute] namespace Umbraco.Tests { /// /// Full Trust benchmark tests for typefinder and the old typefinder /// - [TestFixture] - [Ignore("This is a benchark test")] - public class TypeFinderBenchmarkTests + [TestFixture] + public class TypeFinderTests { /// /// List of assemblies to scan @@ -37,9 +36,7 @@ namespace Umbraco.Tests { _assemblies = new[] { - //both contain the type this.GetType().Assembly, - //these dont contain the type typeof(ApplicationStartupHandler).Assembly, typeof(SqlCEHelper).Assembly, typeof(CMSNode).Assembly, @@ -73,18 +70,43 @@ namespace Umbraco.Tests { } + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class MyTestAttribute : Attribute + { + + } + public abstract class TestEditor { } + [MyTestAttribute] public class BenchmarkTestEditor : TestEditor { } + [MyTestAttribute] + public class MyOtherTestEditor : TestEditor + { + + } + + [Test] + public void Get_Type_With_Attribute() + { + + var finder2 = new Umbraco.Core.TypeFinder2(); + + var typesFound = finder2.FindClassesOfTypeWithAttribute(_assemblies); + + Assert.AreEqual(2, typesFound.Count()); + + } [Test] + [Ignore("This is a benchark test")] public void Benchmark_Old_TypeFinder_vs_New_TypeFinder_FindClassesWithAttribute() { var timer = new Stopwatch(); @@ -107,6 +129,7 @@ namespace Umbraco.Tests } [Test] + [Ignore("This is a benchark test")] public void Benchmark_Old_TypeFinder_vs_New_TypeFinder_FindClassesOfType() { var timer = new Stopwatch(); @@ -133,6 +156,7 @@ namespace Umbraco.Tests /// cache files created instead since this is clearly a TON faster. /// [Test] + [Ignore("This is a benchark test")] public void Benchmark_Finding_First_Type_In_Assemblies() { var timer = new Stopwatch(); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index ae089775fd..6e02fd0446 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -49,6 +49,11 @@ + + + + + @@ -62,7 +67,7 @@ - + @@ -92,6 +97,10 @@ {C7CB79F0-1C97-4B33-BFA7-00731B579AE2} umbraco.datalayer + + {255F5DF1-4E43-4758-AC05-7A0B68EB021B} + umbraco.editorControls + {511F6D8D-7717-440A-9A57-A507E9A8B27F} umbraco.interfaces diff --git a/src/Umbraco.Web/Routing/DocumentLookupsResolver.cs b/src/Umbraco.Web/Routing/DocumentLookupsResolver.cs index 168c65eed7..fd2a021112 100644 --- a/src/Umbraco.Web/Routing/DocumentLookupsResolver.cs +++ b/src/Umbraco.Web/Routing/DocumentLookupsResolver.cs @@ -22,7 +22,7 @@ namespace Umbraco.Web.Routing internal DocumentLookupsResolver(IEnumerable lookupTypes, IDocumentLastChanceLookup lastChanceLookup) { //TODO: I've changed this to resolve types but the intances are not created yet! - // I've created a method on the PluginTypeResolver to create types: PluginTypesResolver.Current.CreateInstances() + // I've created a method on the PluginTypeResolver to create types: PluginTypesResolver.Current.FindAndCreateInstances() _lookupTypes.AddRange(lookupsTypes); diff --git a/src/umbraco.businesslogic/ApplicationRegistrar.cs b/src/umbraco.businesslogic/ApplicationRegistrar.cs index d8ee358a93..29cd59ba37 100644 --- a/src/umbraco.businesslogic/ApplicationRegistrar.cs +++ b/src/umbraco.businesslogic/ApplicationRegistrar.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Xml.Linq; +using Umbraco.Core; using umbraco.BusinessLogic.Utils; using umbraco.DataLayer; using umbraco.businesslogic; @@ -29,11 +30,12 @@ namespace umbraco.BusinessLogic public ApplicationRegistrar() { // Load all Applications by attribute and add them to the XML config - var typeFinder = new Umbraco.Core.TypeFinder2(); - var types = typeFinder.FindClassesOfType() - .Where(x => x.GetCustomAttributes(typeof(ApplicationAttribute), false).Any()); + var types = PluginTypeResolver.Current.ResolveApplications(); - var attrs = types.Select(x => (ApplicationAttribute)x.GetCustomAttributes(typeof(ApplicationAttribute), false).Single()) + //since applications don't populate their metadata from the attribute and because it is an interface, + //we need to interrogate the attributes for the data. Would be better to have a base class that contains + //metadata populated by the attribute. Oh well i guess. + var attrs = types.Select(x => x.GetCustomAttributes(false).Single()) .Where(x => Application.getByAlias(x.Alias) == null); var allAliases = Application.getAll().Select(x => x.alias).Concat(attrs.Select(x => x.Alias)); diff --git a/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs b/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs index 2a9cd706d0..5ba139a3ff 100644 --- a/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs +++ b/src/umbraco.businesslogic/ApplicationTreeRegistrar.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Xml.Linq; +using Umbraco.Core; using umbraco.BusinessLogic.Utils; using umbraco.DataLayer; using umbraco.businesslogic; @@ -29,14 +30,13 @@ namespace umbraco.BusinessLogic public ApplicationTreeRegistrar() { - // Load all Applications by attribute and add them to the XML config - var typeFinder = new Umbraco.Core.TypeFinder2(); - var types = typeFinder.FindClassesOfType() - .Where(x => x.GetCustomAttributes(typeof(TreeAttribute), false).Any()); + // Load all Trees by attribute and add them to the XML config + var types = PluginTypeResolver.Current.ResolveTrees(); - var items = types.Select(x => new Tuple(x, - (TreeAttribute)x.GetCustomAttributes(typeof(TreeAttribute), false).Single())) - .Where(x => ApplicationTree.getByAlias(x.Item2.Alias) == null); + var items = types + .Select(x => + new Tuple(x, x.GetCustomAttributes(false).Single())) + .Where(x => ApplicationTree.getByAlias(x.Item2.Alias) == null); var allAliases = ApplicationTree.getAll().Select(x => x.Alias).Concat(items.Select(x => x.Item2.Alias)); var inString = "'" + string.Join("','", allAliases) + "'"; diff --git a/src/umbraco.businesslogic/PluginTypeResolverExtensions.cs b/src/umbraco.businesslogic/PluginTypeResolverExtensions.cs index 924403820c..724ad770ba 100644 --- a/src/umbraco.businesslogic/PluginTypeResolverExtensions.cs +++ b/src/umbraco.businesslogic/PluginTypeResolverExtensions.cs @@ -20,5 +20,25 @@ namespace umbraco.businesslogic return resolver.ResolveTypes(); } + /// + /// Returns all available IApplication in application + /// + /// + /// + internal static IEnumerable ResolveApplications(this PluginTypeResolver resolver) + { + return resolver.ResolveTypesWithAttribute(); + } + + /// + /// Returns all available ITrees in application + /// + /// + /// + internal static IEnumerable ResolveTrees(this PluginTypeResolver resolver) + { + return resolver.ResolveTypesWithAttribute(); + } + } } \ No newline at end of file diff --git a/src/umbraco.cms/Actions/Action.cs b/src/umbraco.cms/Actions/Action.cs index b7cae428d8..0622709b3b 100644 --- a/src/umbraco.cms/Actions/Action.cs +++ b/src/umbraco.cms/Actions/Action.cs @@ -6,6 +6,7 @@ using System.Reflection; using Umbraco.Core; using umbraco.BasePages; using umbraco.BusinessLogic.Utils; +using umbraco.cms; using umbraco.cms.businesslogic.web; using umbraco.cms.businesslogic.workflow; using umbraco.interfaces; @@ -35,9 +36,6 @@ namespace umbraco.BusinessLogic.Actions private static readonly Dictionary ActionJs = new Dictionary(); private static readonly object Lock = new object(); - private static readonly object LockerReRegister = new object(); - - private static readonly Umbraco.Core.TypeFinder2 TypeFinder = new TypeFinder2(); static Action() { @@ -64,17 +62,11 @@ namespace umbraco.BusinessLogic.Actions /// private static void RegisterIActionHandlers() { - if (ActionHandlers.Count == 0) { - - var foundIActionHandlers = TypeFinder.FindClassesOfType(); - foreach (var type in foundIActionHandlers) - { - var typeInstance = Activator.CreateInstance(type) as IActionHandler; - if (typeInstance != null) - ActionHandlers.Add(typeInstance); - } + ActionHandlers.AddRange( + PluginTypeResolver.Current.CreateInstances( + PluginTypeResolver.Current.ResolveActions())); } } diff --git a/src/umbraco.cms/PluginTypeResolverExtensions.cs b/src/umbraco.cms/PluginTypeResolverExtensions.cs new file mode 100644 index 0000000000..3588a855dc --- /dev/null +++ b/src/umbraco.cms/PluginTypeResolverExtensions.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core; +using umbraco.BusinessLogic.Actions; +using umbraco.businesslogic; +using umbraco.cms.businesslogic.macro; +using umbraco.cms.businesslogic.media; +using umbraco.interfaces; + +namespace umbraco.cms +{ + /// + /// Extension methods for the PluginTypeResolver + /// + public static class PluginTypeResolverExtensions + { + + /// + /// Returns all available IActionHandler in application + /// + /// + /// + internal static IEnumerable ResolveActions(this PluginTypeResolver resolver) + { + return resolver.ResolveTypes(); + } + + /// + /// Returns all available IDataType in application + /// + /// + /// + internal static IEnumerable ResolveDataTypes(this PluginTypeResolver resolver) + { + return resolver.ResolveTypes(); + } + + /// + /// Returns all available IDataType in application + /// + /// + /// + internal static IEnumerable ResolveMacroEngines(this PluginTypeResolver resolver) + { + return resolver.ResolveTypes(); + } + + /// + /// Returns all available IMediaFactory in application + /// + /// + /// + internal static IEnumerable ResolveMediaFactories(this PluginTypeResolver resolver) + { + return resolver.ResolveTypes(); + } + + /// + /// Returns all available IPackageAction in application + /// + /// + /// + internal static IEnumerable ResolvePackageActions(this PluginTypeResolver resolver) + { + return resolver.ResolveTypes(); + } + + } +} \ No newline at end of file diff --git a/src/umbraco.cms/Properties/AssemblyInfo.cs b/src/umbraco.cms/Properties/AssemblyInfo.cs index c38a6bd99c..9cbdba2843 100644 --- a/src/umbraco.cms/Properties/AssemblyInfo.cs +++ b/src/umbraco.cms/Properties/AssemblyInfo.cs @@ -13,4 +13,5 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("umbraco", AllInternalsVisible=true)] -[assembly: InternalsVisibleTo("Umbraco.LegacyTests")] \ No newline at end of file +[assembly: InternalsVisibleTo("Umbraco.LegacyTests")] +[assembly: InternalsVisibleTo("Umbraco.Tests")] \ No newline at end of file diff --git a/src/umbraco.cms/businesslogic/Packager/PackageInstance/PackageActions.cs b/src/umbraco.cms/businesslogic/Packager/PackageInstance/PackageActions.cs index 36f24a918e..151de71d00 100644 --- a/src/umbraco.cms/businesslogic/Packager/PackageInstance/PackageActions.cs +++ b/src/umbraco.cms/businesslogic/Packager/PackageInstance/PackageActions.cs @@ -3,7 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Web; using System.Xml; - +using Umbraco.Core; using umbraco.BasePages; using umbraco.BusinessLogic.Utils; using umbraco.cms.businesslogic.web; @@ -11,79 +11,84 @@ using umbraco.cms.businesslogic.workflow; using umbraco.interfaces; -namespace umbraco.cms.businesslogic.packager { +namespace umbraco.cms.businesslogic.packager +{ - /// - /// Package actions are executed on packge install / uninstall. - /// - public class PackageAction { - private static readonly List _packageActions = new List(); + /// + /// Package actions are executed on packge install / uninstall. + /// + public class PackageAction + { + internal static readonly List PackageActions = new List(); - /// - /// Initializes the class. - /// - static PackageAction(){ - RegisterPackageActions(); - } - - private static void RegisterPackageActions() - { - var typeFinder = new Umbraco.Core.TypeFinder2(); - var types = typeFinder.FindClassesOfType(); - foreach (var t in types) - { - var typeInstance = Activator.CreateInstance(t) as IPackageAction; - if (typeInstance != null) - { - _packageActions.Add(typeInstance); - - if (HttpContext.Current != null) - HttpContext.Current.Trace.Write("registerPackageActions", " + Adding package action '" + typeInstance.Alias()); - } - } - } + /// + /// Initializes the class. + /// + static PackageAction() + { + RegisterPackageActions(); + } - /// - /// Runs the package action with the specified action alias. - /// - /// Name of the package. - /// The action alias. - /// The action XML. - public static void RunPackageAction(string packageName, string actionAlias, System.Xml.XmlNode actionXml) { + private static void RegisterPackageActions() + { + PackageActions.AddRange( + PluginTypeResolver.Current.CreateInstances( + PluginTypeResolver.Current.ResolvePackageActions())); + } - foreach (IPackageAction ipa in _packageActions) { - try { - if (ipa.Alias() == actionAlias) { + /// + /// Runs the package action with the specified action alias. + /// + /// Name of the package. + /// The action alias. + /// The action XML. + public static void RunPackageAction(string packageName, string actionAlias, System.Xml.XmlNode actionXml) + { - ipa.Execute(packageName, actionXml); - } - } catch (Exception ipaExp) { - BusinessLogic.Log.Add(BusinessLogic.LogTypes.Error, BusinessLogic.User.GetUser(0), -1, string.Format("Error loading package action '{0}' for package {1}: {2}", - ipa.Alias(), packageName, ipaExp)); - } - } - } + foreach (IPackageAction ipa in PackageActions) + { + try + { + if (ipa.Alias() == actionAlias) + { - /// - /// Undos the package action with the specified action alias. - /// - /// Name of the package. - /// The action alias. - /// The action XML. - public static void UndoPackageAction(string packageName, string actionAlias, System.Xml.XmlNode actionXml) { + ipa.Execute(packageName, actionXml); + } + } + catch (Exception ipaExp) + { + BusinessLogic.Log.Add(BusinessLogic.LogTypes.Error, BusinessLogic.User.GetUser(0), -1, string.Format("Error loading package action '{0}' for package {1}: {2}", + ipa.Alias(), packageName, ipaExp)); + } + } + } - foreach (IPackageAction ipa in _packageActions) { - try { - if (ipa.Alias() == actionAlias) { + /// + /// Undos the package action with the specified action alias. + /// + /// Name of the package. + /// The action alias. + /// The action XML. + public static void UndoPackageAction(string packageName, string actionAlias, System.Xml.XmlNode actionXml) + { - ipa.Undo(packageName, actionXml); - } - } catch (Exception ipaExp) { - BusinessLogic.Log.Add(BusinessLogic.LogTypes.Error, BusinessLogic.User.GetUser(0), -1, string.Format("Error undoing package action '{0}' for package {1}: {2}", - ipa.Alias(), packageName, ipaExp)); - } - } - } - - } + foreach (IPackageAction ipa in PackageActions) + { + try + { + if (ipa.Alias() == actionAlias) + { + + ipa.Undo(packageName, actionXml); + } + } + catch (Exception ipaExp) + { + BusinessLogic.Log.Add(BusinessLogic.LogTypes.Error, BusinessLogic.User.GetUser(0), -1, string.Format("Error undoing package action '{0}' for package {1}: {2}", + ipa.Alias(), packageName, ipaExp)); + } + } + } + + } } diff --git a/src/umbraco.cms/businesslogic/datatype/factory.cs b/src/umbraco.cms/businesslogic/datatype/factory.cs index 617c6bf093..240742cddd 100644 --- a/src/umbraco.cms/businesslogic/datatype/factory.cs +++ b/src/umbraco.cms/businesslogic/datatype/factory.cs @@ -1,7 +1,9 @@ using System; using System.Collections; +using System.Collections.Concurrent; +using System.Linq; using System.Web; - +using Umbraco.Core; using umbraco.BusinessLogic.Utils; using umbraco.interfaces; using System.Collections.Generic; @@ -17,7 +19,7 @@ namespace umbraco.cms.businesslogic.datatype.controls { #region Declarations - private static readonly Dictionary _controls = new Dictionary(); + internal static readonly ConcurrentDictionary _controls = new ConcurrentDictionary(); #endregion @@ -53,7 +55,7 @@ namespace umbraco.cms.businesslogic.datatype.controls } if (_controls.ContainsKey(DataEditorId)) { - IDataType newObject = Activator.CreateInstance(_controls[DataEditorId]) as IDataType; + var newObject = PluginTypeResolver.Current.CreateInstance(_controls[DataEditorId]); return newObject; } else @@ -68,10 +70,10 @@ namespace umbraco.cms.businesslogic.datatype.controls /// A list of IDataType's public IDataType[] GetAll() { - IDataType[] retVal = new IDataType[_controls.Count]; - int c = 0; + var retVal = new IDataType[_controls.Count]; + var c = 0; - foreach (Guid id in _controls.Keys) + foreach (var id in _controls.Keys) { retVal[c] = GetNewObject(id); c++; @@ -80,39 +82,19 @@ namespace umbraco.cms.businesslogic.datatype.controls return retVal; } - private static void Initialize() + internal static void Initialize() { // Get all datatypes from interface - var typeFinder = new Umbraco.Core.TypeFinder2(); - var types = typeFinder.FindClassesOfType(); - GetDataTypes(types); - } - - private static void GetDataTypes(IEnumerable types) - { - foreach (var t in types) - { - IDataType typeInstance = null; - try - { - if (t.IsVisible) - { - typeInstance = Activator.CreateInstance(t) as IDataType; - } - } - catch { } - if (typeInstance != null) - { - try - { - _controls.Add(typeInstance.Id, t); - } - catch (Exception ee) - { - BusinessLogic.Log.Add(umbraco.BusinessLogic.LogTypes.Error, -1, "Can't import datatype '" + t.FullName + "': " + ee.ToString()); - } - } - } + var types = PluginTypeResolver.Current.ResolveDataTypes().ToArray(); + foreach (var t in types) + { + var instance = PluginTypeResolver.Current.CreateInstance(t); + if (instance != null) + { + _controls.TryAdd(instance.Id, t); + } + } } + } } \ No newline at end of file diff --git a/src/umbraco.cms/businesslogic/macro/MacroEngineFactory.cs b/src/umbraco.cms/businesslogic/macro/MacroEngineFactory.cs index 506c1a2d51..fe5406c76c 100644 --- a/src/umbraco.cms/businesslogic/macro/MacroEngineFactory.cs +++ b/src/umbraco.cms/businesslogic/macro/MacroEngineFactory.cs @@ -1,59 +1,50 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; +using Umbraco.Core; using umbraco.BusinessLogic.Utils; using umbraco.interfaces; namespace umbraco.cms.businesslogic.macro { + + //TODO: This class needs to be changed to use the new MultipleResolverBase + public class MacroEngineFactory { - private static readonly Dictionary m_engines = new Dictionary(); - private static readonly List m_allEngines = new List(); - private static object locker = new object(); + private static readonly List AllEngines = new List(); + private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); + private static volatile bool _isInitialized = false; public MacroEngineFactory() { - Initialize(); + EnsureInitialize(); } + internal static void EnsureInitialize() + { + if (_isInitialized) + return; + + using (new WriteLock(Lock)) + { + AllEngines.Clear(); + + AllEngines.AddRange( + PluginTypeResolver.Current.CreateInstances( + PluginTypeResolver.Current.ResolveMacroEngines())); + + _isInitialized = true; + } + } + + [Obsolete("Use EnsureInitialize method instead")] protected static void Initialize() { - var typeFinder = new Umbraco.Core.TypeFinder2(); - var types = typeFinder.FindClassesOfType(); - GetEngines(types); - } - - private static void GetEngines(IEnumerable types) - { - foreach (Type t in types) - { - IMacroEngine typeInstance = null; - try - { - if (t.IsVisible) - { - typeInstance = Activator.CreateInstance(t) as IMacroEngine; - } - } - catch { } - if (typeInstance != null) - { - try - { - lock (locker) - { - if (!m_engines.ContainsKey(typeInstance.Name)) - m_engines.Add(typeInstance.Name, t); - } - } - catch (Exception ee) - { - BusinessLogic.Log.Add(umbraco.BusinessLogic.LogTypes.Error, -1, "Can't import MacroEngine '" + t.FullName + "': " + ee); - } - } - } + EnsureInitialize(); } public static IEnumerable GetSupportedLanguages() { @@ -78,27 +69,15 @@ namespace umbraco.cms.businesslogic.macro public static List GetAll() { - - if (m_allEngines.Count == 0) - { - Initialize(); - foreach (string name in m_engines.Keys) { - m_allEngines.Add(GetEngine(name)); - } - } - - return m_allEngines; + EnsureInitialize(); + return AllEngines; } public static IMacroEngine GetEngine(string name) { - if (m_engines.ContainsKey(name)) - { - var newObject = Activator.CreateInstance(m_engines[name]) as IMacroEngine; - return newObject; - } - - return null; + EnsureInitialize(); + var engine = AllEngines.FirstOrDefault(x => x.Name == name); + return engine; } public static IMacroEngine GetByFilename(string filename) @@ -114,8 +93,7 @@ namespace umbraco.cms.businesslogic.macro public static IMacroEngine GetByExtension(string extension) { - IMacroEngine engine = - GetAll().Find(t => t.SupportedExtensions.Contains(extension)); + var engine = GetAll().Find(t => t.SupportedExtensions.Contains(extension)); if (engine != null) { return engine; diff --git a/src/umbraco.cms/businesslogic/media/MediaFactory.cs b/src/umbraco.cms/businesslogic/media/MediaFactory.cs index f11bf97d0b..da9154549d 100644 --- a/src/umbraco.cms/businesslogic/media/MediaFactory.cs +++ b/src/umbraco.cms/businesslogic/media/MediaFactory.cs @@ -3,14 +3,17 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Umbraco.Core; using umbraco.BusinessLogic; using umbraco.BusinessLogic.Utils; namespace umbraco.cms.businesslogic.media { + //TODO: This class needs to inherit from the new MultipleResolverBase class + public class MediaFactory { - private static readonly List Factories = new List(); + internal static readonly List Factories = new List(); static MediaFactory() { @@ -19,36 +22,11 @@ namespace umbraco.cms.businesslogic.media private static void Initialize() { - var typeFinder = new Umbraco.Core.TypeFinder2(); - var types = typeFinder.FindClassesOfType(); - - foreach (var t in types) - { - IMediaFactory typeInstance = null; - - try - { - if (t.IsVisible) - { - typeInstance = Activator.CreateInstance(t) as IMediaFactory; - } - } - catch { } - - if (typeInstance != null) - { - try - { - Factories.Add(typeInstance); - } - catch (Exception ee) - { - Log.Add(LogTypes.Error, -1, "Can't import MediaFactory '" + t.FullName + "': " + ee); - } - } - } - - Factories.Sort((f1, f2) => f1.Priority.CompareTo(f2.Priority)); + Factories.AddRange( + PluginTypeResolver.Current.CreateInstances( + PluginTypeResolver.Current.ResolveMediaFactories())); + + Factories.Sort((f1, f2) => f1.Priority.CompareTo(f2.Priority)); } public static IMediaFactory GetMediaFactory(int parentId, PostedMediaFile postedFile, User user) diff --git a/src/umbraco.cms/umbraco.cms.csproj b/src/umbraco.cms/umbraco.cms.csproj index 068836f738..bdd3b9639d 100644 --- a/src/umbraco.cms/umbraco.cms.csproj +++ b/src/umbraco.cms/umbraco.cms.csproj @@ -267,6 +267,7 @@ + Code diff --git a/src/umbraco.editorControls/PluginTypeResolverExtensions.cs b/src/umbraco.editorControls/PluginTypeResolverExtensions.cs new file mode 100644 index 0000000000..ae557087a1 --- /dev/null +++ b/src/umbraco.editorControls/PluginTypeResolverExtensions.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core; +using umbraco.BusinessLogic.Actions; +using umbraco.cms.businesslogic.macro; +using umbraco.cms.businesslogic.media; +using umbraco.interfaces; + +namespace umbraco.editorControls +{ + /// + /// Extension methods for the PluginTypeResolver + /// + public static class PluginTypeResolverExtensions + { + + /// + /// Returns all available IMacroGuiRendering in application + /// + /// + /// + internal static IEnumerable ResolveMacroRenderings(this PluginTypeResolver resolver) + { + return resolver.ResolveTypes(); + } + + + } +} \ No newline at end of file diff --git a/src/umbraco.editorControls/Properties/AssemblyInfo.cs b/src/umbraco.editorControls/Properties/AssemblyInfo.cs index 15de1fa37b..e84fc669e0 100644 --- a/src/umbraco.editorControls/Properties/AssemblyInfo.cs +++ b/src/umbraco.editorControls/Properties/AssemblyInfo.cs @@ -10,3 +10,5 @@ using System.Runtime.CompilerServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyProduct("")] + +[assembly: InternalsVisibleTo("Umbraco.Tests")] \ No newline at end of file diff --git a/src/umbraco.editorControls/macrocontainer/MacroControlFactory.cs b/src/umbraco.editorControls/macrocontainer/MacroControlFactory.cs index e7b7ff1f6a..da2b1d301b 100644 --- a/src/umbraco.editorControls/macrocontainer/MacroControlFactory.cs +++ b/src/umbraco.editorControls/macrocontainer/MacroControlFactory.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Web.UI; +using Umbraco.Core; using umbraco.BusinessLogic.Utils; using umbraco.interfaces; using umbraco.editorControls; @@ -12,14 +14,17 @@ namespace umbraco.editorControls.macrocontainer { internal class MacroControlFactory { - #region Private Fields + /// /// All Possible Macro types /// private static List _macroControlTypes = null; - #endregion + + private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); + #region Methods + /// /// Create an instance of a Macro control and return it. /// Because the macro control uses inline client script whichs is not generated after postback @@ -27,19 +32,22 @@ namespace umbraco.editorControls.macrocontainer /// internal static Control GetMacroRenderControlByType(PersistableMacroProperty prop, string uniqueID) { - Control macroControl; - - Type m = MacroControlTypes.FindLast(delegate(Type macroGuiCcontrol) { return macroGuiCcontrol.ToString() == string.Format("{0}.{1}", prop.AssemblyName, prop.TypeName); }); - IMacroGuiRendering typeInstance; - typeInstance = Activator.CreateInstance(m) as IMacroGuiRendering; - if (!string.IsNullOrEmpty(prop.Value)) - { - ((IMacroGuiRendering)typeInstance).Value = prop.Value; - } - macroControl = (Control)typeInstance; - - macroControl.ID = uniqueID; - return macroControl; + var m = MacroControlTypes.FindLast(macroGuiCcontrol => macroGuiCcontrol.ToString() == string.Format("{0}.{1}", prop.AssemblyName, prop.TypeName)); + var instance = PluginTypeResolver.Current.CreateInstance(m); + if (instance != null) + { + if (!string.IsNullOrEmpty(prop.Value)) + { + instance.Value = prop.Value; + } + var macroControl = instance as Control; + if (macroControl != null) + { + macroControl.ID = uniqueID; + return macroControl; + } + } + return null; } /// @@ -51,25 +59,29 @@ namespace umbraco.editorControls.macrocontainer { return ((IMacroGuiRendering)macroControl).Value; } + #endregion #region Properties /// /// All Possible Macro types /// - private static List MacroControlTypes + internal static List MacroControlTypes { get { - if (_macroControlTypes == null || !_macroControlTypes.Any()) - { - //Populate the list with all the types of IMacroGuiRendering - var typeFinder = new Umbraco.Core.TypeFinder2(); - _macroControlTypes = new List(); - _macroControlTypes = typeFinder.FindClassesOfType().ToList(); - } + using (var readLock = new UpgradeableReadLock(Lock)) + { + if (_macroControlTypes == null || !_macroControlTypes.Any()) + { - return _macroControlTypes; + readLock.UpgradeToWriteLock(); + + _macroControlTypes = new List(PluginTypeResolver.Current.ResolveMacroRenderings()); + } + + return _macroControlTypes; + } } } #endregion diff --git a/src/umbraco.editorControls/umbraco.editorControls.csproj b/src/umbraco.editorControls/umbraco.editorControls.csproj index cfdcd26b37..e3a392ee94 100644 --- a/src/umbraco.editorControls/umbraco.editorControls.csproj +++ b/src/umbraco.editorControls/umbraco.editorControls.csproj @@ -176,6 +176,7 @@ + Code