content.cs :  » Content-Management-Systems-CMS » umbraco » presentation » umbracoBase » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Content Management Systems CMS » umbraco 
umbraco » presentation » umbracoBase » content.cs
/// <changelog>
///   <item who="Esben" when="18. november 2006">Rewrote</item>
/// </changelog>

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Web;
using System.Xml;
using System.Xml.XPath;

using umbraco.BusinessLogic;
using umbraco.BusinessLogic.Actions;
using umbraco.cms.businesslogic.cache;
using umbraco.cms.businesslogic.web;
using umbraco.DataLayer;

namespace umbraco{
    /// <summary>
    /// Handles umbraco content
    /// </summary>
    public class content
    {
        #region Declarations

        private readonly string UmbracoXmlDiskCacheFileName = HttpRuntime.AppDomainAppPath +
                                                              GlobalSettings.ContentXML.Replace('/', '\\').TrimStart(
                                                                  '\\');

        private readonly string XmlContextContentItemKey = "UmbracoXmlContextContent";

        // Current content
        private volatile XmlDocument _xmlContent = null;

        // Sync access to disk file
        private object _readerWriterSyncLock = new object();

        // Sync access to internal cache
        private object _xmlContentInternalSyncLock = new object();

        // Sync database access
        private object _dbReadSyncLock = new object();

        #endregion

        #region Constructors

        public content()
        {
            ;
        }

        static content()
        {
            Trace.Write("Initializing content");
            ThreadPool.QueueUserWorkItem(
                delegate
                {
                    XmlDocument xmlDoc = Instance.XmlContentInternal;
                    Trace.WriteLine("Content initialized");
                });
        }

        #endregion

        #region Singleton

