001/**
002 * Copyright 2010-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.common.util.filter;
017
018import java.util.List;
019import java.util.regex.Matcher;
020import java.util.regex.Pattern;
021
022import org.kuali.common.util.Assert;
023
024import com.google.common.collect.ImmutableList;
025
026/**
027 * This class provides logic for filtering strings based on regular expressions.
028 */
029public final class StringFilter {
030
031        /**
032         * List of include regular expressions.
033         */
034        private final List<String> includes;
035
036        /**
037         * List of exclude regular expressions.
038         */
039        private final List<String> excludes;
040
041        private final List<Pattern> includePatterns;
042        private final List<Pattern> excludePatterns;
043
044        public List<String> getIncludes() {
045                return includes;
046        }
047
048        public List<String> getExcludes() {
049                return excludes;
050        }
051
052        /**
053         * Return true if the string should be included.
054         */
055        public boolean include(String s) {
056                if (isMatch(s, excludePatterns)) {
057                        // An exclude pattern match always "wins"
058                        return false;
059                } else {
060                        // If there are no include patterns always return true
061                        // Otherwise only return true if the string matches one of the provided patterns
062                        return includePatterns.size() == 0 || isMatch(s, includePatterns);
063                }
064        }
065
066        /**
067         * Return true if the string matches any of the patterns
068         */
069        private boolean isMatch(String s, List<Pattern> patterns) {
070                // Loop through the patterns looking for a match
071                for (Pattern pattern : patterns) {
072                        Matcher matcher = pattern.matcher(s);
073                        // We found a match, return true
074                        if (matcher.matches()) {
075                                return true;
076                        }
077                }
078                // We cycled through all of the patterns without finding a match
079                return false;
080        }
081
082        public static class Builder {
083
084                private final List<String> includes;
085                private final List<String> excludes;
086                private final List<Pattern> includePatterns;
087                private final List<Pattern> excludePatterns;
088
089                public Builder() {
090                        this(ImmutableList.<String> of(), ImmutableList.<String> of());
091                }
092
093                public Builder(List<String> includes) {
094                        this(includes, ImmutableList.<String> of());
095                }
096
097                public Builder(List<String> includes, List<String> excludes) {
098                        this.includes = ImmutableList.copyOf(includes);
099                        this.excludes = ImmutableList.copyOf(excludes);
100                        this.includePatterns = ImmutableList.copyOf(RegexUtils.getPatterns(includes));
101                        this.excludePatterns = ImmutableList.copyOf(RegexUtils.getPatterns(excludes));
102                }
103
104                private void validate(StringFilter filter) {
105                        Assert.noNulls(filter.includes, filter.excludes, filter.excludePatterns, filter.includePatterns);
106                }
107
108                public StringFilter build() {
109                        StringFilter filter = new StringFilter(this);
110                        validate(filter);
111                        return filter;
112                }
113
114        }
115
116        private StringFilter(Builder builder) {
117                this.includes = builder.includes;
118                this.excludes = builder.excludes;
119                this.includePatterns = builder.includePatterns;
120                this.excludePatterns = builder.excludePatterns;
121        }
122}