diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs index f37d20bd19..e2ea37cee9 100644 --- a/src/Umbraco.Core/Cache/CacheKeys.cs +++ b/src/Umbraco.Core/Cache/CacheKeys.cs @@ -26,5 +26,7 @@ namespace Umbraco.Core.Cache public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache"; + public const string LanguageCacheKey = "UmbracoLanguageCache"; + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs index 1b4ff703d6..4d6215bf10 100644 --- a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs +++ b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs @@ -30,6 +30,15 @@ namespace Umbraco.Web.Cache content.AfterUpdateDocumentCache += ContentAfterUpdateDocumentCache; content.AfterClearDocumentCache += ContentAfterClearDocumentCache; + //Bind to language events + //NOTE: we need to bind to legacy and new API events currently: http://issues.umbraco.org/issue/U4-1979 + + global::umbraco.cms.businesslogic.language.Language.AfterDelete += LanguageAfterDelete; + global::umbraco.cms.businesslogic.language.Language.New += LanguageNew; + global::umbraco.cms.businesslogic.language.Language.AfterSave += LanguageAfterSave; + LocalizationService.SavedLanguage += LocalizationServiceSavedLanguage; + LocalizationService.DeletedLanguage += LocalizationServiceDeletedLanguage; + //Bind to content type events ContentTypeService.SavedContentType += ContentTypeServiceSavedContentType; @@ -68,6 +77,56 @@ namespace Umbraco.Web.Cache MediaService.Trashing += MediaServiceTrashing; } + /// + /// Fires when a langauge is deleted + /// + /// + /// + static void LocalizationServiceDeletedLanguage(ILocalizationService sender, Core.Events.DeleteEventArgs e) + { + e.DeletedEntities.ForEach(x => DistributedCache.Instance.RemoveLanguageCache(x)); + } + + /// + /// Fires when a langauge is saved + /// + /// + /// + static void LocalizationServiceSavedLanguage(ILocalizationService sender, Core.Events.SaveEventArgs e) + { + e.SavedEntities.ForEach(x => DistributedCache.Instance.RefreshLanguageCache(x)); + } + + /// + /// Fires when a langauge is saved + /// + /// + /// + static void LanguageAfterSave(global::umbraco.cms.businesslogic.language.Language sender, SaveEventArgs e) + { + DistributedCache.Instance.RefreshLanguageCache(sender); + } + + /// + /// Fires when a langauge is created + /// + /// + /// + static void LanguageNew(global::umbraco.cms.businesslogic.language.Language sender, NewEventArgs e) + { + DistributedCache.Instance.RefreshLanguageCache(sender); + } + + /// + /// Fires when a langauge is deleted + /// + /// + /// + static void LanguageAfterDelete(global::umbraco.cms.businesslogic.language.Language sender, DeleteEventArgs e) + { + DistributedCache.Instance.RemoveLanguageCache(sender); + } + /// /// Fires when a media type is deleted /// diff --git a/src/Umbraco.Web/Cache/DistributedCache.cs b/src/Umbraco.Web/Cache/DistributedCache.cs index d919510b9f..a34ef5e48a 100644 --- a/src/Umbraco.Web/Cache/DistributedCache.cs +++ b/src/Umbraco.Web/Cache/DistributedCache.cs @@ -42,6 +42,7 @@ namespace Umbraco.Web.Cache public const string MacroCacheRefresherId = "7B1E683C-5F34-43dd-803D-9699EA1E98CA"; public const string UserCacheRefresherId = "E057AF6D-2EE6-41F4-8045-3694010F0AA6"; public const string ContentTypeCacheRefresherId = "6902E22C-9C10-483C-91F3-66B7CAE9E2F5"; + public const string LanguageCacheRefresherId = "3E0F95D8-0BE5-44B8-8394-2B8750B62654"; #endregion diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index 53ab7adf27..85a66f814e 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -278,6 +278,42 @@ namespace Umbraco.Web.Cache } #endregion + #region Language Cache + + public static void RefreshLanguageCache(this DistributedCache dc, ILanguage language) + { + if (language != null) + { + dc.Refresh(new Guid(DistributedCache.LanguageCacheRefresherId), language.Id); + } + } + + public static void RemoveLanguageCache(this DistributedCache dc, ILanguage language) + { + if (language != null) + { + dc.Remove(new Guid(DistributedCache.LanguageCacheRefresherId), language.Id); + } + } + + public static void RefreshLanguageCache(this DistributedCache dc, global::umbraco.cms.businesslogic.language.Language language) + { + if (language != null) + { + dc.Refresh(new Guid(DistributedCache.LanguageCacheRefresherId), language.id); + } + } + + public static void RemoveLanguageCache(this DistributedCache dc, global::umbraco.cms.businesslogic.language.Language language) + { + if (language != null) + { + dc.Remove(new Guid(DistributedCache.LanguageCacheRefresherId), language.id); + } + } + + #endregion + public static void ClearXsltCacheOnCurrentServer(this DistributedCache dc) { if (UmbracoSettings.UmbracoLibraryCacheDuration > 0) diff --git a/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs b/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs new file mode 100644 index 0000000000..59214b7258 --- /dev/null +++ b/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs @@ -0,0 +1,39 @@ +using System; +using Umbraco.Core; +using Umbraco.Core.Cache; + +namespace Umbraco.Web.Cache +{ + /// + /// A cache refresher to ensure language cache is refreshed when languages change + /// + public sealed class LanguageCacheRefresher : CacheRefresherBase + { + protected override LanguageCacheRefresher Instance + { + get { return this; } + } + + public override Guid UniqueIdentifier + { + get { return new Guid(DistributedCache.LanguageCacheRefresherId); } + } + + public override string Name + { + get { return "Language cache refresher"; } + } + + public override void Refresh(int id) + { + ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.LanguageCacheKey); + base.Refresh(id); + } + + public override void Remove(int id) + { + ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.LanguageCacheKey); + base.Remove(id); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 08cd74b77b..a59ec5c5c0 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -267,6 +267,7 @@ + diff --git a/src/umbraco.cms/businesslogic/language/Language.cs b/src/umbraco.cms/businesslogic/language/Language.cs index fd1da001ab..91aaa03f9b 100644 --- a/src/umbraco.cms/businesslogic/language/Language.cs +++ b/src/umbraco.cms/businesslogic/language/Language.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Data; using System.Globalization; using System.Xml; +using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Logging; using umbraco.cms.businesslogic.cache; using umbraco.DataLayer; @@ -31,12 +33,7 @@ namespace umbraco.cms.businesslogic.language #endregion #region Constants and static members - - private static object getLanguageSyncLock = new object(); - private static readonly string UmbracoLanguageCacheKey = "UmbracoLanguageCache"; - - private const int DefaultLanguageId = 1; - + /// /// Gets the SQL helper. /// @@ -48,8 +45,6 @@ namespace umbraco.cms.businesslogic.language protected internal const string m_SQLOptimizedGetAll = @"select * from umbracoLanguage"; - private static readonly object m_Locker = new object(); - #endregion #region Constructors @@ -93,19 +88,12 @@ namespace umbraco.cms.businesslogic.language SqlHelper.ExecuteNonQuery( "insert into umbracoLanguage (languageISOCode) values (@CultureCode)", SqlHelper.CreateParameter("@CultureCode", CultureCode)); - - InvalidateCache(); - + NewEventArgs e = new NewEventArgs(); GetByCultureCode(CultureCode).OnNew(e); } } - private static void InvalidateCache() - { - Cache.ClearCacheItem(UmbracoLanguageCacheKey); - } - /// /// Method for accessing all installed languagess /// @@ -127,23 +115,24 @@ namespace umbraco.cms.businesslogic.language /// public static IEnumerable GetAllAsList() { - return Cache.GetCacheItem>(UmbracoLanguageCacheKey, getLanguageSyncLock, TimeSpan.FromMinutes(60), - delegate - { - var languages = new List(); - - using (IRecordsReader dr = SqlHelper.ExecuteReader(m_SQLOptimizedGetAll)) + return ApplicationContext.Current.ApplicationCache.GetCacheItem>( + CacheKeys.LanguageCacheKey, + TimeSpan.FromMinutes(60), + () => { - while (dr.Read()) + var languages = new List(); + using (var dr = SqlHelper.ExecuteReader(m_SQLOptimizedGetAll)) { - //create the ContentType object without setting up - Language ct = new Language(); - ct.PopulateFromReader(dr); - languages.Add(ct); + while (dr.Read()) + { + //create the ContentType object without setting up + var ct = new Language(); + ct.PopulateFromReader(dr); + languages.Add(ct); + } } - } - return languages; - }); + return languages; + }); } /// @@ -252,7 +241,6 @@ namespace umbraco.cms.businesslogic.language if (!e.Cancel) { - InvalidateCache(); FireAfterSave(e); } } @@ -287,8 +275,6 @@ namespace umbraco.cms.businesslogic.language //remove the dictionary entries first Item.RemoveByLanguage(id); - InvalidateCache(); - SqlHelper.ExecuteNonQuery("delete from umbracoLanguage where id = @id", SqlHelper.CreateParameter("@id", id));