Merge branch dev-v8 into temp-u4-8497

This commit is contained in:
Stephan
2016-07-20 12:38:57 +02:00
400 changed files with 13964 additions and 4002 deletions

View File

@@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
@@ -29,52 +27,30 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
/// <param name="isPreviewing">A value indicating whether the published content is being previewed.</param>
/// <param name="cacheProvider">A cache provider.</param>
/// <param name="contentTypeCache">A content type cache.</param>
public XmlPublishedContent(XmlNode xmlNode, bool isPreviewing, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache)
private XmlPublishedContent(XmlNode xmlNode, bool isPreviewing, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache)
{
_xmlNode = xmlNode;
_isPreviewing = isPreviewing;
_cacheProvider = cacheProvider;
_contentTypeCache = contentTypeCache;
InitializeStructure();
Initialize();
InitializeChildren();
}
/// <summary>
/// Initializes a new instance of the <c>XmlPublishedContent</c> class with an Xml node,
/// and a value indicating whether to lazy-initialize the instance.
/// </summary>
/// <param name="xmlNode">The Xml node.</param>
/// <param name="isPreviewing">A value indicating whether the published content is being previewed.</param>
/// <param name="cacheProvider">A cache provider.</param>
/// <param name="contentTypeCache">A content type cache.</param>
/// <param name="lazyInitialize">A value indicating whether to lazy-initialize the instance.</param>
/// <remarks>Lazy-initializationg is NOT thread-safe.</remarks>
internal XmlPublishedContent(XmlNode xmlNode, bool isPreviewing, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache, bool lazyInitialize)
{
_xmlNode = xmlNode;
_isPreviewing = isPreviewing;
_cacheProvider = cacheProvider;
_contentTypeCache = contentTypeCache;
InitializeStructure();
if (lazyInitialize == false)
{
Initialize();
InitializeChildren();
}
}
private readonly XmlNode _xmlNode;
private readonly bool _isPreviewing;
private readonly ICacheProvider _cacheProvider;
private readonly PublishedContentTypeCache _contentTypeCache;
private bool _initialized;
private bool _nodeInitialized;
private bool _parentInitialized;
private bool _childrenInitialized;
private readonly ICollection<IPublishedContent> _children = new Collection<IPublishedContent>();
private IEnumerable<IPublishedContent> _children = Enumerable.Empty<IPublishedContent>();
private IPublishedContent _parent;
private int _id;
private PublishedContentType _contentType;
private Dictionary<string, IPublishedProperty> _properties;
private int _id;
private Guid _key;
private int _template;
private string _name;
@@ -89,28 +65,25 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
private DateTime _createDate;
private DateTime _updateDate;
private Guid _version;
private IPublishedProperty[] _properties;
private int _sortOrder;
private int _level;
private bool _isDraft;
private readonly bool _isPreviewing;
private PublishedContentType _contentType;
public override IEnumerable<IPublishedContent> Children
{
get
{
if (_initialized == false)
Initialize();
if (_childrenInitialized == false)
InitializeChildren();
return _children.OrderBy(x => x.SortOrder);
if (_nodeInitialized == false) InitializeNode();
if (_childrenInitialized == false) InitializeChildren();
return _children;
}
}
public override IPublishedProperty GetProperty(string alias)
{
return Properties.FirstOrDefault(x => x.PropertyTypeAlias.InvariantEquals(alias));
if (_nodeInitialized == false) InitializeNode();
IPublishedProperty property;
return _properties.TryGetValue(alias, out property) ? property : null;
}
// override to implement cache
@@ -120,24 +93,21 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
if (recurse == false) return GetProperty(alias);
var key = string.Format("XmlPublishedCache.PublishedContentCache:RecursiveProperty-{0}-{1}", Id, alias.ToLowerInvariant());
var key = $"XmlPublishedCache.PublishedContentCache:RecursiveProperty-{Id}-{alias.ToLowerInvariant()}";
var cacheProvider = _cacheProvider;
return cacheProvider.GetCacheItem<IPublishedProperty>(key, () => base.GetProperty(alias, true));
// note: cleared by PublishedContentCache.Resync - any change here must be applied there
}
public override PublishedItemType ItemType
{
get { return PublishedItemType.Content; }
}
public override PublishedItemType ItemType => PublishedItemType.Content;
public override IPublishedContent Parent
public override IPublishedContent Parent
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
if (_parentInitialized == false) InitializeParent();
return _parent;
}
}
@@ -146,8 +116,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _id;
}
}
@@ -156,8 +125,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _key;
}
}
@@ -166,8 +134,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _template;
}
}
@@ -176,8 +143,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _sortOrder;
}
}
@@ -186,8 +152,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _name;
}
}
@@ -196,8 +161,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _docTypeAlias;
}
}
@@ -206,8 +170,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _docTypeId;
}
}
@@ -216,8 +179,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _writerName;
}
}
@@ -226,8 +188,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _creatorName;
}
}
@@ -236,8 +197,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _writerId;
}
}
@@ -246,8 +206,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _creatorId;
}
}
@@ -256,8 +215,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _path;
}
}
@@ -266,8 +224,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _createDate;
}
}
@@ -276,8 +233,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _updateDate;
}
}
@@ -286,8 +242,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _version;
}
}
@@ -296,8 +251,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _urlName;
}
}
@@ -306,8 +260,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _level;
}
}
@@ -316,8 +269,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _isDraft;
}
}
@@ -326,9 +278,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
return _properties;
if (_nodeInitialized == false) InitializeNode();
return _properties.Values;
}
}
@@ -336,24 +287,24 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
get
{
if (_initialized == false)
Initialize();
if (_nodeInitialized == false) InitializeNode();
return _contentType;
}
}
private void InitializeStructure()
{
// load parent if it exists and is a node
var parent = _xmlNode == null ? null : _xmlNode.ParentNode;
private void InitializeParent()
{
var parent = _xmlNode?.ParentNode;
if (parent == null) return;
if (parent.Attributes != null && parent.Attributes.GetNamedItem("isDoc") != null)
_parent = (new XmlPublishedContent(parent, _isPreviewing, _cacheProvider, _contentTypeCache, true)).CreateModel();
if (parent.Attributes?.GetNamedItem("isDoc") != null)
_parent = Get(parent, _isPreviewing, _cacheProvider, _contentTypeCache);
// warn: this is not thread-safe...
_parentInitialized = true;
}
private void Initialize()
private void InitializeNode()
{
if (_xmlNode == null) return;
@@ -382,7 +333,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
_creatorName = _writerName;
}
//Added the actual userID, as a user cannot be looked up via full name only...
//Added the actual userID, as a user cannot be looked up via full name only...
if (_xmlNode.Attributes.GetNamedItem("creatorID") != null)
_creatorId = int.Parse(_xmlNode.Attributes.GetNamedItem("creatorID").Value);
if (_xmlNode.Attributes.GetNamedItem("writerID") != null)
@@ -407,7 +358,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
}
// load data
var dataXPath = "* [not(@isDoc)]";
const string dataXPath = "* [not(@isDoc)]";
var nodes = _xmlNode.SelectNodes(dataXPath);
_contentType = _contentTypeCache.Get(PublishedItemType.Content, _docTypeAlias);
@@ -420,16 +371,19 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
propertyNodes[alias.ToLowerInvariant()] = n;
}
_properties = _contentType.PropertyTypes.Select(p =>
{
XmlNode n;
return propertyNodes.TryGetValue(p.PropertyTypeAlias.ToLowerInvariant(), out n)
? new XmlPublishedProperty(p, _isPreviewing, n)
: new XmlPublishedProperty(p, _isPreviewing);
}).Cast<IPublishedProperty>().ToArray();
_properties = _contentType.PropertyTypes.Select(p =>
{
XmlNode n;
return propertyNodes.TryGetValue(p.PropertyTypeAlias.ToLowerInvariant(), out n)
? new XmlPublishedProperty(p, _isPreviewing, n)
: new XmlPublishedProperty(p, _isPreviewing);
}).Cast<IPublishedProperty>().ToDictionary(
x => x.PropertyTypeAlias,
x => x,
StringComparer.OrdinalIgnoreCase);
// warn: this is not thread-safe...
_initialized = true;
_nodeInitialized = true;
}
private void InitializeChildren()
@@ -437,17 +391,49 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
if (_xmlNode == null) return;
// load children
var childXPath = "* [@isDoc]";
const string childXPath = "* [@isDoc]";
var nav = _xmlNode.CreateNavigator();
var expr = nav.Compile(childXPath);
expr.AddSort("@sortOrder", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Number);
//expr.AddSort("@sortOrder", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Number);
var iterator = nav.Select(expr);
while (iterator.MoveNext())
_children.Add(
(new XmlPublishedContent(((IHasXmlNode)iterator.Current).GetNode(), _isPreviewing, _cacheProvider, _contentTypeCache, true)).CreateModel());
_children = iterator.Cast<XPathNavigator>()
.Select(n => Get(((IHasXmlNode) n).GetNode(), _isPreviewing, _cacheProvider, _contentTypeCache))
.OrderBy(x => x.SortOrder)
.ToList();
// warn: this is not thread-safe
_childrenInitialized = true;
}
}
/// <summary>
/// Gets an IPublishedContent corresponding to an Xml cache node.
/// </summary>
/// <param name="node">The Xml node.</param>
/// <param name="isPreviewing">A value indicating whether we are previewing or not.</param>
/// <param name="cacheProvider">A cache provider.</param>
/// <param name="contentTypeCache">A content type cache.</param>
/// <returns>The IPublishedContent corresponding to the Xml cache node.</returns>
/// <remarks>Maintains a per-request cache of IPublishedContent items in order to make
/// sure that we create only one instance of each for the duration of a request. The
/// returned IPublishedContent is a model, if models are enabled.</remarks>
public static IPublishedContent Get(XmlNode node, bool isPreviewing, ICacheProvider cacheProvider, PublishedContentTypeCache contentTypeCache)
{
// only 1 per request
var attrs = node.Attributes;
var id = attrs?.GetNamedItem("id").Value;
if (id.IsNullOrWhiteSpace()) throw new InvalidOperationException("Node has no ID attribute.");
var cache = ApplicationContext.Current.ApplicationCache.RequestCache;
var key = CacheKeyPrefix + id; // dont bother with preview, wont change during request in v7
return (IPublishedContent) cache.GetCacheItem(key, () => (new XmlPublishedContent(node, isPreviewing, cacheProvider, contentTypeCache)).CreateModel());
}
public static void ClearRequest()
{
ApplicationContext.Current.ApplicationCache.RequestCache.ClearCacheByKeySearch(CacheKeyPrefix);
}
private const string CacheKeyPrefix = "CONTENTCACHE_XMLPUBLISHEDCONTENT_";
}
}