org.opencms.site.xmlsitemap.CmsDetailPageDuplicateEliminatingSitemapGenerator.java Source code

Java tutorial

Introduction

Here is the source code for org.opencms.site.xmlsitemap.CmsDetailPageDuplicateEliminatingSitemapGenerator.java

Source

/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.site.xmlsitemap;

import org.opencms.ade.configuration.CmsADEConfigData.DetailInfo;
import org.opencms.file.CmsProperty;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.types.I_CmsResourceType;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
import org.opencms.main.OpenCms;
import org.opencms.util.CmsFileUtil;
import org.opencms.util.CmsPathMap;
import org.opencms.util.CmsStringUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import org.apache.commons.logging.Log;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;

/**
 * Sitemap generator class which tries to eliminate duplicate detail pages for the same content and locale.<p>
 *
 * In principle, any detail page for a type somewhere in the system could be used to display contents anywhere
 * else in the system. This sitemap generator, instead of generating all detail page URLs that could possibly be generated,
 * instead tries to find only the best candidate URL for each content / locale combination.
 */
public class CmsDetailPageDuplicateEliminatingSitemapGenerator extends CmsXmlSitemapGenerator {

    /** The logger instance for this class. */
    private static final Log LOG = CmsLog.getLog(CmsDetailPageDuplicateEliminatingSitemapGenerator.class);

    /** The detail page information. */
    protected List<DetailInfo> m_detailInfos = new ArrayList<DetailInfo>();

    /** Multimap of detail infos with the detail page as key. */
    private Multimap<String, DetailInfo> m_detailInfosByPage;

    /** Cache for path maps containing the content resources. */
    private HashMap<String, CmsPathMap<CmsResource>> m_pathMapsByType = Maps.newHashMap();

