001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (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 GmbH & Co. KG, 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.repository;
029
030import org.opencms.configuration.CmsConfigurationException;
031import org.opencms.main.CmsLog;
032
033import java.util.ArrayList;
034import java.util.Collections;
035import java.util.Iterator;
036import java.util.List;
037import java.util.regex.Matcher;
038import java.util.regex.Pattern;
039
040/**
041 * This class is a filter for the repositories.<p>
042 *
043 * It filters path names, depending on the configuration made.<p>
044 *
045 * @since 6.2.4
046 */
047public class CmsRepositoryFilter {
048
049    /** The exclude type to set for the filer. */
050    private static final String TYPE_EXCLUDE = "exclude";
051
052    /** The include type to set for the filer. */
053    private static final String TYPE_INCLUDE = "include";
054
055    /** The rules to be used of the filter. */
056    private List<Pattern> m_filterRules;
057
058    /** The type of the filter: include or exclude. */
059    private String m_type;
060
061    /**
062     * Default constructor initializing member variables.
063     */
064    public CmsRepositoryFilter() {
065
066        m_filterRules = new ArrayList<Pattern>();
067    }
068
069    /**
070     * Adds a new filter rule (regex) to the filter.<p>
071     *
072     * @param rule the rule (regex) to add
073     */
074    public void addFilterRule(String rule) {
075
076        m_filterRules.add(Pattern.compile(rule));
077    }
078
079    /**
080     * Returns the filterRules.<p>
081     *
082     * @return the filterRules
083     */
084    public List<Pattern> getFilterRules() {
085
086        return m_filterRules;
087    }
088
089    /**
090     * Returns the type.<p>
091     *
092     * @return the type
093     */
094    public String getType() {
095
096        return m_type;
097    }
098
099    /**
100     * Initializes a configuration after all parameters have been added.<p>
101     *
102     * @throws CmsConfigurationException if something goes wrong
103     */
104    public void initConfiguration() throws CmsConfigurationException {
105
106        if ((!TYPE_INCLUDE.equals(m_type)) && (!TYPE_EXCLUDE.equals(m_type))) {
107            throw new CmsConfigurationException(Messages.get().container(Messages.ERR_INVALID_FILTER_TYPE_1, m_type));
108        }
109
110        if (CmsLog.INIT.isInfoEnabled()) {
111
112            Iterator<Pattern> iter = m_filterRules.iterator();
113            while (iter.hasNext()) {
114                Pattern rule = iter.next();
115
116                CmsLog.INIT.info(
117                    Messages.get().getBundle().key(Messages.INIT_ADD_FILTER_RULE_2, m_type, rule.pattern()));
118            }
119        }
120
121        m_filterRules = Collections.unmodifiableList(m_filterRules);
122    }
123
124    /**
125     * Checks if a path is filtered out of the filter or not.<p>
126     *
127     * @param path the path of a resource to check
128     * @return true if the name matches one of the given filter patterns
129     */
130    public boolean isFiltered(String path) {
131
132        for (int j = 0; j < m_filterRules.size(); j++) {
133            Pattern pattern = m_filterRules.get(j);
134            if (isPartialMatch(pattern, path)) {
135                return m_type.equals(TYPE_EXCLUDE);
136            }
137        }
138
139        return m_type.equals(TYPE_INCLUDE);
140    }
141
142    /**
143     * Sets the filterRules.<p>
144     *
145     * @param filterRules the filterRules to set
146     */
147    public void setFilterRules(List<Pattern> filterRules) {
148
149        m_filterRules = filterRules;
150    }
151
152    /**
153     * Sets the type.<p>
154     *
155     * @param type the type to set
156     */
157    public void setType(String type) {
158
159        m_type = type;
160    }
161
162    /**
163     * Returns if the given path matches or partially matches the pattern.<p>
164     *
165     * For example the regex "/system/modules/" should match the path "/system/".
166     * That's not working with Java 1.4. Starting with Java 1.5 there are possiblities
167     * to do that. Until then you have to configure all parent paths as a regex filter.<p>
168     *
169     * @param pattern the pattern to use
170     * @param path the path to test if the pattern matches (partially)
171     *
172     * @return true if the path matches (partially) the pattern
173     */
174    private boolean isPartialMatch(Pattern pattern, String path) {
175
176        Matcher matcher = pattern.matcher(path);
177        if (matcher.matches()) {
178            return true;
179        }
180
181        if (!path.endsWith("/")) {
182            matcher = pattern.matcher(path + "/");
183            return matcher.matches();
184        }
185
186        return false;
187        // return matcher.hitEnd();
188    }
189}