001/*
002 *  Copyright 2011 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 */
016
017package org.ametys.web.cache;
018
019import java.util.Map;
020import java.util.regex.Matcher;
021import java.util.regex.Pattern;
022
023import org.ametys.core.observation.Event;
024import org.ametys.core.observation.Observer;
025import org.ametys.core.util.FilenameUtils;
026import org.ametys.core.util.URIUtils;
027import org.ametys.plugins.explorer.ObservationConstants;
028import org.ametys.runtime.plugin.component.AbstractLogEnabled;
029
030/**
031 * {@link Observer} for listening resource changes in order to invalidate cache on front-office.
032 */
033public class InvalidateCacheOnResourceUpdateObserver extends AbstractLogEnabled implements Observer
034{
035    private static final Pattern __RESOURCE_PATTERN = Pattern.compile("^.*/ametys-internal:sites/([^/]+)/ametys-internal:resources/(.*)$");
036    private static final Pattern __ROOT_SITE_RESOURCE_PATTERN = Pattern.compile("^.*/ametys-internal:sites/[^/]+/[^/]+/([^/]+)/ametys-internal:resources/(.*)$");
037    private static final Pattern __SHARED_RESOURCE_PATTERN = Pattern.compile("^.*/ametys:plugins/web-explorer/shared-resources/(.*)$");
038    
039    @Override
040    public int getPriority(Event event)
041    {
042        return Observer.MAX_PRIORITY;
043    }
044    
045    @Override
046    public boolean supports(Event event)
047    {
048        String eventType = event.getId();
049        return eventType.equals(ObservationConstants.EVENT_RESOURCE_CREATED)
050                || eventType.equals(ObservationConstants.EVENT_RESOURCE_UPDATED)
051                || eventType.equals(ObservationConstants.EVENT_RESOURCE_DELETED)
052                || eventType.equals(ObservationConstants.EVENT_RESOURCE_MOVED)
053                || eventType.equals(ObservationConstants.EVENT_RESOURCE_RENAMED)
054                || eventType.equals(ObservationConstants.EVENT_COLLECTION_CREATED)
055                || eventType.equals(ObservationConstants.EVENT_COLLECTION_DELETED)
056                || eventType.equals(ObservationConstants.EVENT_COLLECTION_RENAMED)
057                || eventType.equals(ObservationConstants.EVENT_COLLECTION_MOVED);
058    }
059    
060    @Override
061    public void observe(Event event, Map<String, Object> transientVars) throws Exception
062    {
063        String eventType = event.getId();
064        
065        try
066        {
067            Map<String, Object> args = event.getArguments();
068            if (eventType.equals(ObservationConstants.EVENT_RESOURCE_CREATED))
069            {
070                // Multiple resources may have been created, look for to parent path
071                String path = (String) args.get(ObservationConstants.ARGS_PARENT_PATH);
072                _invalidate(path);
073            }
074            else if (eventType.equals(ObservationConstants.EVENT_RESOURCE_UPDATED) || eventType.equals(ObservationConstants.EVENT_RESOURCE_DELETED) || eventType.equals(ObservationConstants.EVENT_COLLECTION_DELETED))
075            {
076                String path = (String) args.get(ObservationConstants.ARGS_PATH);
077                _invalidate(path);
078            }
079            else if (eventType.equals(ObservationConstants.EVENT_RESOURCE_RENAMED) || eventType.equals(ObservationConstants.EVENT_COLLECTION_RENAMED) || eventType.equals(ObservationConstants.EVENT_RESOURCE_MOVED)  || eventType.equals(ObservationConstants.EVENT_COLLECTION_MOVED))
080            {
081                String oldPath = (String) args.get("object.old.path");
082                _invalidate(oldPath);
083            }
084        }
085        catch (Exception e)
086        {
087            getLogger().error("Exception while trying to handle explorer event + " + event, e);
088        }
089        
090    }
091    
092    private void _invalidate(String path) throws Exception
093    {
094        Matcher matcher1 = __RESOURCE_PATTERN.matcher(path);
095        Matcher matcher2 = __ROOT_SITE_RESOURCE_PATTERN.matcher(path);
096        Matcher sharedMatcher = __SHARED_RESOURCE_PATTERN.matcher(path);
097        
098        String site = null;
099        String pathInSite = null;
100        if (matcher1.matches())
101        {
102            site = matcher1.group(1);
103            pathInSite = matcher1.group(2);
104        }
105        else if (matcher2.matches())
106        {
107            site = matcher2.group(1);
108            pathInSite = matcher2.group(2);
109        }
110        else if (sharedMatcher.matches())
111        {
112            pathInSite = sharedMatcher.group(1);
113        }
114        else
115        {
116            getLogger().debug("{} does not match attempted pattern for resources of explorer", path);
117            return;
118        }
119        
120        // encode it twice, as it is stored in encoded form on FO side
121        String encodedPath = URIUtils.encodePath(FilenameUtils.encodePath(pathInSite));
122        
123        if (site != null)
124        {
125            CacheHelper.testWS("/_invalidate-page/" + site + "/_resource/" + encodedPath, getLogger());
126            CacheHelper.testWS("/_invalidate-images/" + site + "/_resource/" + encodedPath, getLogger());
127        }
128        else
129        {
130            CacheHelper.testWS("/_invalidate-shared-resources/_shared-resource/" + encodedPath, getLogger());
131            CacheHelper.testWS("/_invalidate-shared-resources-images/_shared-resource/" + encodedPath, getLogger());
132        }
133    }
134}