| /* |
| * Copyright 2009 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| |
| package com.google.gwt.util.regexfilter; |
| |
| import com.google.gwt.core.ext.TreeLogger; |
| import com.google.gwt.core.ext.UnableToCompleteException; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.regex.Pattern; |
| import java.util.regex.PatternSyntaxException; |
| |
| /** |
| * This class implements filters that are configured with a sequence of regexes. |
| * Each regex in the sequence can be preceded by a + or a - to indicate whether |
| * it indicates that queries matching the regex should be included or excluded. |
| * Concrete subclasses indicate the default behaviors by overriding |
| * {@link #acceptByDefault()} and {@link #entriesArePositiveByDefault()}. |
| */ |
| public abstract class RegexFilter { |
| private final List<String> values; |
| private final ArrayList<Pattern> typePatterns; |
| private final ArrayList<Boolean> includeType; |
| |
| public RegexFilter(TreeLogger logger, List<String> values) |
| throws UnableToCompleteException { |
| this.values = values; |
| int size = values.size(); |
| typePatterns = new ArrayList<Pattern>(size); |
| includeType = new ArrayList<Boolean>(size); |
| |
| // TODO investigate grouping multiple patterns into a single regex |
| for (String regex : values) { |
| // Patterns that don't start with [+-] are considered to be [-] |
| boolean include = entriesArePositiveByDefault(); |
| // Ignore empty regexes |
| if (regex.length() == 0) { |
| logger.log(TreeLogger.ERROR, "Got empty blacklist entry"); |
| throw new UnableToCompleteException(); |
| } |
| char c = regex.charAt(0); |
| if (c == '+' || c == '-') { |
| regex = regex.substring(1); // skip initial character |
| include = (c == '+'); |
| } |
| try { |
| Pattern p = Pattern.compile(regex); |
| typePatterns.add(p); |
| includeType.add(include); |
| |
| logger.log(TreeLogger.DEBUG, "Got filter entry '" + regex + "'"); |
| } catch (PatternSyntaxException e) { |
| logger.log(TreeLogger.ERROR, "Got malformed filter entry '" + regex |
| + "'"); |
| throw new UnableToCompleteException(); |
| } |
| } |
| } |
| |
| public boolean isIncluded(TreeLogger logger, String query) { |
| logger = logger.branch(TreeLogger.DEBUG, "Considering query " + query); |
| |
| // Process patterns in reverse order for early exit |
| int size = typePatterns.size(); |
| for (int idx = size - 1; idx >= 0; idx--) { |
| logger.log(TreeLogger.DEBUG, "Considering filter rule " |
| + values.get(idx) + " for query " + query); |
| boolean include = includeType.get(idx); |
| Pattern pattern = typePatterns.get(idx); |
| if (pattern.matcher(query).matches()) { |
| if (include) { |
| logger.log(TreeLogger.DEBUG, "Whitelisting " + query |
| + " according to rule " + values.get(idx)); |
| return true; |
| } else { |
| logger.log(TreeLogger.DEBUG, "Blacklisting " + query |
| + " according to rule " + values.get(idx)); |
| return false; |
| } |
| } |
| } |
| |
| // None of the patterns matched |
| return acceptByDefault(); |
| } |
| |
| /** |
| * If no pattern matches, whether the query should be considered as an accept. |
| */ |
| protected abstract boolean acceptByDefault(); |
| |
| /** |
| * If a pattern is not preceded by + or -, whether the query should be |
| * considered positive. |
| */ |
| protected abstract boolean entriesArePositiveByDefault(); |
| } |