001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (C) Alkacon Software (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.site.xmlsitemap; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsResource; 032import org.opencms.file.CmsResourceFilter; 033import org.opencms.file.types.I_CmsResourceType; 034import org.opencms.jsp.CmsJspActionElement; 035import org.opencms.main.CmsException; 036import org.opencms.main.CmsLog; 037import org.opencms.main.OpenCms; 038import org.opencms.util.CmsFileUtil; 039import org.opencms.util.CmsStringUtil; 040 041import java.lang.reflect.Constructor; 042import java.util.List; 043 044import javax.servlet.http.HttpServletRequest; 045import javax.servlet.http.HttpServletResponse; 046import javax.servlet.jsp.PageContext; 047 048import org.apache.commons.logging.Log; 049 050/** 051 * Action element class for displaying the XML sitemap from a JSP.<p> 052 */ 053public class CmsXmlSitemapActionElement extends CmsJspActionElement { 054 055 /** The logger instance for this class. */ 056 private static final Log LOG = CmsLog.getLog(CmsXmlSitemapActionElement.class); 057 058 /** Runtime property name for the default sitemap generator class. */ 059 private static final String PARAM_DEFAULT_SITEMAP_GENERATOR = "sitemap.generator"; 060 061 /** The configuration bean. */ 062 protected CmsXmlSeoConfiguration m_configuration; 063 064 /** 065 * Constructor, with parameters. 066 * 067 * @param pageContext the JSP page context object 068 * @param request the JSP request 069 * @param response the JSP response 070 */ 071 public CmsXmlSitemapActionElement( 072 PageContext pageContext, 073 HttpServletRequest request, 074 HttpServletResponse response) { 075 076 super(pageContext, request, response); 077 } 078 079 /** 080 * Creates an XML sitemap generator instance given a class name and the root path for the sitemap.<p> 081 * 082 * @param className the class name of the sitemap generator (may be null for the default 083 * @param folderRootPath the root path of the start folder for the sitemap 084 * @return the sitemap generator instance 085 * 086 * @throws CmsException if something goes wrong 087 */ 088 public static CmsXmlSitemapGenerator createSitemapGenerator(String className, String folderRootPath) 089 throws CmsException { 090 091 if (CmsStringUtil.isEmptyOrWhitespaceOnly(className)) { 092 className = (String)(OpenCms.getRuntimeProperty(PARAM_DEFAULT_SITEMAP_GENERATOR)); 093 } 094 if (CmsStringUtil.isEmptyOrWhitespaceOnly(className)) { 095 className = CmsXmlSitemapGenerator.class.getName(); 096 } 097 try { 098 Class<? extends CmsXmlSitemapGenerator> generatorClass = Class.forName(className).asSubclass( 099 CmsXmlSitemapGenerator.class); 100 Constructor<? extends CmsXmlSitemapGenerator> constructor = generatorClass.getConstructor(String.class); 101 CmsXmlSitemapGenerator generator = constructor.newInstance(folderRootPath); 102 return generator; 103 } catch (Exception e) { 104 LOG.error( 105 "Could not create configured sitemap generator " + className + ", using the default class instead", 106 e); 107 return new CmsXmlSitemapGenerator(folderRootPath); 108 } 109 } 110 111 /** 112 * Constructs an XML sitemap generator given an XML sitemap configuration file.<p> 113 * 114 * @param seoFileRes the sitemap XML file 115 * @param config the parsed configuration 116 * 117 * @return the sitemap generator, or null if the given configuration is not an XML sitemap configuration 118 * 119 * @throws CmsException if something goes wrong 120 */ 121 public static CmsXmlSitemapGenerator prepareSitemapGenerator(CmsResource seoFileRes, CmsXmlSeoConfiguration config) 122 throws CmsException { 123 124 if (config.getMode().equals(CmsXmlSeoConfiguration.MODE_XML_SITEMAP)) { 125 String baseFolderRootPath = CmsFileUtil.removeTrailingSeparator( 126 CmsResource.getParentFolder(seoFileRes.getRootPath())); 127 CmsXmlSitemapGenerator xmlSitemapGenerator = createSitemapGenerator( 128 config.getSitemapGeneratorClassName(), 129 baseFolderRootPath); 130 xmlSitemapGenerator.setComputeContainerPageDates(config.shouldComputeContainerPageModificationDates()); 131 CmsPathIncludeExcludeSet inexcludeSet = xmlSitemapGenerator.getIncludeExcludeSet(); 132 for (String include : config.getIncludes()) { 133 inexcludeSet.addInclude(include); 134 } 135 for (String exclude : config.getExcludes()) { 136 inexcludeSet.addExclude(exclude); 137 } 138 xmlSitemapGenerator.setServerUrl(config.getServerUrl()); 139 return xmlSitemapGenerator; 140 } 141 return null; 142 } 143 144 /** 145 * Displays either the generated sitemap.xml or the generated robots.txt, depending on the configuration.<p> 146 * 147 * @throws Exception if something goes wrong 148 */ 149 public void run() throws Exception { 150 151 CmsObject cms = getCmsObject(); 152 String seoFilePath = cms.getRequestContext().getUri(); 153 CmsResource seoFile = cms.readResource(seoFilePath); 154 m_configuration = new CmsXmlSeoConfiguration(); 155 m_configuration.load(cms, seoFile); 156 String mode = m_configuration.getMode(); 157 if (mode.equals(CmsXmlSeoConfiguration.MODE_ROBOTS_TXT)) { 158 showRobotsTxt(); 159 } else { 160 boolean updateCache = Boolean.parseBoolean(getRequest().getParameter("updateCache")); 161 String value = ""; 162 if (updateCache && m_configuration.usesCache()) { 163 // update request, and caching is configured -> update the cache 164 CmsXmlSitemapGenerator generator = prepareSitemapGenerator(seoFile, m_configuration); 165 value = generator.renderSitemap(); 166 CmsXmlSitemapCache.INSTANCE.put(seoFile.getRootPath(), value); 167 } else if (!updateCache && m_configuration.usesCache()) { 168 // normal request, and caching is configured -> look in the cache first, and if not found, calculate sitemap and store it in cache 169 String cachedValue = CmsXmlSitemapCache.INSTANCE.get(seoFile.getRootPath()); 170 if (cachedValue != null) { 171 value = cachedValue; 172 } else { 173 CmsXmlSitemapGenerator generator = prepareSitemapGenerator(seoFile, m_configuration); 174 value = generator.renderSitemap(); 175 CmsXmlSitemapCache.INSTANCE.put(seoFile.getRootPath(), value); 176 } 177 } else if (!updateCache && !m_configuration.usesCache()) { 178 // normal request, caching is not configured -> always generate a fresh sitemap 179 CmsXmlSitemapGenerator generator = prepareSitemapGenerator(seoFile, m_configuration); 180 value = generator.renderSitemap(); 181 } else if (updateCache && !m_configuration.usesCache()) { 182 // update request with no caching configured -> ignore 183 } 184 getResponse().getWriter().print(value); 185 } 186 187 } 188 189 /** 190 * Renders the robots.txt data containing the sitemaps automatically.<p> 191 * 192 * @throws Exception if something goes wrong 193 */ 194 private void showRobotsTxt() throws Exception { 195 196 CmsObject cms = getCmsObject(); 197 StringBuffer buffer = new StringBuffer(); 198 I_CmsResourceType seoFileType = OpenCms.getResourceManager().getResourceType( 199 CmsXmlSeoConfiguration.SEO_FILE_TYPE); 200 List<CmsResource> seoFiles = cms.readResources( 201 "/", 202 CmsResourceFilter.DEFAULT_FILES.addRequireVisible().addRequireType(seoFileType)); 203 for (CmsResource seoFile : seoFiles) { 204 try { 205 if (seoFile.getName().contains("test")) { 206 continue; 207 } 208 CmsXmlSeoConfiguration seoFileConfig = new CmsXmlSeoConfiguration(); 209 seoFileConfig.load(cms, seoFile); 210 if (seoFileConfig.isXmlSitemapMode()) { 211 buffer.append( 212 "Sitemap: " 213 + CmsXmlSitemapGenerator.replaceServerUri( 214 OpenCms.getLinkManager().getOnlineLink(cms, cms.getSitePath(seoFile)), 215 m_configuration.getServerUrl())); 216 buffer.append("\n"); 217 } 218 } catch (CmsException e) { 219 LOG.error("Error while generating robots.txt : " + e.getLocalizedMessage(), e); 220 } 221 } 222 buffer.append("\n"); 223 buffer.append(m_configuration.getRobotsTxtText()); 224 buffer.append("\n"); 225 getResponse().getWriter().print(buffer.toString()); 226 } 227 228}