001/*
002 *  Copyright 2017 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.odfweb.observation;
017
018import java.util.Map;
019
020import org.apache.avalon.framework.context.Context;
021import org.apache.avalon.framework.context.ContextException;
022import org.apache.avalon.framework.context.Contextualizable;
023import org.apache.avalon.framework.logger.AbstractLogEnabled;
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.avalon.framework.service.Serviceable;
027import org.apache.cocoon.components.ContextHelper;
028import org.apache.cocoon.environment.Request;
029
030import org.ametys.cms.ObservationConstants;
031import org.ametys.cms.repository.Content;
032import org.ametys.core.observation.Event;
033import org.ametys.core.observation.Observer;
034import org.ametys.odf.orgunit.OrgUnit;
035import org.ametys.odf.program.Program;
036import org.ametys.plugins.odfweb.repository.FirstLevelPageFactory;
037import org.ametys.plugins.odfweb.repository.ODFPageCache;
038import org.ametys.plugins.odfweb.repository.OdfPageHandler;
039import org.ametys.plugins.odfweb.repository.OdfPageResolver;
040import org.ametys.plugins.repository.AmetysObjectIterable;
041import org.ametys.plugins.repository.AmetysObjectResolver;
042import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector;
043import org.ametys.plugins.repository.query.expression.Expression;
044import org.ametys.plugins.repository.query.expression.VirtualFactoryExpression;
045import org.ametys.web.WebConstants;
046import org.ametys.web.repository.page.Page;
047import org.ametys.web.repository.page.PageQueryHelper;
048import org.ametys.web.repository.site.Site;
049import org.ametys.web.repository.site.SiteManager;
050import org.ametys.web.repository.sitemap.Sitemap;
051
052/**
053 * Clear ODF caches when page ODF root page has changed
054 *
055 */
056public class ClearODFPageCacheObserver extends AbstractLogEnabled implements Observer, Serviceable, Contextualizable
057{
058    /** The ODF root page handler. */
059    protected OdfPageHandler _odfPageHandler;
060    
061    /** The ODF page cache */
062    protected ODFPageCache _odfPageCache;
063    
064    /** Site manager */
065    protected SiteManager _siteManager;
066    
067    /** Odf page resolver */
068    protected OdfPageResolver _odfPageResolver;
069    
070    /** Ametys object resolver */
071    protected AmetysObjectResolver _resolver;
072    
073    /** Avalon context */
074    protected Context _context;
075    
076    @Override
077    public void service(ServiceManager manager) throws ServiceException
078    {
079        _odfPageHandler = (OdfPageHandler) manager.lookup(OdfPageHandler.ROLE);
080        _odfPageCache = (ODFPageCache) manager.lookup(ODFPageCache.ROLE);
081        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
082        _odfPageResolver = (OdfPageResolver) manager.lookup(OdfPageResolver.ROLE);
083        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
084    }
085    
086    @Override
087    public void contextualize(Context context) throws ContextException
088    {
089        _context = context;
090    }
091
092    @Override
093    public boolean supports(Event event)
094    {
095        Content content = (Content) event.getArguments().get(ObservationConstants.ARGS_CONTENT);
096        return event.getId().equals(org.ametys.web.ObservationConstants.EVENT_PAGE_CHANGED) 
097            || event.getId().equals(org.ametys.web.ObservationConstants.EVENT_SITE_UPDATED)
098            || event.getId().equals(ObservationConstants.EVENT_CONTENT_MODIFIED) && content instanceof OrgUnit/* for handling moved orgUnit */
099            || (event.getId().equals(ObservationConstants.EVENT_CONTENT_VALIDATED) && (content instanceof OrgUnit || content instanceof Program));
100    }
101
102    @Override
103    public int getPriority(Event event)
104    {
105        // Will be processed AFTER live synchronization observers and BEFORE page indexation observer
106        return MAX_PRIORITY + 1100;
107    }
108
109    @Override
110    public void observe(Event event, Map<String, Object> transientVars) throws Exception
111    {
112        Content targetContent = (Content) event.getArguments().get(ObservationConstants.ARGS_CONTENT);
113        Page targetPage = (Page) event.getArguments().get(org.ametys.web.ObservationConstants.ARGS_PAGE);
114        Site targetSite = (Site) event.getArguments().get(org.ametys.web.ObservationConstants.ARGS_SITE);
115        if (targetPage != null)
116        {
117            _clearCache(targetPage);
118        }
119        else if (targetContent instanceof Program)
120        {
121            _clearCache((Program) targetContent);
122        }
123        else if (targetContent instanceof OrgUnit)
124        {
125            _clearCache((OrgUnit) targetContent);
126        }
127        
128        else if (targetSite != null)
129        {
130            _clearCache(targetSite);
131        }
132    }
133    
134    /**
135     * Clear the cache when necessary in case of a page 
136     * @param page The page
137     */
138    protected void _clearCache(Page page)
139    {
140        if (_odfPageHandler.isODFRootPage(page))
141        {
142            // Clear ODF page cache
143            _odfPageCache.clearCache(page);
144        }
145    }
146    
147    /**
148     * Clear the cache when necessary in case of a program 
149     * @param program The program
150     */
151    protected void _clearCache(Program program)
152    {
153        AmetysObjectIterable<Page> rootPages = _getOdfRootPages();
154        
155        for (Page rootPage : rootPages)
156        {
157            _odfPageCache.clearCache(rootPage);
158        }
159    }
160    
161    private AmetysObjectIterable<Page> _getOdfRootPages()
162    {
163        Expression expression = new VirtualFactoryExpression(FirstLevelPageFactory.class.getName());
164        String query = PageQueryHelper.getPageXPathQuery(null, null, null, expression, null);
165        return _resolver.query(query);
166    }
167    
168    /**
169     * Clear the cache when necessary in case of an orgUnit 
170     * @param orgUnit The orgUnit
171     */
172    protected void _clearCache(OrgUnit orgUnit)
173    {
174        Request request = ContextHelper.getRequest(_context);
175
176        // Retrieve current workspace
177        String currentWsp = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
178
179        try
180        {
181            // Use live workspace
182            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, WebConstants.LIVE_WORKSPACE);
183            for (Site site : _siteManager.getSites())
184            {
185                if (_odfPageHandler.hasOdfRootPage(site))
186                {
187                    for (Sitemap sitemap : site.getSitemaps())
188                    {
189                        for (Page page : _odfPageHandler.getOdfRootPages(sitemap.getSiteName(), sitemap.getSitemapName()))
190                        {
191                            // Clear ODF page cache
192                            _odfPageCache.clearCache(page);
193                        }
194                    }
195                }
196            }
197        }
198        finally
199        {
200            // Restore context
201            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWsp);
202        }
203    }
204    
205    /**
206     * Clear the cache when necessary in case of a site 
207     * @param site The site
208     */
209    protected void _clearCache(Site site)
210    {
211        String siteName = site.getName();
212        
213        for (Sitemap sitemap : site.getSitemaps())
214        {
215            for (Page odfRootPage : _odfPageHandler.getOdfRootPages(siteName, sitemap.getSitemapName()))
216            {
217                _odfPageCache.clearCache(odfRootPage);
218            }
219        }
220    }
221}