        public static content Instance
        {
            get { return Singleton<content>.Instance; }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Get content. First call to this property will initialize xmldoc
        /// subsequent calls will be blocked until initialization is done
        /// Further we cache(in context) xmlContent for each request to ensure that
        /// we always have the same XmlDoc throughout the whole request.
        /// Note that context cache does not need to be locked, because all access
        /// to it is done from a web request which runs in a single thread
        /// </summary>
        public virtual XmlDocument XmlContent
        {
            get
            {
                if (HttpContext.Current == null)
                    return XmlContentInternal;
                XmlDocument content = HttpContext.Current.Items[XmlContextContentItemKey] as XmlDocument;
                if (content == null)
                {
                    content = XmlContentInternal;
                    HttpContext.Current.Items[XmlContextContentItemKey] = content;
                }
                return content;
            }
        }

        [Obsolete("Please use: content.Instance.XmlContent")]
        public static XmlDocument xmlContent
        {
            get { return Instance.XmlContent; }
        }

        public virtual bool isInitializing
        {
            get { return _xmlContent == null; }
        }

        /// <summary>
        /// Internal reference to XmlContent
        /// </summary>
        protected virtual XmlDocument XmlContentInternal
        {
            get
            {
                if (isInitializing)
                {
                    lock (_xmlContentInternalSyncLock)
                    {
                        if (isInitializing)
                        {
                            _xmlContent = LoadContent();
                            if (!UmbracoSettings.isXmlContentCacheDisabled && !IsValidDiskCachePresent())
                                SaveContentToDiskAsync(_xmlContent);
                        }
                    }
                }

                return _xmlContent;
            }
            set
            {
                lock (_xmlContentInternalSyncLock)
                {
                    // Clear macro cache
                    Cache.ClearCacheObjectTypes("umbraco.MacroCacheContent");
                    requestHandler.ClearProcessedRequests();
                    _xmlContent = value;

                    if (!UmbracoSettings.isXmlContentCacheDisabled && UmbracoSettings.continouslyUpdateXmlDiskCache)
                        SaveContentToDiskAsync(_xmlContent);
                    else
                        // Clear cache...
                        ClearDiskCacheAsync();
                }
            }
        }

        #endregion

        protected static ISqlHelper SqlHelper
        {
            get { return Application.SqlHelper; }
        }

        #region Public Methods

        /// <summary>
        /// Load content from database in a background thread
        /// Replaces active content when done.
        /// </summary>
        public virtual void RefreshContentFromDatabaseAsync()
        {
            cms.businesslogic.RefreshContentEventArgs e = new umbraco.cms.businesslogic.RefreshContentEventArgs();
            FireBeforeRefreshContent(e);

            if (!e.Cancel)
            {
                ThreadPool.QueueUserWorkItem(
                    delegate
                    {
                        XmlDocument xmlDoc = LoadContentFromDatabase(true);
                        XmlContentInternal = xmlDoc;

                        if (!UmbracoSettings.isXmlContentCacheDisabled)
                            SaveContentToDisk(xmlDoc);
                    });

                FireAfterRefreshContent(e);
            }
        }

        private void TransferValuesFromDocumentXmlToPublishedXml(XmlNode DocumentNode, XmlNode PublishedNode)
        {
            // Remove all attributes and data nodes from the published node
            PublishedNode.Attributes.RemoveAll();
            foreach (XmlNode n in PublishedNode.SelectNodes("./data"))
                PublishedNode.RemoveChild(n);

            // Append all attributes and datanodes from the documentnode to the publishednode
            foreach (XmlAttribute att in DocumentNode.Attributes)
                ((XmlElement)PublishedNode).SetAttribute(att.Name, att.Value);

            foreach (XmlElement el in DocumentNode.SelectNodes("./data"))
            {
                XmlNode newDatael = PublishedNode.OwnerDocument.ImportNode(el, true);
                PublishedNode.AppendChild(newDatael);
            }
        }

        /// <summary>
        /// Used by all overloaded publish methods to do the actual "noderepresentation to xml"
        /// </summary>
        /// <param name="d"></param>
        /// <param name="xmlContentCopy"></param>
        private void PublishNodeDo(Document d, XmlDocument xmlContentCopy)
        {
            // check if document *is* published, it could be unpublished by an event
            if (d.Published)
            {

                // Find the document in the xml cache
                XmlNode x = xmlContentCopy.GetElementById(d.Id.ToString());

                // Find the parent (used for sortering and maybe creation of new node)
                XmlNode parentNode;
                if (d.Level == 1)
                    parentNode = xmlContentCopy.DocumentElement;
                else
                    parentNode = xmlContentCopy.GetElementById(d.Parent.Id.ToString());

                if (parentNode != null)
                {
                    if (x == null)
                    {
                        x = d.ToXml(xmlContentCopy, false);
                        parentNode.AppendChild(x);
                    }
                    else
                        TransferValuesFromDocumentXmlToPublishedXml(d.ToXml(xmlContentCopy, false), x);

                    XmlNodeList childNodes = parentNode.SelectNodes("./node");

                    // Maybe sort the nodes if the added node has a lower sortorder than the last
                    if (childNodes.Count > 0)
                    {
                        int siblingSortOrder = int.Parse(childNodes[childNodes.Count - 1].Attributes.GetNamedItem("sortOrder").Value);
                        int currentSortOrder = int.Parse(x.Attributes.GetNamedItem("sortOrder").Value);
                        if (childNodes.Count > 1 && siblingSortOrder > currentSortOrder)
                        {
                            SortNodes(ref parentNode);
                        }
                    }
                }

                // update sitemapprovider
                if (SiteMap.Provider is presentation.nodeFactory.UmbracoSiteMapProvider)
                {
                    presentation.nodeFactory.UmbracoSiteMapProvider prov = (presentation.nodeFactory.UmbracoSiteMapProvider)SiteMap.Provider;
                    prov.UpdateNode(new umbraco.presentation.nodeFactory.Node(d.Id));
                }
            }
        }

        /// <summary>
        /// Sorts the documents.
        /// </summary>
        /// <param name="parentNode">The parent node.</param>
        public static void SortNodes(ref XmlNode parentNode)
        {
            XmlNode n = parentNode.CloneNode(true);

            // remove all children from original node
            foreach (XmlNode child in parentNode.SelectNodes("./node"))
                parentNode.RemoveChild(child);


            XPathNavigator nav = n.CreateNavigator();
            XPathExpression expr = nav.Compile("./node");
            expr.AddSort("@sortOrder", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Number);
            XPathNodeIterator iterator = nav.Select(expr);
            while (iterator.MoveNext())
                parentNode.AppendChild(
                    ((IHasXmlNode)iterator.Current).GetNode());
        }


        /// <summary>
        /// Updates the document cache.
        /// </summary>
        /// <param name="pageId">The page id.</param>
        public virtual void UpdateDocumentCache(int pageId)
        {
            Document d = new Document(pageId);
            UpdateDocumentCache(d);
        }


        /// <summary>
        /// Updates the document cache.
        /// </summary>
        /// <param name="d">The d.</param>
        public virtual void UpdateDocumentCache(Document d)
        {

            cms.businesslogic.DocumentCacheEventArgs e = new umbraco.cms.businesslogic.DocumentCacheEventArgs();
            FireBeforeUpdateDocumentCache(d, e);

            if (!e.Cancel)
            {

                // We need to lock content cache here, because we cannot allow other threads
                // making changes at the same time, they need to be queued
                // Adding log entry before locking the xmlfile
                lock (_xmlContentInternalSyncLock)
                {
                    // Make copy of memory content, we cannot make changes to the same document
                    // the is read from elsewhere
                    if (UmbracoSettings.CloneXmlCacheOnPublish)
                    {
                        XmlDocument xmlContentCopy = CloneXmlDoc(XmlContentInternal);

                        PublishNodeDo(d, xmlContentCopy);
                        XmlContentInternal = xmlContentCopy;
                    }
                    else
                    {
                        PublishNodeDo(d, XmlContentInternal);
                        XmlContentInternal = _xmlContent;
                    }

                    ClearContextCache();
                }

                // clear cached field values
                System.Web.Caching.Cache httpCache = HttpContext.Current.Cache;
                string cachedFieldKeyStart = String.Format("contentItem{0}_", d.Id);
                List<string> foundKeys = new List<string>();
                foreach (DictionaryEntry cacheItem in httpCache)
                {
                    string key = cacheItem.Key.ToString();
                    if (key.StartsWith(cachedFieldKeyStart))
                        foundKeys.Add(key);
                }
                foreach (string foundKey in foundKeys)
                {
                    httpCache.Remove(foundKey);
                }

                umbraco.BusinessLogic.Actions.Action.RunActionHandlers(d, ActionPublish.Instance);

                FireAfterUpdateDocumentCache(d, e);
            }
        }

        /// <summary>
        /// Updates the document cache for multiple documents
        /// </summary>
        /// <param name="Documents">The documents.</param>
        public virtual void UpdateDocumentCache(List<Document> Documents)
        {
            // We need to lock content cache here, because we cannot allow other threads
            // making changes at the same time, they need to be queued
            int parentid = Documents[0].Id;

            lock (_xmlContentInternalSyncLock)
            {
                // Make copy of memory content, we cannot make changes to the same document
                // the is read from elsewhere
                XmlDocument xmlContentCopy = CloneXmlDoc(XmlContentInternal);
                foreach (Document d in Documents)
                {
                    PublishNodeDo(d, xmlContentCopy);
                }
                XmlContentInternal = xmlContentCopy;
                ClearContextCache();
            }

            foreach (Document d in Documents)
            {
                umbraco.BusinessLogic.Actions.Action.RunActionHandlers(d, ActionPublish.Instance);
            }
        }

        /// <summary>
        /// Updates the document cache async.
        /// </summary>
        /// <param name="documentId">The document id.</param>
        public virtual void UpdateDocumentCacheAsync(int documentId)
        {
            ThreadPool.QueueUserWorkItem(delegate { UpdateDocumentCache(documentId); });
        }



        /// <summary>
        /// Clears the document cache async.
        /// </summary>
        /// <param name="documentId">The document id.</param>
        public virtual void ClearDocumentCacheAsync(int documentId)
        {
            ThreadPool.QueueUserWorkItem(delegate { ClearDocumentCache(documentId); });
        }


        /// <summary>
        /// Clears the document cache and removes the document from the xml db cache.
        /// This means the node gets unpublished from the website.
        /// </summary>
        /// <param name="documentId">The document id.</param>
        public virtual void ClearDocumentCache(int documentId)
        {

            // Get the document
            Document d = new Document(documentId);

            cms.businesslogic.DocumentCacheEventArgs e = new umbraco.cms.businesslogic.DocumentCacheEventArgs();
            FireBeforeClearDocumentCache(d, e);

            if (!e.Cancel)
            {
                XmlNode x;

                // remove from xml db cache 
                d.XmlRemoveFromDB();

                // Check if node present, before cloning
                x = XmlContentInternal.GetElementById(d.Id.ToString());
                if (x == null)
                    return;

                // We need to lock content cache here, because we cannot allow other threads
                // making changes at the same time, they need to be queued
                lock (_xmlContentInternalSyncLock)
                {
                    // Make copy of memory content, we cannot make changes to the same document
                    // the is read from elsewhere
                    XmlDocument xmlContentCopy = CloneXmlDoc(XmlContentInternal);

                    // Find the document in the xml cache
                    x = xmlContentCopy.GetElementById(d.Id.ToString());
                    if (x != null)
                    {
                        // The document already exists in cache, so repopulate it
                        x.ParentNode.RemoveChild(x);
                        XmlContentInternal = xmlContentCopy;
                        ClearContextCache();
                    }
                }

                if (x != null)
                {
                    // Run Handler        
                    umbraco.BusinessLogic.Actions.Action.RunActionHandlers(d, ActionUnPublish.Instance);
                }

                // update sitemapprovider
                if (SiteMap.Provider is presentation.nodeFactory.UmbracoSiteMapProvider)
                {
                    presentation.nodeFactory.UmbracoSiteMapProvider prov = (presentation.nodeFactory.UmbracoSiteMapProvider)SiteMap.Provider;
                    prov.RemoveNode(d.Id);
                }

                FireAfterClearDocumentCache(d, e);
            }
        }


        /// <summary>
        /// Unpublishes the  node.
        /// </summary>
        /// <param name="documentId">The document id.</param>
        [Obsolete("Please use: umbraco.content.ClearDocumentCache")]
        public virtual void UnPublishNode(int documentId)
        {
            ClearDocumentCache(documentId);
        }

        /// <summary>
        /// Uns the publish node async.
        /// </summary>
        /// <param name="documentId">The document id.</param>
        [Obsolete("Please use: umbraco.content.ClearDocumentCacheAsync")]
        public virtual void UnPublishNodeAsync(int documentId)
        {
            ThreadPool.QueueUserWorkItem(delegate { ClearDocumentCache(documentId); });
        }

        /// <summary>
        /// Legacy method - you should use the overloaded publishnode(document d) method whenever possible
        /// </summary>
        /// <param name="documentId"></param>
        [Obsolete("Please use: umbraco.content.UpdateDocumentCache")]
        public virtual void PublishNode(int documentId)
        {
            // Get the document
            Document d = new Document(documentId);
            PublishNode(d);
        }

        /// <summary>
        /// Publishes the node async.
        /// </summary>
        /// <param name="documentId">The document id.</param>
        [Obsolete("Please use: umbraco.content.UpdateDocumentCacheAsync")]
        public virtual void PublishNodeAsync(int documentId)
        {
            UpdateDocumentCacheAsync(documentId);
        }

        /// <summary>
        /// Publishes the node.
        /// </summary>
        /// <param name="Documents">The documents.</param>
        [Obsolete("Please use: umbraco.content.UpdateDocumentCache")]
        public virtual void PublishNode(List<Document> Documents)
        {
            UpdateDocumentCache(Documents);
        }


        /// <summary>
        /// Publishes the node.
        /// </summary>
        /// <param name="d">The document.</param>
        [Obsolete("Please use: umbraco.content.UpdateDocumentCache")]
        public virtual void PublishNode(Document d)
        {
            UpdateDocumentCache(d);
        }

        public delegate void DocumentCacheEventHandler(Document sender, cms.businesslogic.DocumentCacheEventArgs e);
        public delegate void RefreshContentEventHandler(Document sender, cms.businesslogic.RefreshContentEventArgs e);

        /// <summary>
        /// Occurs when [before document cache update].
        /// </summary>
        public static event DocumentCacheEventHandler BeforeUpdateDocumentCache;

        /// <summary>
        /// Fires the before document cache.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="umbraco.cms.businesslogic.DocumentCacheEventArgs"/> instance containing the event data.</param>
        protected virtual void FireBeforeUpdateDocumentCache(Document sender, cms.businesslogic.DocumentCacheEventArgs e)
        {
            if (BeforeUpdateDocumentCache != null)
            {
                BeforeUpdateDocumentCache(sender, e);
            }
        }


        /// <summary>
        /// Occurs when [after document cache update].
        /// </summary>
        public static event DocumentCacheEventHandler AfterUpdateDocumentCache;

        /// <summary>
        /// Fires after document cache updater.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="umbraco.cms.businesslogic.DocumentCacheEventArgs"/> instance containing the event data.</param>
        protected virtual void FireAfterUpdateDocumentCache(Document sender, cms.businesslogic.DocumentCacheEventArgs e)
        {
            if (AfterUpdateDocumentCache != null)
            {
                AfterUpdateDocumentCache(sender, e);
            }
        }

        /// <summary>
        /// Occurs when [before document cache unpublish].
        /// </summary>
        public static event DocumentCacheEventHandler BeforeClearDocumentCache;

        /// <summary>
        /// Fires the before document cache unpublish.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="umbraco.cms.businesslogic.DocumentCacheEventArgs"/> instance containing the event data.</param>
        protected virtual void FireBeforeClearDocumentCache(Document sender, cms.businesslogic.DocumentCacheEventArgs e)
        {
            if (BeforeClearDocumentCache != null)
            {
                BeforeClearDocumentCache(sender, e);
            }
        }

        public static event DocumentCacheEventHandler AfterClearDocumentCache;

        /// <summary>
        /// Fires the after document cache unpublish.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="umbraco.cms.businesslogic.DocumentCacheEventArgs"/> instance containing the event data.</param>
        protected virtual void FireAfterClearDocumentCache(Document sender, cms.businesslogic.DocumentCacheEventArgs e)
        {
            if (AfterClearDocumentCache != null)
            {
                AfterClearDocumentCache(sender, e);
            }
        }

        /// <summary>
        /// Occurs when [before refresh content].
        /// </summary>
        public static event RefreshContentEventHandler BeforeRefreshContent;

        /// <summary>
        /// Fires the content of the before refresh.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="umbraco.cms.businesslogic.RefreshContentEventArgs"/> instance containing the event data.</param>
        protected virtual void FireBeforeRefreshContent(cms.businesslogic.RefreshContentEventArgs e)
        {
            if (BeforeRefreshContent != null)
            {
                BeforeRefreshContent(null, e);
            }
        }

        /// <summary>
        /// Occurs when [after refresh content].
        /// </summary>
        public static event RefreshContentEventHandler AfterRefreshContent;

        /// <summary>
        /// Fires the content of the after refresh.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="umbraco.cms.businesslogic.RefreshContentEventArgs"/> instance containing the event data.</param>
        protected virtual void FireAfterRefreshContent(cms.businesslogic.RefreshContentEventArgs e)
        {
            if (AfterRefreshContent != null)
            {
                AfterRefreshContent(null, e);
            }
        }



        #endregion

        #region Protected & Private methods

        /// <summary>
        /// Invalidates the disk content cache file. Effectively just deletes it.
        /// </summary>
        private void ClearDiskCache()
        {
            lock (_readerWriterSyncLock)
            {
                if (File.Exists(UmbracoXmlDiskCacheFileName))
                {
                    // Reset file attributes, to make sure we can delete file
                    File.SetAttributes(UmbracoXmlDiskCacheFileName, FileAttributes.Normal);
                    File.Delete(UmbracoXmlDiskCacheFileName);
                }
            }
        }

        /// <summary>
        /// Clear HTTPContext cache if any
        /// </summary>
        private void ClearContextCache()
        {
            // If running in a context very important to reset context cache orelse new nodes are missing
            if (HttpContext.Current != null && HttpContext.Current.Items.Contains(XmlContextContentItemKey))
                HttpContext.Current.Items.Remove(XmlContextContentItemKey);
        }

        /// <summary>
        /// Invalidates the disk content cache file. Effectively just deletes it.
        /// </summary>
        private void ClearDiskCacheAsync()
        {
            // Queue file deletion
            // We queue this function, because there can be a write process running at the same time
            // and we don't want this method to block web request
            ThreadPool.QueueUserWorkItem(
                delegate { ClearDiskCache(); });
        }

        /// <summary>
        /// Load content from either disk or database
        /// </summary>
        /// <returns></returns>
        private XmlDocument LoadContent()
        {
            if (!UmbracoSettings.isXmlContentCacheDisabled && IsValidDiskCachePresent())
            {
                try
                {
                    return LoadContentFromDiskCache();
                }
                catch (Exception e)
                {
                    // This is really bad, loading from cache file failed for some reason, now fallback to loading from database
                    Debug.WriteLine("Content file cache load failed: " + e);
                    ClearDiskCache();
                }
            }
            return LoadContentFromDatabase(true);
        }

        private bool IsValidDiskCachePresent()
        {
            return File.Exists(UmbracoXmlDiskCacheFileName);
        }

        /// <summary>
        /// Load content from cache file
        /// </summary>
        private XmlDocument LoadContentFromDiskCache()
        {
            lock (_readerWriterSyncLock)
            {
                XmlDocument xmlDoc = new XmlDocument();
                Log.Add(LogTypes.System, User.GetUser(0), -1, "Loading content from disk cache...");
                xmlDoc.Load(UmbracoXmlDiskCacheFileName);
                return xmlDoc;
            }
        }

        private void InitContentDocumentBase(XmlDocument xmlDoc)
        {
            // Create id -1 attribute
            xmlDoc.LoadXml(@"<!DOCTYPE umbraco [ " +
                           "<!ELEMENT nodes ANY>  " +
                           "<!ELEMENT node ANY>  " +
                           "<!ATTLIST node id ID #REQUIRED> ]>" +
                           "<root id=\"-1\"/>");
        }

        /// <summary>
        /// Load content from database
        /// </summary>
        private XmlDocument LoadContentFromDatabase(bool loadDocuments)
        {
            XmlDocument xmlDoc = new XmlDocument();
            InitContentDocumentBase(xmlDoc);

            Log.Add(LogTypes.System, User.GetUser(0), -1, "Loading content from database...");

            Hashtable nodes = new Hashtable();
            Hashtable parents = new Hashtable();
            try
            {
                Log.Add(LogTypes.Debug, User.GetUser(0), -1, "Republishing starting");

                // Esben Carlsen: At some point we really need to put all data access into to a tier of its own.
                string sql = "";
                if (loadDocuments)
                {
                    sql = @"select umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, cmsContentXml.xml from umbracoNode 
inner join cmsContentXml on cmsContentXml.nodeId = umbracoNode.id and umbracoNode.nodeObjectType = @type 
inner join cmsDocument on cmsDocument.nodeId = umbracoNode.id and cmsDocument.published = 1 
order by umbracoNode.level, umbracoNode.sortOrder";
                }
                else
                {
                    sql =
                        @"select umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, cmsContentXml.xml from umbracoNode 
inner join cmsContentXml on cmsContentXml.nodeId = umbracoNode.id and umbracoNode.nodeObjectType = @type
order by umbracoNode.level, umbracoNode.sortOrder";
                }
                lock (_dbReadSyncLock)
                {
                    using (IRecordsReader dr = SqlHelper.ExecuteReader(sql, SqlHelper.CreateParameter("@type", new Guid("C66BA18E-EAF3-4CFF-8A22-41B16D66A972"))))
                    {
                        while (dr.Read())
                        {
                            int currentId = dr.GetInt("id");
                            int parentId = dr.GetInt("parentId");

                            xmlDoc.LoadXml(xmlHelper.SanitizeXmlString(currentId, dr.GetString("xml"), true, " while republishing"));
                            nodes.Add(currentId, xmlDoc.FirstChild);

                            if (parents.ContainsKey(parentId))
                                ((ArrayList)parents[parentId]).Add(currentId);
                            else
                            {
                                ArrayList a = new ArrayList();
                                a.Add(currentId);
                                parents.Add(parentId, a);
                            }
                        }
                    }
                }

                Log.Add(LogTypes.Debug, User.GetUser(0), -1, "Xml Pages loaded");

                // Reset
                InitContentDocumentBase(xmlDoc);

                try
                {
                    GenerateXmlDocument(parents, nodes, -1, xmlDoc.DocumentElement);
                }
                catch (Exception ee)
                {
                    Log.Add(LogTypes.Error, User.GetUser(0), -1,
                            string.Format("Error while generating XmlDocument from database: {0}", ee));
                }
            }
            catch (OutOfMemoryException)
            {
                Log.Add(LogTypes.Error, User.GetUser(0), -1,
                        string.Format("Error Republishin: Out Of Memory. Parents: {0}, Nodes: {1}",
                                      parents.Count, nodes.Count));
            }
            catch (Exception ee)
            {
                Log.Add(LogTypes.Error, User.GetUser(0), -1, string.Format("Error Republishing: {0}", ee));
            }
            finally
            {
                Log.Add(LogTypes.Debug, User.GetUser(0), -1, "Done republishing Xml Index");
            }

            return xmlDoc;
        }

        private void GenerateXmlDocument(Hashtable parents, Hashtable nodes, int parentId, XmlNode parentNode)
        {
            if (parents.ContainsKey(parentId))
            {
                ArrayList children = (ArrayList)parents[parentId];
                foreach (int i in children)
                {
                    XmlNode childNode = (XmlNode)nodes[i];
                    parentNode.AppendChild(childNode);
                    GenerateXmlDocument(parents, nodes, i, childNode);
                }
            }
        }

        /// <summary>
        /// Persist a XmlDocument to the Disk Cache
        /// </summary>
        /// <param name="xmlDoc"></param>
        internal void SaveContentToDisk(XmlDocument xmlDoc)
        {
            lock (_readerWriterSyncLock)
            {
                try
                {
                    Stopwatch stopWatch = Stopwatch.StartNew();

                    ClearDiskCache();
                    xmlDoc.Save(UmbracoXmlDiskCacheFileName);

                    Log.Add(LogTypes.Debug, User.GetUser(0), -1, string.Format("Xml saved in {0}", stopWatch.Elapsed));
                }
                catch (Exception ee)
                {
                    // If for whatever reason something goes wrong here, invalidate disk cache
                    ClearDiskCache();
                    Log.Add(LogTypes.Error, User.GetUser(0), -1, string.Format("Xml wasn't saved: {0}", ee));
                }
            }
        }

        /// <summary>
        /// Persist xml document to disk cache in a background thread
        /// </summary>
        /// <param name="xmlDoc"></param>
        private void SaveContentToDiskAsync(XmlDocument xmlDoc)
        {
            // Save copy of content
            if (UmbracoSettings.CloneXmlCacheOnPublish)
            {
                XmlDocument xmlContentCopy = CloneXmlDoc(xmlDoc);

                ThreadPool.QueueUserWorkItem(
                    delegate { SaveContentToDisk(xmlContentCopy); });

            }
            else
                ThreadPool.QueueUserWorkItem(
                    delegate { SaveContentToDisk(xmlDoc); });
        }

        /// <summary>
        /// Make a copy of a XmlDocument
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <returns></returns>
        private XmlDocument CloneXmlDoc(XmlDocument xmlDoc)
        {
            Log.Add(LogTypes.Debug, -1, "Cloning...");
            // Save copy of content
            XmlDocument xmlCopy = new XmlDocument();
            xmlCopy.LoadXml(xmlDoc.OuterXml);
            Log.Add(LogTypes.Debug, -1, "Cloning ended...");
            return xmlCopy;
        }

        #endregion
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.