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 @Override 102 public void contextualize(Context context) throws ContextException 103 { 104 _context = context; 105 } 106 107 @Override 108 public boolean isCacheable(Site site, Page page) 109 { 110 return site.getRestrictedPagePolicy() == RestrictedPagePolicy.DISPLAYED; 111 } 112 113 public boolean shouldBeCached(Site site, Page page) 114 { 115 // Sometimes we return true to #isCacheable because the whole page is cacheable 116 // but we don't use general cache, so here we always answer yes 117 return false; 118 } 119 120 @Override 121 public void toSAX(ContentHandler handler) throws SAXException, ProcessingException 122 { 123 Request request = ContextHelper.getRequest(_context); 124 125 String siteName = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITE_NAME); 126 String sitemapName = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITEMAP_NAME); 127 128 Page page = (Page) request.getAttribute(WebConstants.REQUEST_ATTR_PAGE); 129 130 String skinId = _getSkinId(); 131 _loadSitemapConfiguration(!_getCache().hasKey(SitemapKey.of(skinId, __INITIAL_DEPTH))); 132 133 int initialDepth = _getCache().get(SitemapKey.of(skinId, __INITIAL_DEPTH)); 134 int descendantDepth = _getCache().get(SitemapKey.of(skinId, __DESCENDANT_DEPTH)); 135 136 _sitemapSaxer.toSAX(handler, siteName, sitemapName, page, initialDepth, descendantDepth); 137 } 138 139 private void _loadSitemapConfiguration(boolean forceRead) 140 { 141 try 142 { 143 String file = "skin://conf/sitemap.xml"; 144 _fileReloaderUtils.updateFile(file, forceRead, this); 145 } 146 catch (Exception e) 147 { 148 getLogger().error("An error occurred reading the sitemap configuration file {}.", "skin://conf/sitemap.xml", e); 149 } 150 } 151 152 public String getId(String sourceUrl) 153 { 154 return SitemapInputData.class.getName() + "#" + _getSkinId(); 155 } 156 157 private String _getSkinId() 158 { 159 Request request = ContextHelper.getRequest(_context); 160 161 String skinId = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SKIN_ID); 162 163 if (skinId == null) 164 { 165 String siteName = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITE_NAME); 166 Site site = _siteManager.getSite(siteName); 167 return site.getSkinId(); 168 } 169 else 170 { 171 return skinId; 172 } 173 } 174 175 public void updateFile(String sourceUrl, Source source, InputStream is) throws Exception 176 { 177 int initialDepth = __DEFAULT_INITIAL_DEPTH; 178 int descendantDepth = __DEFAULT_DESCENDANT_DEPTH; 179 180 if (is != null) 181 { 182 Configuration cfg = new DefaultConfigurationBuilder().build(is); 183 initialDepth = _parseInt(cfg, __INITIAL_DEPTH, __DEFAULT_INITIAL_DEPTH); 184 descendantDepth = _parseInt(cfg, __DESCENDANT_DEPTH, __DEFAULT_DESCENDANT_DEPTH); 185 } 186 187 String skinId = _getSkinId(); 188 _getCache().put(SitemapKey.of(skinId, __INITIAL_DEPTH), initialDepth); 189 _getCache().put(SitemapKey.of(skinId, __DESCENDANT_DEPTH), descendantDepth); 190 } 191 192 private int _parseInt(Configuration cfg, String tagName, int defaultValue) 193 { 194 return cfg.getChild(tagName, true).getValueAsInteger(defaultValue); 195 } 196 197 private Cache<SitemapKey, Integer> _getCache() 198 { 199 return _cacheManager.get(_CACHE_ID); 200 } 201}