001/*
002 *  Copyright 2016 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.flipbook;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Map;
021import java.util.regex.Matcher;
022import java.util.regex.Pattern;
023
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.avalon.framework.service.Serviceable;
027
028import org.ametys.core.observation.Event;
029import org.ametys.core.observation.Observer;
030import org.ametys.core.util.URLEncoder;
031import org.ametys.plugins.explorer.ObservationConstants;
032import org.ametys.plugins.explorer.resources.Resource;
033import org.ametys.plugins.repository.AmetysObjectResolver;
034import org.ametys.runtime.plugin.component.AbstractLogEnabled;
035import org.ametys.runtime.plugin.component.PluginAware;
036import org.ametys.web.cache.CacheHelper;
037import org.ametys.web.repository.site.SiteManager;
038
039/**
040 * {@link Observer} for listening resource changes in order to invalidate flipbook cache on front-office.
041 */
042public class InvalidateFlipbookCacheOnResourceUpdateObserver extends AbstractLogEnabled implements Observer, PluginAware, Serviceable
043{
044    private static final Pattern __RESOURCE_PATTERN = Pattern.compile("^.*/ametys-internal:sites/([^/]+)/ametys-internal:resources/(.*)$");
045    private static final Pattern __ROOT_SITE_RESOURCE_PATTERN = Pattern.compile("^.*/ametys-internal:sites/[^/]+/[^/]+/([^/]+)/ametys-internal:resources/(.*)$");
046    private static final Pattern __SHARED_RESOURCE_PATTERN = Pattern.compile("^.*/ametys:plugins/web-explorer/shared-resources/(.*)$");
047    private static final Pattern __ATTACHMENTS_PATTERN = Pattern.compile("^.*/ametys-internal:sites/([^/]+)/ametys-internal:contents/([^/]+)/ametys-internal:attachments/(.*)$");
048    
049    private String _pluginName;
050    private SiteManager _siteManager;
051    private AmetysObjectResolver _resolver;
052    
053    @Override
054    public void setPluginInfo(String pluginName, String featureName, String id)
055    {
056        _pluginName = pluginName;
057    }
058    
059    public void service(ServiceManager smanager) throws ServiceException
060    {
061        _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE);
062        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
063    }
064    
065    @Override
066    public boolean supports(Event event)
067    {
068        return event.getId().equals(ObservationConstants.EVENT_RESOURCE_UPDATED);
069    }
070
071    @Override
072    public int getPriority(Event event)
073    {
074        return Observer.MIN_PRIORITY;
075    }
076
077    @Override
078    public void observe(Event event, Map<String, Object> transientVars) throws Exception
079    {
080        try
081        {
082            Map<String, Object> args = event.getArguments();
083            String path = (String) args.get(ObservationConstants.ARGS_PATH);
084            String resourceId = (String) args.get(ObservationConstants.ARGS_ID);
085            _invalidate(path, resourceId);
086        }
087        catch (Exception e)
088        {
089            getLogger().error("Exception while trying to handle explorer event + " + event, e);
090        }
091    }
092    
093    private void _invalidate(String path, String resourceId) throws Exception
094    {
095        Matcher matcher1 = __RESOURCE_PATTERN.matcher(path);
096        Matcher matcher2 = __ROOT_SITE_RESOURCE_PATTERN.matcher(path);
097        Matcher sharedMatcher = __SHARED_RESOURCE_PATTERN.matcher(path);
098        Matcher attachmentMatcher = __ATTACHMENTS_PATTERN.matcher(path);
099        
100        String site = null;
101        String prefix = null;
102        String bookPathInSite = null;
103        String pagePathInSite = null;
104        String resourcePrefix = "resource";
105        if (matcher1.matches())
106        {
107            site = matcher1.group(1);
108            bookPathInSite = URLEncoder.encodePath(matcher1.group(2));
109            pagePathInSite = bookPathInSite;
110            prefix = "resource-flipbook";
111        }
112        else if (matcher2.matches())
113        {
114            site = matcher2.group(1);
115            bookPathInSite = URLEncoder.encodePath(matcher2.group(2));
116            pagePathInSite = bookPathInSite;
117            prefix = "resource-flipbook";
118        }
119        else if (sharedMatcher.matches())
120        {
121            //FIXME ISSUE .... EXPLORER-392
122            bookPathInSite = URLEncoder.encodePath(sharedMatcher.group(1));
123            pagePathInSite = bookPathInSite;
124            prefix = "shared-resource-flipbook";
125        }
126        else if (attachmentMatcher.matches())
127        {
128            site = attachmentMatcher.group(1);
129            prefix = "attachments-flipbook";
130            resourcePrefix = "contents";
131            
132            bookPathInSite = URLEncoder.encodePath(attachmentMatcher.group(2) + "/" + attachmentMatcher.group(3));
133            
134            Resource resource = _resolver.resolveById(resourceId);
135            bookPathInSite += "/_contents" + URLEncoder.encodePath(resource.getPath()).replaceAll(":", "%3A");
136            
137            pagePathInSite = URLEncoder.encodePath(attachmentMatcher.group(2) + "/attachments/" + attachmentMatcher.group(3));
138        }
139        else
140        {
141            getLogger().warn(path + " does not match attempted pattern for resources");
142            return;
143        }
144        
145        Collection<String> siteNames = new ArrayList<>();
146        
147        if (site != null)
148        {
149            // Only one site is concerned
150            siteNames.add(site);
151        }
152        else
153        {
154            // Clear cache for all sites
155            siteNames = _siteManager.getSiteNames();
156        }
157        
158        for (String siteName : siteNames)
159        {
160            String fullPath = "_plugins/" + _pluginName + "/" + siteName
161                    + "/_" + prefix
162                    + "/" + bookPathInSite
163                    + "/book.html";
164         
165            String encodedPath = URLEncoder.encodePath(fullPath);
166            CacheHelper.testWS("/_invalidate-page/" + siteName + "/" + encodedPath, getLogger());
167            
168            fullPath = "_plugins/" + _pluginName + "/" + siteName
169                    + "/" + resourcePrefix
170                    + "/" + pagePathInSite
171                    + "/pages";
172            
173            encodedPath = URLEncoder.encodePath(fullPath);
174            CacheHelper.testWS("/_invalidate-page/" + siteName + "/" + encodedPath, getLogger());
175        }
176    }
177}