From 87c904cc969d69bc067eea5e82da6ed2fb46dca6 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 4 Apr 2013 21:57:41 +0600 Subject: [PATCH] Fixes: #U4-2044, #U4-2048 --- src/Umbraco.Core/Cache/CacheKeys.cs | 3 ++ .../Cache/ApplicationCacheRefresher.cs | 43 +++++++++++++++++ .../Cache/CacheRefresherEventHandler.cs | 40 +++++++++++++++- src/Umbraco.Web/Cache/DistributedCache.cs | 2 + .../Cache/DistributedCacheExtensions.cs | 14 ++++++ .../Cache/UserTypeCacheRefresher.cs | 43 +++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 2 + src/umbraco.businesslogic/Application.cs | 47 ++++++++++++------- src/umbraco.businesslogic/ApplicationTree.cs | 42 +++++++++++++++-- .../businesslogic/web/StyleSheet.cs | 8 ++-- 10 files changed, 218 insertions(+), 26 deletions(-) create mode 100644 src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs create mode 100644 src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs index 5b31a4f315..1c89d7662f 100644 --- a/src/Umbraco.Core/Cache/CacheKeys.cs +++ b/src/Umbraco.Core/Cache/CacheKeys.cs @@ -6,6 +6,9 @@ namespace Umbraco.Core.Cache /// public static class CacheKeys { + public const string ApplicationTreeCacheKey = "ApplicationTreeCache"; + public const string ApplicationsCacheKey = "ApplicationCache"; + public const string UserTypeCacheKey = "UserTypeCache"; public const string ContentItemCacheKey = "contentItem"; diff --git a/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs new file mode 100644 index 0000000000..a9e52fbb2f --- /dev/null +++ b/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs @@ -0,0 +1,43 @@ +using System; +using Umbraco.Core; +using Umbraco.Core.Cache; + +namespace Umbraco.Web.Cache +{ + /// + /// Handles Application cache invalidation/refreshing + /// + public sealed class ApplicationCacheRefresher : CacheRefresherBase + { + protected override ApplicationCacheRefresher Instance + { + get { return this; } + } + + public override Guid UniqueIdentifier + { + get { return Guid.Parse(DistributedCache.ApplicationCacheRefresherId); } + } + + public override string Name + { + get { return "Applications cache refresher"; } + } + + public override void RefreshAll() + { + ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + } + + public override void Refresh(int id) + { + Remove(id); + } + + public override void Remove(int id) + { + ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs index 6176446088..025748cf13 100644 --- a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs +++ b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs @@ -21,7 +21,16 @@ namespace Umbraco.Web.Cache public class CacheRefresherEventHandler : ApplicationEventHandler { protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) - { + { + //bind to application tree events + ApplicationTree.Deleted += ApplicationTreeDeleted; + ApplicationTree.Updated += ApplicationTreeUpdated; + ApplicationTree.New += ApplicationTreeNew; + + //bind to application events + Application.Deleted += ApplicationDeleted; + Application.New += ApplicationNew; + //bind to user type events UserType.Deleted += UserTypeDeleted; UserType.New += UserTypeNew; @@ -116,6 +125,35 @@ namespace Umbraco.Web.Cache MediaService.Trashing += MediaServiceTrashing; } + #region ApplicationTree event handlers + static void ApplicationTreeNew(ApplicationTree sender, System.EventArgs e) + { + DistributedCache.Instance.RefreshAllApplicationTreeCache(); + } + + static void ApplicationTreeUpdated(ApplicationTree sender, System.EventArgs e) + { + DistributedCache.Instance.RefreshAllApplicationTreeCache(); + } + + static void ApplicationTreeDeleted(ApplicationTree sender, System.EventArgs e) + { + DistributedCache.Instance.RefreshAllApplicationTreeCache(); + } + #endregion + + #region Application event handlers + static void ApplicationNew(Application sender, System.EventArgs e) + { + DistributedCache.Instance.RefreshAllApplicationCache(); + } + + static void ApplicationDeleted(Application sender, System.EventArgs e) + { + DistributedCache.Instance.RefreshAllApplicationCache(); + } + #endregion + #region UserType event handlers static void UserTypeUpdated(UserType sender, System.EventArgs e) { diff --git a/src/Umbraco.Web/Cache/DistributedCache.cs b/src/Umbraco.Web/Cache/DistributedCache.cs index ffc43c1a73..a0ce50d4c7 100644 --- a/src/Umbraco.Web/Cache/DistributedCache.cs +++ b/src/Umbraco.Web/Cache/DistributedCache.cs @@ -35,6 +35,8 @@ namespace Umbraco.Web.Cache #region Public constants/Ids + public const string ApplicationTreeCacheRefresherId = "0AC6C028-9860-4EA4-958D-14D39F45886E"; + public const string ApplicationCacheRefresherId = "B15F34A1-BC1D-4F8B-8369-3222728AB4C8"; public const string TemplateRefresherId = "DD12B6A0-14B9-46e8-8800-C154F74047C8"; public const string PageCacheRefresherId = "27AB3022-3DFA-47b6-9119-5945BC88FD66"; public const string MemberCacheRefresherId = "E285DF34-ACDC-4226-AE32-C0CB5CF388DA"; diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index 48f8bf7bdd..f9ae3b8d6e 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -13,6 +13,20 @@ namespace Umbraco.Web.Cache /// internal static class DistributedCacheExtensions { + #region Application tree cache + public static void RefreshAllApplicationTreeCache(this DistributedCache dc) + { + dc.RefreshAll(new Guid(DistributedCache.ApplicationTreeCacheRefresherId)); + } + #endregion + + #region Application cache + public static void RefreshAllApplicationCache(this DistributedCache dc) + { + dc.RefreshAll(new Guid(DistributedCache.ApplicationCacheRefresherId)); + } + #endregion + #region User type cache public static void RemoveUserTypeCache(this DistributedCache dc, int userTypeId) { diff --git a/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs new file mode 100644 index 0000000000..d4ec8a0d60 --- /dev/null +++ b/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs @@ -0,0 +1,43 @@ +using System; +using Umbraco.Core; +using Umbraco.Core.Cache; + +namespace Umbraco.Web.Cache +{ + /// + /// Handles User type cache invalidation/refreshing + /// + public sealed class UserTypeCacheRefresher : CacheRefresherBase + { + protected override UserTypeCacheRefresher Instance + { + get { return this; } + } + + public override Guid UniqueIdentifier + { + get { return Guid.Parse(DistributedCache.UserTypeCacheRefresherId); } + } + + public override string Name + { + get { return "User type cache refresher"; } + } + + public override void RefreshAll() + { + ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.UserTypeCacheKey); + } + + public override void Refresh(int id) + { + Remove(id); + } + + public override void Remove(int id) + { + ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.UserTypeCacheKey); + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 4cf8f78146..39f1b28bb7 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -263,6 +263,8 @@ + + diff --git a/src/umbraco.businesslogic/Application.cs b/src/umbraco.businesslogic/Application.cs index 034f302895..efa7131196 100644 --- a/src/umbraco.businesslogic/Application.cs +++ b/src/umbraco.businesslogic/Application.cs @@ -6,6 +6,8 @@ using System.Linq; using System.Web; using System.Xml.Linq; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; using umbraco.DataLayer; @@ -21,7 +23,6 @@ namespace umbraco.BusinessLogic { private static ISqlHelper _sqlHelper; - private const string CacheKey = "ApplicationCache"; internal const string AppConfigFileName = "applications.config"; private static string _appConfig; private static readonly object Locker = new object(); @@ -45,8 +46,6 @@ namespace umbraco.BusinessLogic set { _appConfig = value; } } - //private static List _testApps; - /// /// The cache storage for all applications /// @@ -55,7 +54,7 @@ namespace umbraco.BusinessLogic get { return ApplicationContext.Current.ApplicationCache.GetCacheItem( - CacheKey, + CacheKeys.ApplicationsCacheKey, () => { ////used for unit tests @@ -98,15 +97,6 @@ namespace umbraco.BusinessLogic } } - ///// - ///// THIS IS USED ONLY FOR UNIT TESTS! - ///// - ///// - //internal static void SetTestApps(List testApps) - //{ - // _testApps = testApps; - //} - /// /// Gets the SQL helper. /// @@ -144,8 +134,6 @@ namespace umbraco.BusinessLogic } } - - /// /// Initializes a new instance of the class. /// @@ -237,6 +225,9 @@ namespace umbraco.BusinessLogic new XAttribute("icon", icon), new XAttribute("sortOrder", sortOrder))); }, true); + + //raise event + OnNew(new Application(name, alias, icon, sortOrder), new EventArgs()); } } @@ -269,6 +260,9 @@ namespace umbraco.BusinessLogic { doc.Root.Elements("add").Where(x => x.Attribute("alias") != null && x.Attribute("alias").Value == this.alias).Remove(); }, true); + + //raise event + OnDeleted(this, new EventArgs()); } /// @@ -308,11 +302,30 @@ namespace umbraco.BusinessLogic doc.Save(AppConfigFilePath); - //remove the cache so it gets re-read - ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKey); + //remove the cache so it gets re-read ... SD: I'm leaving this here even though it + // is taken care of by events as well, I think unit tests may rely on it being cleared here. + ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); } } } } + + internal static event TypedEventHandler Deleted; + private static void OnDeleted(Application app, EventArgs args) + { + if (Deleted != null) + { + Deleted(app, args); + } + } + + internal static event TypedEventHandler New; + private static void OnNew(Application app, EventArgs args) + { + if (New != null) + { + New(app, args); + } + } } } diff --git a/src/umbraco.businesslogic/ApplicationTree.cs b/src/umbraco.businesslogic/ApplicationTree.cs index 27c7a2d04f..968b3b86cb 100644 --- a/src/umbraco.businesslogic/ApplicationTree.cs +++ b/src/umbraco.businesslogic/ApplicationTree.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Web; using System.Xml.Linq; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Events; using Umbraco.Core.IO; using umbraco.DataLayer; @@ -18,7 +20,6 @@ namespace umbraco.BusinessLogic public class ApplicationTree { - private const string CacheKey = "ApplicationTreeCache"; internal const string TreeConfigFileName = "trees.config"; private static string _treeConfig; private static readonly object Locker = new object(); @@ -50,7 +51,7 @@ namespace umbraco.BusinessLogic get { return ApplicationContext.Current.ApplicationCache.GetCacheItem( - CacheKey, + CacheKeys.ApplicationTreeCacheKey, () => { var list = new List(); @@ -244,6 +245,8 @@ namespace umbraco.BusinessLogic new XAttribute("action", string.IsNullOrEmpty(action) ? "" : action))); } }, true); + + OnNew(new ApplicationTree(silent, initialize, sortOrder, applicationAlias, alias, title, iconClosed, iconOpened, assemblyName, type, action), new EventArgs()); } /// @@ -274,6 +277,7 @@ namespace umbraco.BusinessLogic }, true); + OnUpdated(this, new EventArgs()); } /// @@ -289,6 +293,8 @@ namespace umbraco.BusinessLogic doc.Root.Elements("add").Where(x => x.Attribute("application") != null && x.Attribute("application").Value == this.ApplicationAlias && x.Attribute("alias") != null && x.Attribute("alias").Value == this.Alias).Remove(); }, true); + + OnDeleted(this, new EventArgs()); } @@ -359,11 +365,39 @@ namespace umbraco.BusinessLogic doc.Save(TreeConfigFilePath); - //remove the cache now that it has changed - ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKey); + //remove the cache now that it has changed SD: I'm leaving this here even though it + // is taken care of by events as well, I think unit tests may rely on it being cleared here. + ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); } } } } + + internal static event TypedEventHandler Deleted; + private static void OnDeleted(ApplicationTree app, EventArgs args) + { + if (Deleted != null) + { + Deleted(app, args); + } + } + + internal static event TypedEventHandler New; + private static void OnNew(ApplicationTree app, EventArgs args) + { + if (New != null) + { + New(app, args); + } + } + + internal static event TypedEventHandler Updated; + private static void OnUpdated(ApplicationTree app, EventArgs args) + { + if (Updated != null) + { + Updated(app, args); + } + } } } diff --git a/src/umbraco.cms/businesslogic/web/StyleSheet.cs b/src/umbraco.cms/businesslogic/web/StyleSheet.cs index c73b3a337f..d9de01dcb5 100644 --- a/src/umbraco.cms/businesslogic/web/StyleSheet.cs +++ b/src/umbraco.cms/businesslogic/web/StyleSheet.cs @@ -238,9 +238,7 @@ namespace umbraco.cms.businesslogic.web return retval; } - - - + public StylesheetProperty AddProperty(string Alias, BusinessLogic.User u) { return StylesheetProperty.MakeNew(Alias, this, u); @@ -254,8 +252,10 @@ namespace umbraco.cms.businesslogic.web if (!e.Cancel) { File.Delete(IOHelper.MapPath(String.Format("{0}/{1}.css", SystemDirectories.Css, this.Text))); - foreach (StylesheetProperty p in this.Properties) + foreach (var p in Properties.Where(p => p != null)) + { p.delete(); + } SqlHelper.ExecuteNonQuery("delete from cmsStylesheet where nodeId = @nodeId", SqlHelper.CreateParameter("@nodeId", this.Id)); base.delete();