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 CmsXmlSitemapGenerator createSitemapGenerator(String className, String folderRootPath) throws CmsException {
089
090        if (CmsStringUtil.isEmptyOrWhitespaceOnly(className)) {
091            className = (String)(OpenCms.getRuntimeProperty(PARAM_DEFAULT_SITEMAP_GENERATOR));
092        }
093        if (CmsStringUtil.isEmptyOrWhitespaceOnly(className)) {
094            className = CmsXmlSitemapGenerator.class.getName();
095        }
096        try {
097            Class<? extends CmsXmlSitemapGenerator> generatorClass = Class.forName(className).asSubclass(
098                CmsXmlSitemapGenerator.class);
099            Constructor<? extends CmsXmlSitemapGenerator> constructor = generatorClass.getConstructor(String.class);
100            CmsXmlSitemapGenerator generator = constructor.newInstance(folderRootPath);
101            return generator;
102        } catch (Exception e) {
103            LOG.error(
104                "Could not create configured sitemap generator " + className + ", using the default class instead",
105                e);
106            return new CmsXmlSitemapGenerator(folderRootPath);
107        }
108    }
109
110    /**
111     * Writes the XML sitemap to the response.<p>
112     *
113     * @throws Exception if something goes wrong
114     */
115    public void renderXmlSitemap() throws Exception {
116
117        CmsObject cms = getCmsObject();
118        String baseFolderRootPath = CmsFileUtil.removeTrailingSeparator(
119            CmsResource.getParentFolder(cms.getRequestContext().addSiteRoot(cms.getRequestContext().getUri())));
120        CmsXmlSitemapGenerator xmlSitemapGenerator = createSitemapGenerator(
121            m_configuration.getSitemapGeneratorClassName(),
122            baseFolderRootPath);
123        xmlSitemapGenerator.setComputeContainerPageDates(m_configuration.shouldComputeContainerPageModificationDates());
124        CmsPathIncludeExcludeSet inexcludeSet = xmlSitemapGenerator.getIncludeExcludeSet();
125        for (String include : m_configuration.getIncludes()) {
126            inexcludeSet.addInclude(include);
127        }
128        for (String exclude : m_configuration.getExcludes()) {
129            inexcludeSet.addExclude(exclude);
130        }
131        xmlSitemapGenerator.setServerUrl(m_configuration.getServerUrl());
132        String xmlSitemap = xmlSitemapGenerator.renderSitemap();
133        getResponse().getWriter().print(xmlSitemap);
134    }
135
136    /**
137     * Displays either the generated sitemap.xml or the generated robots.txt, depending on the configuration.<p>
138     *
139     * @throws Exception if something goes wrong
140     */
141    public void run() throws Exception {
142
143        CmsObject cms = getCmsObject();
144        String seoFilePath = cms.getRequestContext().getUri();
145        CmsResource seoFile = cms.readResource(seoFilePath);
146        m_configuration = new CmsXmlSeoConfiguration();
147        m_configuration.load(cms, seoFile);
148        String mode = m_configuration.getMode();
149        if (mode.equals(CmsXmlSeoConfiguration.MODE_ROBOTS_TXT)) {
150            showRobotsTxt();
151        } else {
152            renderXmlSitemap();
153        }
154    }
155
156    /**
157     * Renders the robots.txt data containing the sitemaps automatically.<p>
158     *
159     * @throws Exception if something goes wrong
160     */
161    private void showRobotsTxt() throws Exception {
162
163        CmsObject cms = getCmsObject();
164        StringBuffer buffer = new StringBuffer();
165        I_CmsResourceType seoFileType = OpenCms.getResourceManager().getResourceType(
166            CmsXmlSeoConfiguration.SEO_FILE_TYPE);
167        List<CmsResource> seoFiles = cms.readResources(
168            "/",
169            CmsResourceFilter.DEFAULT_FILES.addRequireVisible().addRequireType(seoFileType));
170        for (CmsResource seoFile : seoFiles) {
171            try {
172                CmsXmlSeoConfiguration seoFileConfig = new CmsXmlSeoConfiguration();
173                seoFileConfig.load(cms, seoFile);
174                if (seoFileConfig.isXmlSitemapMode()) {
175                    buffer.append(
176                        "Sitemap: "
177                            + CmsXmlSitemapGenerator.replaceServerUri(
178                                OpenCms.getLinkManager().getOnlineLink(cms, cms.getSitePath(seoFile)),
179                                m_configuration.getServerUrl()));
180                    buffer.append("\n");
181                }
182            } catch (CmsException e) {
183                LOG.error("Error while generating robots.txt : " + e.getLocalizedMessage(), e);
184            }
185        }
186        buffer.append("\n");
187        buffer.append(m_configuration.getRobotsTxtText());
188        buffer.append("\n");
189        getResponse().getWriter().print(buffer.toString());
190    }
191
192}