001/*
002 *  Copyright 2021 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.workspaces.members.observers;
017
018import java.util.HashSet;
019import java.util.List;
020import java.util.Set;
021
022import org.apache.avalon.framework.service.ServiceException;
023import org.apache.avalon.framework.service.ServiceManager;
024import org.apache.commons.collections4.CollectionUtils;
025
026import org.ametys.cms.ObservationConstants;
027import org.ametys.cms.repository.Content;
028import org.ametys.core.observation.Event;
029import org.ametys.core.observation.Observer;
030import org.ametys.plugins.repository.version.VersionableAmetysObject;
031import org.ametys.plugins.userdirectory.observation.AbstractContentObserver;
032import org.ametys.plugins.workspaces.WorkspacesConstants;
033import org.ametys.plugins.workspaces.members.MemberHelper;
034import org.ametys.web.repository.page.Page;
035
036/**
037 * {@link Observer} to invalidate zone item cache of related members when the skills or keywords have changed 
038 *
039 */
040public class InvalidateZoneItemCacheOnMemberModificationObserver extends AbstractContentObserver
041{
042    private MemberHelper _memberHelper;
043
044    @Override
045    public void service(ServiceManager smanager) throws ServiceException
046    {
047        super.service(smanager);
048        _memberHelper = (MemberHelper) smanager.lookup(MemberHelper.ROLE);
049    }
050    
051    public int getPriority(Event event)
052    {
053        // processed just before front-office cache invalidation
054        return MAX_PRIORITY + 3500;
055    }
056    
057    public boolean supports(Event event)
058    {
059        String eventId = event.getId();
060        boolean eventSupported =  eventId.equals(ObservationConstants.EVENT_CONTENT_DELETING)  
061                || eventId.equals(ObservationConstants.EVENT_CONTENT_UNTAG_LIVE) 
062                || eventId.equals(ObservationConstants.EVENT_CONTENT_VALIDATED);
063        
064        if (eventSupported)
065        {
066            Content content = (Content) event.getArguments().get(ObservationConstants.ARGS_CONTENT);
067            return content != null && _contentTypeHelper.isInstanceOf(content, WorkspacesConstants.MEMBER_CONTENT_TYPE_ID);
068        }
069        
070        return false;
071    }
072
073    @Override
074    protected void _internalObserve(Event event, Page rootUsersPage, Content userContent)
075    {
076        try
077        {
078            if (_needCacheInvalidation(event, userContent))
079            {
080                Set<Content> contentsToInvalidate = new HashSet<>();
081                
082                List<Content> relatedMembers = _memberHelper.getRelatedMembers(userContent, Integer.MAX_VALUE);
083                contentsToInvalidate.addAll(relatedMembers);
084                
085                if (userContent instanceof VersionableAmetysObject && !event.getId().equals(ObservationConstants.EVENT_CONTENT_DELETING))
086                {
087                    VersionableAmetysObject versionableContent = (VersionableAmetysObject) userContent;
088                    String[] allRevisions = versionableContent.getAllRevisions();
089                    if (allRevisions.length > 1)
090                    {
091                        String lastRevision = allRevisions[allRevisions.length - 2];
092                        
093                        versionableContent.switchToRevision(lastRevision);
094                        try
095                        {
096                            List<Content> oldRelatedMemmbers = _memberHelper.getRelatedMembers(userContent, Integer.MAX_VALUE);
097                            contentsToInvalidate.addAll(oldRelatedMemmbers);
098                        }
099                        finally
100                        {
101                            versionableContent.switchToRevision(null);
102                        }
103                    }
104                }
105                
106                // Invalidate zoneitem cache for new and old related members, for all workspaces
107                for (Content content : contentsToInvalidate)
108                {
109                    _removeZoneItemCache(rootUsersPage, content, null);
110                }
111            }
112            
113        }
114        catch (Exception e)
115        {
116            getLogger().error("Unable to get the related members for content '{}'. The zoneitem cache has not been invalidated.", userContent.getId(), e);
117        }
118        
119    }
120    
121    /**
122     * Determines if the zoneitem cache invalidation is needed
123     * @param event The event
124     * @param userContent the content
125     * @return true if zoneitem cache invalidation is needed
126     */
127    protected boolean _needCacheInvalidation(Event event, Content userContent)
128    {
129        if (event.getId().equals(ObservationConstants.EVENT_CONTENT_DELETING))
130        {
131            return true;
132        }
133        else
134        {
135            List<String> skills = _memberHelper.getSkills(userContent);
136            List<String> keywords = _memberHelper.getKeywords(userContent);
137            
138            if (userContent instanceof VersionableAmetysObject)
139            {
140                VersionableAmetysObject versionableContent = (VersionableAmetysObject) userContent;
141                String[] allRevisions = versionableContent.getAllRevisions();
142                if (allRevisions.length > 1)
143                {
144                    String lastRevision = allRevisions[allRevisions.length - 2];
145                    
146                    versionableContent.switchToRevision(lastRevision);
147                    try
148                    {
149                        List<String> oldSkills = _memberHelper.getSkills(userContent);
150                        List<String> oldKeywords = _memberHelper.getKeywords(userContent);
151                        
152                        // Need cache invalidation if the skills or keywords have changed
153                        return CollectionUtils.disjunction(skills, oldSkills).size() > 0 || CollectionUtils.disjunction(keywords, oldKeywords).size() > 0;
154                    }
155                    finally
156                    {
157                        versionableContent.switchToRevision(null);
158                    }
159                }
160            }
161            
162            return false;
163        }
164            
165    }
166
167}