using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Umbraco.Core.ObjectResolution
{
///
/// 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 : LazyManyObjectsResolverBase
where TResolved : class
where TResolver : 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(Func> types)
: base(types, ObjectLifetimeScope.Transient) // new objects every time
{
}
#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(TResolved obj);
///
/// Returns a new TResolved instance by id
///
///
///
public TResolved GetById(Guid id)
{
EnsureIdsAreTracked();
return !_trackIdToType.ContainsKey(id)
? null
: PluginManager.Current.CreateInstance(_trackIdToType[id]);
}
///
/// Populates the ids -> Type dictionary to allow us to instantiate a type by Id since these legacy types doesn't contain any metadata
///
protected void EnsureIdsAreTracked()
{
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());
}
}
}
}
}
}