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