Files
Umbraco-CMS/src/Umbraco.Web/PublishedCache/NuCache/Property.cs

184 lines
6.7 KiB
C#
Raw Normal View History

2016-05-27 14:26:28 +02:00
using System;
using System.Xml.Serialization;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PublishedCache.NuCache
{
[Serializable]
[XmlType(Namespace = "http://umbraco.org/webservices/")]
class Property : PublishedPropertyBase
{
private readonly object _dataValue;
private readonly Guid _contentUid;
private readonly bool _isPreviewing;
private readonly bool _isMember;
readonly object _locko = new object();
private ValueSet _valueSet;
private string _valueSetCacheKey;
private string _recurseCacheKey;
// initializes a published content property with no value
public Property(PublishedPropertyType propertyType, PublishedContent content)
: this(propertyType, content, null)
{ }
// initializes a published content property with a value
public Property(PublishedPropertyType propertyType, PublishedContent content, object valueSource)
: base(propertyType)
{
_dataValue = valueSource;
_contentUid = content.Key;
var inner = PublishedContent.UnwrapIPublishedContent(content);
_isPreviewing = inner.IsPreviewing;
_isMember = content.ContentType.ItemType == PublishedItemType.Member;
}
// clone for previewing as draft a published content that is published and has no draft
public Property(Property origin)
: base(origin.PropertyType)
{
_dataValue = origin._dataValue;
_contentUid = origin._contentUid;
_isPreviewing = true;
_isMember = origin._isMember;
}
// detached
//internal Property(PublishedPropertyType propertyType, Guid contentUid, object valueSource, bool isPreviewing, bool isMember)
// : base(propertyType)
//{
// _dataValue = valueSource;
// _contentUid = contentUid;
// _isPreviewing = isPreviewing;
// _isMember = isMember;
//}
public override bool HasValue
{
get { return _dataValue != null && ((_dataValue is string) == false || string.IsNullOrWhiteSpace((string)_dataValue) == false); }
}
private class ValueSet
{
public bool SourceInitialized;
public object Source;
public bool ValueInitialized;
public object Value;
public bool XPathInitialized;
public object XPath;
}
internal string RecurseCacheKey
{
get { return _recurseCacheKey ?? (_recurseCacheKey = CacheKeys.PropertyRecurse(_contentUid, PropertyTypeAlias, _isPreviewing)); }
}
internal string ValueSetCacheKey
{
get { return _valueSetCacheKey ?? (_valueSetCacheKey = CacheKeys.PropertyValueSet(_contentUid, PropertyTypeAlias, _isPreviewing)); }
}
private ValueSet GetValueSet(PropertyCacheLevel cacheLevel)
{
ValueSet valueSet;
Facade facade;
ICacheProvider cache;
switch (cacheLevel)
{
case PropertyCacheLevel.None:
// never cache anything
valueSet = new ValueSet();
break;
case PropertyCacheLevel.Content:
// cache within the property object itself, ie within the content object
valueSet = _valueSet ?? (_valueSet = new ValueSet());
break;
case PropertyCacheLevel.ContentCache:
// cache within the snapshot cache, unless previewing, then use the facade or
// snapshot cache (if we don't want to pollute the snapshot cache with short-lived
// data) depending on settings
// for members, always cache in the facade cache - never pollute snapshot cache
facade = Facade.Current;
cache = facade == null
? null
: ((_isPreviewing == false || FacadeService.FullCacheWhenPreviewing) && (_isMember == false)
? facade.SnapshotCache
: facade.FacadeCache);
valueSet = GetValueSet(cache);
break;
case PropertyCacheLevel.Request:
// cache within the facade cache
facade = Facade.Current;
cache = facade == null ? null : facade.FacadeCache;
valueSet = GetValueSet(cache);
break;
default:
throw new InvalidOperationException("Invalid cache level.");
}
return valueSet;
}
private ValueSet GetValueSet(ICacheProvider cache)
{
if (cache == null) // no cache, don't cache
return new ValueSet();
return (ValueSet) cache.GetCacheItem(ValueSetCacheKey, () => new ValueSet());
}
private object GetSourceValue()
{
var valueSet = GetValueSet(PropertyType.SourceCacheLevel);
if (valueSet.SourceInitialized == false)
{
valueSet.Source = PropertyType.ConvertDataToSource(_dataValue, _isPreviewing);
valueSet.SourceInitialized = true;
}
return valueSet.Source;
}
public override object DataValue
{
get { return _dataValue; }
}
public override object Value
{
get
{
lock (_locko)
{
var valueSet = GetValueSet(PropertyType.ObjectCacheLevel);
if (valueSet.ValueInitialized == false)
{
valueSet.Value = PropertyType.ConvertSourceToObject(GetSourceValue(), _isPreviewing);
valueSet.ValueInitialized = true;
}
return valueSet.Value;
}
}
}
public override object XPathValue
{
get
{
lock (_locko)
{
var valueSet = GetValueSet(PropertyType.XPathCacheLevel);
if (valueSet.XPathInitialized == false)
{
valueSet.XPath = PropertyType.ConvertSourceToXPath(GetSourceValue(), _isPreviewing);
valueSet.XPathInitialized = true;
}
return valueSet.XPath;
}
}
}
}
}