using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using Umbraco.Core.ObjectResolution; namespace Umbraco.Web.PublishedCache.XmlPublishedCache { class RoutesCache { private ConcurrentDictionary _routes; private ConcurrentDictionary _nodeIds; /// /// Initializes a new instance of the class. /// public RoutesCache() : this(true) { } /// /// Initializes a new instance of the class. /// internal RoutesCache(bool bindToEvents) { Clear(); if (bindToEvents) { Resolution.Frozen += ResolutionFrozen; } } /// /// Once resolution is frozen, then we can bind to the events that we require /// /// /// private void ResolutionFrozen(object s, EventArgs args) { // content - whenever the entire XML cache is rebuilt (from disk cache or from database) // we must clear the cache entirely global::umbraco.content.AfterRefreshContent += (sender, e) => Clear(); // document - whenever a document is updated in, or removed from, the XML cache // we must clear the cache - at the moment, we clear the entire cache global::umbraco.content.AfterUpdateDocumentCache += (sender, e) => Clear(); global::umbraco.content.AfterClearDocumentCache += (sender, e) => Clear(); // fixme - should refactor once content events are refactored // the content class needs to be refactored - at the moment // content.XmlContentInternal setter does not trigger any event // content.UpdateDocumentCache(List Documents) does not trigger any event // content.RefreshContentFromDatabaseAsync triggers AfterRefresh _while_ refreshing // etc... // in addition some events do not make sense... we trigger Publish when moving // a node, which we should not (the node is moved, not published...) etc. } /// /// Used ONLY for unit tests /// /// internal IDictionary GetCachedRoutes() { return _routes; } /// /// Used ONLY for unit tests /// /// internal IDictionary GetCachedIds() { return _nodeIds; } #region Public /// /// Stores a route for a node. /// /// The node identified. /// The route. public void Store(int nodeId, string route) { _routes.AddOrUpdate(nodeId, i => route, (i, s) => route); _nodeIds.AddOrUpdate(route, i => nodeId, (i, s) => nodeId); } /// /// Gets a route for a node. /// /// The node identifier. /// The route for the node, else null. public string GetRoute(int nodeId) { string val; _routes.TryGetValue(nodeId, out val); return val; } /// /// Gets a node for a route. /// /// The route. /// The node identified for the route, else zero. public int GetNodeId(string route) { int val; _nodeIds.TryGetValue(route, out val); return val; } /// /// Clears the route for a node. /// /// The node identifier. public void ClearNode(int nodeId) { if (!_routes.ContainsKey(nodeId)) return; string key; if (!_routes.TryGetValue(nodeId, out key)) return; int val; _nodeIds.TryRemove(key, out val); string val2; _routes.TryRemove(nodeId, out val2); } /// /// Clears all routes. /// public void Clear() { _routes = new ConcurrentDictionary(); _nodeIds = new ConcurrentDictionary(); } #endregion } }