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