001/*
002 *  Copyright 2010 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.web.inputdata;
017
018import java.io.InputStream;
019import java.util.HashMap;
020import java.util.Map;
021
022import org.apache.avalon.framework.configuration.Configuration;
023import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
024import org.apache.avalon.framework.context.Context;
025import org.apache.avalon.framework.context.ContextException;
026import org.apache.avalon.framework.context.Contextualizable;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030import org.apache.cocoon.ProcessingException;
031import org.apache.cocoon.components.ContextHelper;
032import org.apache.cocoon.environment.Request;
033import org.xml.sax.ContentHandler;
034import org.xml.sax.SAXException;
035
036import org.ametys.core.util.filereloader.FileReloader;
037import org.ametys.core.util.filereloader.FileReloaderUtils;
038import org.ametys.runtime.plugin.component.AbstractLogEnabled;
039import org.ametys.web.WebConstants;
040import org.ametys.web.pageaccess.RestrictedPagePolicy;
041import org.ametys.web.repository.page.Page;
042import org.ametys.web.repository.site.Site;
043import org.ametys.web.repository.site.SiteManager;
044
045/**
046 * {@link InputData} for SAXing events about the current sitemap.
047 */
048public class SitemapInputData extends AbstractLogEnabled implements InputData, Contextualizable, Serviceable, FileReloader
049{
050    private static final String __INITIAL_DEPTH = "initial-depth";
051    private static final String __DESCENDANT_DEPTH = "descendant-depth";
052    
053    private static final int __DEFAULT_INITIAL_DEPTH = 2;
054    private static final int __DEFAULT_DESCENDANT_DEPTH = 1;
055    
056    private Context _context;
057    private SitemapSaxer _sitemapSaxer;
058    private FileReloaderUtils _fileReloaderUtils;
059    
060    private Map<String, Map<String, Integer>> _sitemapCfgCache = new HashMap<>();
061    private SiteManager _siteManager;
062    
063    @Override
064    public void service(ServiceManager manager) throws ServiceException
065    {
066        _sitemapSaxer = (SitemapSaxer) manager.lookup(SitemapSaxer.ROLE);
067        _fileReloaderUtils = (FileReloaderUtils) manager.lookup(FileReloaderUtils.ROLE);
068        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
069    }
070    
071    @Override
072    public void contextualize(Context context) throws ContextException
073    {
074        _context = context;
075    }
076
077    @Override
078    public boolean isCacheable(Site site, Page page)
079    {
080        return site.getRestrictedPagePolicy() == RestrictedPagePolicy.DISPLAYED;
081    }
082    
083    public boolean shouldBeCached(Site site, Page page)
084    {
085        // Sometimes we return true to #isCacheable because the whole page is cacheable 
086        // but we don't use general cache, so here we always answer yes
087        return false;
088    }
089    
090    @Override
091    public void toSAX(ContentHandler handler) throws SAXException, ProcessingException
092    {
093        Request request = ContextHelper.getRequest(_context);
094        
095        String siteName = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITE_NAME);
096        String sitemapName = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITEMAP_NAME);
097        
098        Page page = (Page) request.getAttribute(WebConstants.REQUEST_ATTR_PAGE);
099        
100        String skinId = _getSkinId();
101        _loadSitemapConfiguration();
102        
103        int initialDepth = _sitemapCfgCache.get(skinId).get(__INITIAL_DEPTH);
104        int descendantDepth = _sitemapCfgCache.get(skinId).get(__DESCENDANT_DEPTH);
105        
106        _sitemapSaxer.toSAX(handler, siteName, sitemapName, page, initialDepth, descendantDepth);
107    }
108    
109    private void _loadSitemapConfiguration()
110    {
111        try
112        {
113            String file = "skin://conf/sitemap.xml";
114            _fileReloaderUtils.updateFile(file, this);
115        }
116        catch (Exception e)
117        {
118            getLogger().error("An error occurred reading the sitemap configuration file {}.", "skin://conf/sitemap.xml", e);
119        }
120    }
121    
122    public String getId(String sourceUrl)
123    {
124        return SitemapInputData.class.getName() + "#" + _getSkinId();
125    }
126    
127    private String _getSkinId()
128    {
129        Request request = ContextHelper.getRequest(_context);
130        
131        String skinId = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SKIN_ID);
132        
133        if (skinId == null)
134        {
135            String siteName = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITE_NAME);
136            Site site = _siteManager.getSite(siteName);
137            return site.getSkinId();
138        }
139        else
140        {
141            return skinId;
142        }
143        
144    }
145    
146    public void updateFile(String sourceUrl, InputStream is) throws Exception
147    {
148        int initialDepth = __DEFAULT_INITIAL_DEPTH;
149        int descendantDepth = __DEFAULT_DESCENDANT_DEPTH;
150        
151        if (is != null)
152        {
153            Configuration cfg = new DefaultConfigurationBuilder().build(is);
154            initialDepth = _parseInt(cfg, __INITIAL_DEPTH, __DEFAULT_INITIAL_DEPTH);
155            descendantDepth = _parseInt(cfg, __DESCENDANT_DEPTH, __DEFAULT_DESCENDANT_DEPTH);
156        }
157        
158        String skinId = _getSkinId();
159        
160        if (!_sitemapCfgCache.containsKey(skinId))
161        {
162            _sitemapCfgCache.put(skinId, new HashMap<>());
163        }
164        
165        Map<String, Integer> skinConf = _sitemapCfgCache.get(skinId);
166        skinConf.put(__INITIAL_DEPTH, initialDepth);
167        skinConf.put(__DESCENDANT_DEPTH, descendantDepth);
168    }
169    
170    private int _parseInt(Configuration cfg, String tagName, int defaultValue)
171    {
172        return cfg.getChild(tagName, true).getValueAsInteger(defaultValue);
173    }
174}