diff --git a/src/Umbraco.Core/CacheRefreshersResolver.cs b/src/Umbraco.Core/CacheRefreshersResolver.cs index 9b363b4a80..1f8108b369 100644 --- a/src/Umbraco.Core/CacheRefreshersResolver.cs +++ b/src/Umbraco.Core/CacheRefreshersResolver.cs @@ -1,15 +1,15 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; -using System.Threading; -using Umbraco.Core.Resolving; using umbraco.interfaces; namespace Umbraco.Core { - internal sealed class CacheRefreshersResolver : ManyObjectResolverBase + /// + /// A resolver to return all ICacheRefresher objects + /// + internal sealed class CacheRefreshersResolver : LegacyTransientObjectsResolver { #region Singleton @@ -28,29 +28,14 @@ namespace Umbraco.Core /// /// Constructor /// - /// - /// - /// We are creating Transient instances (new instances each time) because this is how the legacy code worked and - /// I don't want to muck anything up by changing them to application based instances. - /// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier. - /// + /// internal CacheRefreshersResolver(IEnumerable refreshers) - : base(true) + : base(refreshers) { - foreach (var l in refreshers) - { - this.Add(l); - } + } #endregion - /// - /// Maintains a list of Ids and their types when first call to CacheResolvers or GetById occurs, this is used - /// in order to return a single object by id without instantiating the entire type stack. - /// - private static ConcurrentDictionary _refreshers; - private readonly ReaderWriterLockSlim _lock= new ReaderWriterLockSlim(); - /// /// Gets the implementations. /// @@ -63,37 +48,9 @@ namespace Umbraco.Core } } - /// - /// Returns a new ICacheRefresher instance by id - /// - /// - /// - public ICacheRefresher GetById(Guid id) + protected override Guid GetUniqueIdentifier(ICacheRefresher obj) { - EnsureRefreshersList(); - return !_refreshers.ContainsKey(id) - ? null - : PluginTypeResolver.Current.CreateInstance(_refreshers[id]); + return obj.UniqueIdentifier; } - - /// - /// Populates the refreshers dictionary to allow us to instantiate a type by Id since the ICacheRefresher type doesn't contain any metadata - /// - private void EnsureRefreshersList() - { - using (var l = new UpgradeableReadLock(_lock)) - { - if (_refreshers == null) - { - l.UpgradeToWriteLock(); - _refreshers = new ConcurrentDictionary(); - foreach(var v in Values) - { - _refreshers.TryAdd(v.UniqueIdentifier, v.GetType()); - } - } - } - } - } } diff --git a/src/Umbraco.Core/DataTypesResolver.cs b/src/Umbraco.Core/DataTypesResolver.cs new file mode 100644 index 0000000000..d7effb5690 --- /dev/null +++ b/src/Umbraco.Core/DataTypesResolver.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using umbraco.interfaces; + +namespace Umbraco.Core +{ + /// + /// A resolver to return all IDataType objects + /// + internal sealed class DataTypesResolver : LegacyTransientObjectsResolver + { + + #region Singleton + + private static readonly DataTypesResolver Instance = new DataTypesResolver(PluginTypeResolver.Current.ResolveDataTypes()); + + public static DataTypesResolver Current + { + get { return Instance; } + } + #endregion + + #region Constructors + static DataTypesResolver() { } + + /// + /// Constructor + /// + /// + internal DataTypesResolver(IEnumerable dataTypes) + : base(dataTypes) + { + + } + #endregion + + /// + /// Gets the implementations. + /// + public IEnumerable DataTypes + { + get + { + EnsureRefreshersList(); + return Values; + } + } + + protected override Guid GetUniqueIdentifier(IDataType obj) + { + return obj.Id; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/LegacyTransientObjectsResolver.cs b/src/Umbraco.Core/LegacyTransientObjectsResolver.cs new file mode 100644 index 0000000000..35602632ad --- /dev/null +++ b/src/Umbraco.Core/LegacyTransientObjectsResolver.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +using Umbraco.Core.Resolving; + +namespace Umbraco.Core +{ + /// + /// A base resolver used for old legacy factories such as the DataTypeFactory or CacheResolverFactory. + /// + /// + /// + /// This class contains basic functionality to mimic the functionality in these old factories since they all return + /// transient objects (though this should be changed) and the method GetById needs to lookup a type to an ID and since + /// these old classes don't contain metadata, the objects need to be instantiated first to get their metadata, we then store this + /// for use in the GetById method. + /// + internal abstract class LegacyTransientObjectsResolver : ManyObjectResolverBase + where T : class + { + + #region Constructors + + /// + /// Constructor + /// + /// + /// + /// We are creating Transient instances (new instances each time) because this is how the legacy code worked and + /// I don't want to muck anything up by changing them to application based instances. + /// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier. + /// + protected LegacyTransientObjectsResolver(IEnumerable refreshers) + : base(true) + { + foreach (var l in refreshers) + { + this.Add(l); + } + } + #endregion + + /// + /// Maintains a list of Ids and their types when first call to CacheResolvers or GetById occurs, this is used + /// in order to return a single object by id without instantiating the entire type stack. + /// + private ConcurrentDictionary _trackIdToType; + private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); + + /// + /// method to return the unique id for type T + /// + /// + /// + protected abstract Guid GetUniqueIdentifier(T obj); + + /// + /// Returns a new ICacheRefresher instance by id + /// + /// + /// + public T GetById(Guid id) + { + EnsureRefreshersList(); + return !_trackIdToType.ContainsKey(id) + ? null + : PluginTypeResolver.Current.CreateInstance(_trackIdToType[id]); + } + + /// + /// Populates the refreshers dictionary to allow us to instantiate a type by Id since the ICacheRefresher type doesn't contain any metadata + /// + protected void EnsureRefreshersList() + { + using (var l = new UpgradeableReadLock(_lock)) + { + if (_trackIdToType == null) + { + l.UpgradeToWriteLock(); + _trackIdToType = new ConcurrentDictionary(); + foreach (var v in Values) + { + _trackIdToType.TryAdd(GetUniqueIdentifier(v), v.GetType()); + } + } + } + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/PluginTypeResolver.cs b/src/Umbraco.Core/PluginTypeResolver.cs index c1218233aa..8740e4adf6 100644 --- a/src/Umbraco.Core/PluginTypeResolver.cs +++ b/src/Umbraco.Core/PluginTypeResolver.cs @@ -67,6 +67,15 @@ namespace Umbraco.Core return ResolveTypes(); } + /// + /// Returns all available IDataType in application + /// + /// + internal IEnumerable ResolveDataTypes() + { + return ResolveTypes(); + } + /// /// 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. diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 9d8780f644..67eee0d303 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -54,6 +54,7 @@ + @@ -63,6 +64,7 @@ + diff --git a/src/Umbraco.Tests/DataTypeFactoryTests.cs b/src/Umbraco.Tests/DataTypeFactoryTests.cs index eb31e16f1c..61e75a7338 100644 --- a/src/Umbraco.Tests/DataTypeFactoryTests.cs +++ b/src/Umbraco.Tests/DataTypeFactoryTests.cs @@ -26,13 +26,6 @@ namespace Umbraco.Tests }; } - [Test] - public void Find_All_DataTypes() - { - var factory = new umbraco.cms.businesslogic.datatype.controls.Factory(); - Assert.AreEqual(2, umbraco.cms.businesslogic.datatype.controls.Factory._controls.Count); - } - [Test] public void Get_All_Instances() { diff --git a/src/umbraco.cms/PluginTypeResolverExtensions.cs b/src/umbraco.cms/PluginTypeResolverExtensions.cs index a70e200363..b2e8545cc6 100644 --- a/src/umbraco.cms/PluginTypeResolverExtensions.cs +++ b/src/umbraco.cms/PluginTypeResolverExtensions.cs @@ -35,16 +35,6 @@ 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 /// diff --git a/src/umbraco.cms/businesslogic/datatype/factory.cs b/src/umbraco.cms/businesslogic/datatype/factory.cs index 3eb3751a22..b1cf3797bc 100644 --- a/src/umbraco.cms/businesslogic/datatype/factory.cs +++ b/src/umbraco.cms/businesslogic/datatype/factory.cs @@ -15,22 +15,9 @@ namespace umbraco.cms.businesslogic.datatype.controls /// /// Then registering is done using reflection. /// + [Obsolete("Use Umbraco.Core.DataTypesResolver instead")] public class Factory - { - #region Declarations - - internal static readonly ConcurrentDictionary _controls = new ConcurrentDictionary(); - - #endregion - - #region Constructors - - static Factory() - { - Initialize(); - } - - #endregion + { /// /// Retrieves the IDataType specified by it's unique ID @@ -49,19 +36,7 @@ namespace umbraco.cms.businesslogic.datatype.controls /// public IDataType GetNewObject(Guid DataEditorId) { - if (DataEditorId == Guid.Empty) - { - throw new ArgumentException("DataEditorId is empty. This usually means that no data editor was defined for the data type. To correct this update the entry in the cmsDataType table to ensure it matches a Guid from an installed data editor."); - } - if (_controls.ContainsKey(DataEditorId)) - { - var newObject = PluginTypeResolver.Current.CreateInstance(_controls[DataEditorId]); - return newObject; - } - else - { - throw new ArgumentException("Could not find a IDataType control matching DataEditorId " + DataEditorId.ToString() + " in the controls collection. To correct this, check the data type definition in the developer section or ensure that the package/control is installed correctly."); - } + return DataTypesResolver.Current.GetById(DataEditorId); } /// @@ -70,31 +45,9 @@ namespace umbraco.cms.businesslogic.datatype.controls /// A list of IDataType's public IDataType[] GetAll() { - var retVal = new IDataType[_controls.Count]; - var c = 0; - - foreach (var id in _controls.Keys) - { - retVal[c] = GetNewObject(id); - c++; - } - - return retVal; + return DataTypesResolver.Current.DataTypes.ToArray(); } - private static void Initialize() - { - // Get all datatypes from interface - 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