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.util.CmsFileUtil;
031import org.opencms.util.CmsStringUtil;
032
033import java.util.ArrayList;
034import java.util.Collections;
035import java.util.HashSet;
036import java.util.Iterator;
037import java.util.List;
038import java.util.Set;
039import java.util.TreeSet;
040
041/**
042 * A helper class used for calculating which paths need to be included or excluded from the XML sitemap generation.<p>
043 *
044 */
045public class CmsPathIncludeExcludeSet {
046
047    /** The set of all paths of includes or excludes. */
048    private Set<String> m_allPaths = new TreeSet<String>();
049
050    /** The set of excluded paths. */
051    private Set<String> m_excludes = new HashSet<String>();
052
053    /** The set of included paths. */
054    private Set<String> m_includes = new HashSet<String>();
055
056    /**
057     * Adds an excluded path.<p>
058     *
059     * @param exclude the path to add
060     */
061    public void addExclude(String exclude) {
062
063        exclude = normalizePath(exclude);
064        m_excludes.add(exclude);
065        m_allPaths.add(exclude);
066    }
067
068    /**
069     * Adds an included path.<p>
070     *
071     * @param include the path to add
072     */
073    public void addInclude(String include) {
074
075        include = normalizePath(include);
076        m_includes.add(include);
077        m_allPaths.add(include);
078    }
079
080    /**
081     * Gets the root include paths, i.e. those include paths which don't have an ancestor path which is also an include path.<p>
082     *
083     * @return the list of root include paths
084     */
085    public Set<String> getIncludeRoots() {
086
087        List<String> pathList = new ArrayList<String>(m_includes);
088        Set<String> includeRoots = new HashSet<String>();
089        Collections.sort(pathList);
090        while (!pathList.isEmpty()) {
091            Iterator<String> iterator = pathList.iterator();
092            String firstPath = iterator.next();
093            includeRoots.add(firstPath);
094            iterator.remove();
095            while (iterator.hasNext()) {
096                String currentPath = iterator.next();
097                if (CmsStringUtil.isPrefixPath(firstPath, currentPath)) {
098                    iterator.remove();
099                }
100            }
101        }
102        return includeRoots;
103    }
104
105    /**
106     * Checks if the given path is excluded by the include/exclude configuration.<p>
107     *
108     * @param path the path to check
109     *
110     * @return true if the path is excluded
111     */
112    public boolean isExcluded(String path) {
113
114        path = normalizePath(path);
115        List<String> pathList = new ArrayList<String>(m_allPaths);
116        // m_allPaths is already sorted, we need the reverse ordering so children come before their parents
117        // (we want to find the deepest parent folder of 'path' that is marked as include/exclude)
118        Collections.reverse(pathList);
119        for (String pathInList : pathList) {
120            if (CmsStringUtil.isPrefixPath(pathInList, path)) {
121                return m_excludes.contains(pathInList);
122            }
123        }
124        return false;
125    }
126
127    /**
128     * Converts a path to a normalized form.<p>
129     *
130     * @param path the path to normalize
131     *
132     * @return the normalized path
133     */
134    protected String normalizePath(String path) {
135
136        if (path.equals("/")) {
137            return path;
138        } else {
139            return CmsFileUtil.removeTrailingSeparator(path);
140        }
141
142    }
143}