    /**
     * Constructor.<p>
     *
     * @param sitemapPath the sitemap path
     * @throws CmsException if something goes wrong
     */
    public CmsDetailPageDuplicateEliminatingSitemapGenerator(String sitemapPath) throws CmsException {
        super(sitemapPath);
        List<DetailInfo> rawDetailInfo = OpenCms.getADEManager().getDetailInfo(m_guestCms);
        List<DetailInfo> filteredDetailInfo = Lists.newArrayList();
        for (DetailInfo item : rawDetailInfo) {
            String path = item.getFolderPath();
            if (OpenCms.getSiteManager().startsWithShared(path) || CmsStringUtil.isPrefixPath(m_siteRoot, path)) {
                filteredDetailInfo.add(item);
            } else {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Filtered detail info: " + item);
                }
            }
        }
        m_detailInfos = filteredDetailInfo;

    }

    /**
     * @see org.opencms.site.xmlsitemap.CmsXmlSitemapGenerator#generateSitemapBeans()
     */
    @Override
    public List<CmsXmlSitemapUrlBean> generateSitemapBeans() throws CmsException {

        List<CmsXmlSitemapUrlBean> parentResult = super.generateSitemapBeans();
        List<CmsXmlSitemapUrlBean> result = Lists.newArrayList();
        Multimap<String, CmsXmlSitemapUrlBean> detailPageBeans = ArrayListMultimap.create();

        // We want to eliminate duplicate detail pages for the same detail content and locale,
        // so first we group the XML sitemap beans belonging to detail pages by their locale/content combination,
        // and then we sort each group by the sitemap configuration where the detail page is coming from,
        // and then only take the last element in each group.

        for (CmsXmlSitemapUrlBean urlBean : parentResult) {
            if (urlBean.getDetailPageResource() == null) {
                result.add(urlBean);
            } else {
                String localeKey = urlBean.getOriginalResource().getStructureId() + "_" + urlBean.getLocale();
                detailPageBeans.put(localeKey, urlBean);
            }
        }
        Comparator<CmsXmlSitemapUrlBean> pathComparator = new Comparator<CmsXmlSitemapUrlBean>() {

            public int compare(CmsXmlSitemapUrlBean urlbean1, CmsXmlSitemapUrlBean urlbean2) {

                String subsite1 = urlbean1.getSubsite();
                if (subsite1 == null) {
                    subsite1 = "";
                }
                String subsite2 = urlbean2.getSubsite();
                if (subsite2 == null) {
                    subsite2 = "";
                }
                return subsite1.compareTo(subsite2);
            }
        };
        for (String key : detailPageBeans.keySet()) {
            result.add(Collections.max(detailPageBeans.get(key), pathComparator));
        }
        return result;
    }

    /**
     * @see org.opencms.site.xmlsitemap.CmsXmlSitemapGenerator#addDetailLinks(org.opencms.file.CmsResource, java.util.Locale)
     */
    @Override
    protected void addDetailLinks(CmsResource containerPage, Locale locale) throws CmsException {

        Collection<DetailInfo> detailInfos = getDetailInfosForPage(containerPage);
        for (DetailInfo info : detailInfos) {
            List<CmsResource> contents = getContents(info.getFolderPath(), info.getType());
            for (CmsResource detailRes : contents) {
                List<CmsProperty> detailProps = m_guestCms.readPropertyObjects(detailRes, true);
                String detailLink = getDetailLink(containerPage, detailRes, locale);
                detailLink = CmsFileUtil.removeTrailingSeparator(detailLink);
                CmsXmlSitemapUrlBean detailUrlBean = new CmsXmlSitemapUrlBean(replaceServerUri(detailLink),
                        detailRes.getDateLastModified(), getChangeFrequency(detailProps), getPriority(detailProps));
                detailUrlBean.setLocale(locale);
                detailUrlBean.setOriginalResource(detailRes);
                detailUrlBean.setDetailPageResource(containerPage);
                detailUrlBean.setSubsite(info.getBasePath());
                addResult(detailUrlBean, 2);
            }
        }
    }

    /**
     * Gets the contents for the given folder path and type name.<p>
     *
     * @param folderPath the content folder path
     * @param type the type name
     * @return the list of contents
     *
     * @throws CmsException if something goes wrong
     */
    private List<CmsResource> getContents(String folderPath, String type) throws CmsException {

        CmsPathMap<CmsResource> pathMap = getPathMapForType(type);
        return pathMap.getChildValues(folderPath);
    }

    /**
     * Gets the detail information for the given container page.<p>
     *
     * @param containerPage the container page
     * @return the detail information
     */
    private Collection<DetailInfo> getDetailInfosForPage(CmsResource containerPage) {

        if (m_detailInfosByPage == null) {
            m_detailInfosByPage = ArrayListMultimap.create();
            for (DetailInfo detailInfo : m_detailInfos) {
                m_detailInfosByPage.put(detailInfo.getDetailPageInfo().getUri(), detailInfo);
            }
        }
        String folderPath = CmsResource.getParentFolder(containerPage.getRootPath());
        Collection<DetailInfo> result = m_detailInfosByPage.get(containerPage.getRootPath());
        if (result.isEmpty()) {
            result = m_detailInfosByPage.get(folderPath);
        }
        return result;
    }

    /**
     * Gets the path map containing the contents for the given type.<p>
     *
     * @param typeName the type name
     * @return the path map with the content resources
     *
     * @throws CmsException if something goes wrong
     */
    private CmsPathMap<CmsResource> getPathMapForType(String typeName) throws CmsException {

        if (!m_pathMapsByType.containsKey(typeName)) {
            CmsPathMap<CmsResource> pathMap = readPathMapForType(
                    OpenCms.getResourceManager().getResourceType(typeName));
            m_pathMapsByType.put(typeName, pathMap);
        }
        return m_pathMapsByType.get(typeName);
    }

    /**
     * Reads the contents of a given type and stores them in a path map.<p>
     *
     * @param type the type for which to read the contents
     * @return the path map containing the contents
     */
    private CmsPathMap<CmsResource> readPathMapForType(I_CmsResourceType type) {

        List<CmsResource> result = new ArrayList<CmsResource>();
        CmsResourceFilter filter = CmsResourceFilter.DEFAULT_FILES.addRequireType(type);
        try {
            List<CmsResource> siteFiles = m_guestCms.readResources(m_siteRoot, filter, true);
            result.addAll(siteFiles);
        } catch (CmsException e) {
            LOG.error("XML sitemap generator error: " + e.getLocalizedMessage(), e);
        }
        String shared = CmsFileUtil.removeTrailingSeparator(OpenCms.getSiteManager().getSharedFolder());
        if (shared != null) {
            try {
                List<CmsResource> sharedFiles = m_guestCms.readResources(shared, filter, true);
                result.addAll(sharedFiles);
            } catch (CmsException e) {
                LOG.error("XML sitemap generator error: " + e.getLocalizedMessage(), e);
            }
        }
        CmsPathMap<CmsResource> resultMap = new CmsPathMap<CmsResource>();
        for (CmsResource resource : result) {
            resultMap.add(resource.getRootPath(), resource);
        }
        return resultMap;
    }

}