using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; namespace Umbraco.Core.ObjectResolution { /// /// The base class for old legacy factories such as the DataTypeFactory or CacheResolverFactory. /// /// The type of the concrete resolver class. /// The type of the resolved objects. /// /// 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 : LazyManyObjectsResolverBase where TResolved : class where TResolver : ResolverBase { private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); private ConcurrentDictionary _id2type; #region Constructors /// /// Initializes a new instance of the class with an initial list of object types. /// /// A function returning the list of object types. /// /// 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(Func> value) : base(value, ObjectLifetimeScope.Transient) // new objects every time { } #endregion /// /// Returns the unique identifier of the type of a specified object. /// /// The object. /// The unique identifier of the type of . protected abstract Guid GetUniqueIdentifier(TResolved value); /// /// Returns a new instance for the type identified by its unique type identifier. /// /// The type identifier. /// The value of the type uniquely identified by . public TResolved GetById(Guid id) { EnsureIsInitialized(); return !_id2type.ContainsKey(id) ? null : PluginManager.Current.CreateInstance(_id2type[id]); } /// /// Populates the identifiers-to-types dictionnary. /// /// /// This allow us to instantiate a type by ID since these legacy types doesn't contain any metadata. /// We instanciate all types once to get their unique identifier, then build the dictionary so that /// when GetById is called, we can instanciate a single object. /// protected void EnsureIsInitialized() { using (var l = new UpgradeableReadLock(_lock)) { if (_id2type == null) { l.UpgradeToWriteLock(); _id2type = new ConcurrentDictionary(); foreach (var value in Values) { _id2type.TryAdd(GetUniqueIdentifier(value), value.GetType()); } } } } } }