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