// Copyright (c) Umbraco. // See LICENSE for more details. using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Services.Changes; using Umbraco.Cms.Core.Services.Implement; using Umbraco.Cms.Infrastructure.Services.Notifications; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Cache { /// /// Default implementation. /// public partial class DistributedCacheBinder : INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler, INotificationHandler { private List _unbinders; private void Bind(Action binder, Action unbinder) { // bind now binder(); // and register unbinder for later, if needed _unbinders?.Add(unbinder); } /// public void UnbindEvents() { if (_unbinders == null) throw new NotSupportedException(); foreach (var unbinder in _unbinders) unbinder(); _unbinders = null; } /// public void BindEvents(bool supportUnbinding = false) { if (supportUnbinding) _unbinders = new List(); _logger.LogInformation("Initializing Umbraco internal event handlers for cache refreshing."); // bind to content type events Bind(() => ContentTypeService.Changed += ContentTypeService_Changed, () => ContentTypeService.Changed -= ContentTypeService_Changed); Bind(() => MediaTypeService.Changed += MediaTypeService_Changed, () => MediaTypeService.Changed -= MediaTypeService_Changed); Bind(() => MemberTypeService.Changed += MemberTypeService_Changed, () => MemberTypeService.Changed -= MemberTypeService_Changed); // bind to media events - handles all media changes Bind(() => MediaService.TreeChanged += MediaService_TreeChanged, () => MediaService.TreeChanged -= MediaService_TreeChanged); // bind to content events Bind(() => ContentService.TreeChanged += ContentService_TreeChanged,// handles all content changes () => ContentService.TreeChanged -= ContentService_TreeChanged); // TreeChanged should also deal with this //Bind(() => ContentService.SavedBlueprint += ContentService_SavedBlueprint, // () => ContentService.SavedBlueprint -= ContentService_SavedBlueprint); //Bind(() => ContentService.DeletedBlueprint += ContentService_DeletedBlueprint, // () => ContentService.DeletedBlueprint -= ContentService_DeletedBlueprint); } #region PublicAccessService public void Handle(PublicAccessEntrySavedNotification notification) { _distributedCache.RefreshPublicAccess(); } public void Handle(PublicAccessEntryDeletedNotification notification) { _distributedCache.RefreshPublicAccess(); } #endregion #region ContentService /// /// Handles cache refreshing for when content is copied /// /// /// /// /// When an entity is copied new permissions may be assigned to it based on it's parent, if that is the /// case then we need to clear all user permissions cache. /// private void ContentService_Copied(IContentService sender, CopyEventArgs e) { } private void ContentService_TreeChanged(IContentService sender, TreeChange.EventArgs args) { _distributedCache.RefreshContentCache(args.Changes.ToArray()); } //private void ContentService_SavedBlueprint(IContentService sender, SaveEventArgs e) //{ // _distributedCache.RefreshUnpublishedPageCache(e.SavedEntities.ToArray()); //} //private void ContentService_DeletedBlueprint(IContentService sender, DeleteEventArgs e) //{ // _distributedCache.RemoveUnpublishedPageCache(e.DeletedEntities.ToArray()); //} #endregion #region LocalizationService / Dictionary public void Handle(DictionaryItemSavedNotification notification) { foreach (IDictionaryItem entity in notification.SavedEntities) { _distributedCache.RefreshDictionaryCache(entity.Id); } } public void Handle(DictionaryItemDeletedNotification notification) { foreach (IDictionaryItem entity in notification.DeletedEntities) { _distributedCache.RemoveDictionaryCache(entity.Id); } } #endregion #region DataTypeService public void Handle(DataTypeSavedNotification notification) { foreach (IDataType entity in notification.SavedEntities) { _distributedCache.RefreshDataTypeCache(entity); } } public void Handle(DataTypeDeletedNotification notification) { foreach (IDataType entity in notification.DeletedEntities) { _distributedCache.RemoveDataTypeCache(entity); } } #endregion #region DomainService public void Handle(DomainSavedNotification notification) { foreach (IDomain entity in notification.SavedEntities) { _distributedCache.RefreshDomainCache(entity); } } public void Handle(DomainDeletedNotification notification) { foreach (IDomain entity in notification.DeletedEntities) { _distributedCache.RemoveDomainCache(entity); } } #endregion #region LocalizationService / Language /// /// Fires when a language is deleted /// /// public void Handle(LanguageDeletedNotification notification) { foreach (ILanguage entity in notification.DeletedEntities) { _distributedCache.RemoveLanguageCache(entity); } } /// /// Fires when a language is saved /// /// public void Handle(LanguageSavedNotification notification) { foreach (ILanguage entity in notification.SavedEntities) { _distributedCache.RefreshLanguageCache(entity); } } #endregion #region Content|Media|MemberTypeService private void ContentTypeService_Changed(IContentTypeService sender, ContentTypeChange.EventArgs args) { _distributedCache.RefreshContentTypeCache(args.Changes.ToArray()); } private void MediaTypeService_Changed(IMediaTypeService sender, ContentTypeChange.EventArgs args) { _distributedCache.RefreshContentTypeCache(args.Changes.ToArray()); } private void MemberTypeService_Changed(IMemberTypeService sender, ContentTypeChange.EventArgs args) { _distributedCache.RefreshContentTypeCache(args.Changes.ToArray()); } // TODO: our weird events handling wants this for now private void ContentTypeService_Saved(IContentTypeService sender, SaveEventArgs args) { } private void MediaTypeService_Saved(IMediaTypeService sender, SaveEventArgs args) { } private void MemberTypeService_Saved(IMemberTypeService sender, SaveEventArgs args) { } private void ContentTypeService_Deleted(IContentTypeService sender, DeleteEventArgs args) { } private void MediaTypeService_Deleted(IMediaTypeService sender, DeleteEventArgs args) { } private void MemberTypeService_Deleted(IMemberTypeService sender, DeleteEventArgs args) { } #endregion #region UserService public void Handle(UserSavedNotification notification) { foreach (IUser entity in notification.SavedEntities) { _distributedCache.RefreshUserCache(entity.Id); } } public void Handle(UserDeletedNotification notification) { foreach (IUser entity in notification.DeletedEntities) { _distributedCache.RemoveUserCache(entity.Id); } } public void Handle(UserGroupWithUsersSavedNotification notification) { foreach (UserGroupWithUsers entity in notification.SavedEntities) { _distributedCache.RefreshUserGroupCache(entity.UserGroup.Id); } } public void Handle(UserGroupDeletedNotification notification) { foreach (IUserGroup entity in notification.DeletedEntities) { _distributedCache.RemoveUserGroupCache(entity.Id); } } #endregion #region FileService /// /// Removes cache for template /// /// public void Handle(TemplateDeletedNotification notification) { foreach (ITemplate entity in notification.DeletedEntities) { _distributedCache.RemoveTemplateCache(entity.Id); } } /// /// Refresh cache for template /// /// public void Handle(TemplateSavedNotification notification) { foreach (ITemplate entity in notification.SavedEntities) { _distributedCache.RefreshTemplateCache(entity.Id); } } #endregion #region MacroService public void Handle(MacroDeletedNotification notification) { foreach (IMacro entity in notification.DeletedEntities) { _distributedCache.RemoveMacroCache(entity); } } public void Handle(MacroSavedNotification notification) { foreach (IMacro entity in notification.SavedEntities) { _distributedCache.RefreshMacroCache(entity); } } #endregion #region MediaService private void MediaService_TreeChanged(IMediaService sender, TreeChange.EventArgs args) { _distributedCache.RefreshMediaCache(args.Changes.ToArray()); } #endregion #region MemberService public void Handle(MemberDeletedNotification notification) { _distributedCache.RemoveMemberCache(notification.DeletedEntities.ToArray()); } public void Handle(MemberSavedNotification notification) { _distributedCache.RefreshMemberCache(notification.SavedEntities.ToArray()); } #endregion #region MemberGroupService /// /// Fires when a member group is deleted /// /// public void Handle(MemberGroupDeletedNotification notification) { foreach (IMemberGroup entity in notification.DeletedEntities) { _distributedCache.RemoveMemberGroupCache(entity.Id); } } /// /// Fires when a member group is saved /// /// public void Handle(MemberGroupSavedNotification notification) { foreach (IMemberGroup entity in notification.SavedEntities) { _distributedCache.RemoveMemberGroupCache(entity.Id); } } #endregion #region RelationType public void Handle(RelationTypeSavedNotification notification) { DistributedCache dc = _distributedCache; foreach (IRelationType entity in notification.SavedEntities) { dc.RefreshRelationTypeCache(entity.Id); } } public void Handle(RelationTypeDeletedNotification notification) { DistributedCache dc = _distributedCache; foreach (IRelationType entity in notification.DeletedEntities) { dc.RemoveRelationTypeCache(entity.Id); } } #endregion } }