diff --git a/src/Umbraco.Core/PluginTypeResolver.cs b/src/Umbraco.Core/PluginTypeResolver.cs index 50df96c5c2..8440aadb02 100644 --- a/src/Umbraco.Core/PluginTypeResolver.cs +++ b/src/Umbraco.Core/PluginTypeResolver.cs @@ -104,6 +104,19 @@ namespace Umbraco.Core return instances; } + /// + /// Used to create an instance of the specified type based on the resolved/cached plugin types + /// + /// + /// + /// + /// + 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)) diff --git a/src/Umbraco.Core/Resolving/MultipleResolverBase.cs b/src/Umbraco.Core/Resolving/MultipleResolverBase.cs index 8fba742f58..85104696f0 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 to return and set a Multiply registered object. /// diff --git a/src/Umbraco.Tests/DataTypeFactoryTests.cs b/src/Umbraco.Tests/DataTypeFactoryTests.cs new file mode 100644 index 0000000000..46f0cedd7a --- /dev/null +++ b/src/Umbraco.Tests/DataTypeFactoryTests.cs @@ -0,0 +1,63 @@ +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 System.Linq; + +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, + 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 Find_All_DataTypes() + { + umbraco.cms.businesslogic.datatype.controls.Factory.Initialize(); + Assert.AreEqual(33, 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(33, factory.GetAll().Count()); + } + + } +} \ 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/PluginTypeResolverTests.cs b/src/Umbraco.Tests/PluginTypeResolverTests.cs index 96e0ede87a..058c71cb31 100644 --- a/src/Umbraco.Tests/PluginTypeResolverTests.cs +++ b/src/Umbraco.Tests/PluginTypeResolverTests.cs @@ -8,6 +8,7 @@ using umbraco.MacroEngines; using umbraco.MacroEngines.Iron; using umbraco.businesslogic; using umbraco.cms.businesslogic; +using umbraco.editorControls; using umbraco.uicontrols; using umbraco.cms; @@ -40,8 +41,8 @@ namespace Umbraco.Tests typeof(ISqlHelper).Assembly, typeof(DLRScriptingEngine).Assembly, typeof(ICultureDictionary).Assembly, - typeof(UmbracoContext).Assembly - + typeof(UmbracoContext).Assembly, + typeof(BaseDataType).Assembly }; } @@ -81,6 +82,13 @@ namespace Umbraco.Tests 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/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index ae089775fd..d00037beb8 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -49,6 +49,7 @@ + @@ -92,6 +93,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.cms/PluginTypeResolverExtensions.cs b/src/umbraco.cms/PluginTypeResolverExtensions.cs index 1ccda0c54d..6b5c56f1f5 100644 --- a/src/umbraco.cms/PluginTypeResolverExtensions.cs +++ b/src/umbraco.cms/PluginTypeResolverExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Umbraco.Core; using umbraco.BusinessLogic.Actions; using umbraco.businesslogic; +using umbraco.cms.businesslogic.macro; using umbraco.interfaces; namespace umbraco.cms @@ -23,5 +24,25 @@ namespace umbraco.cms 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(); + } + } } \ No newline at end of file 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;