1 package net.sourceforge.pmd.util.filter;
2
3 import java.io.File;
4 import java.io.FilenameFilter;
5 import java.util.ArrayList;
6 import java.util.Collection;
7 import java.util.List;
8
9 /**
10 * Utility class for working with Filters. Contains builder style methods,
11 * apply methods, as well as mechanisms for adapting Filters and FilenameFilters.
12 */
13 public class Filters {
14
15 /**
16 * Filter a given Collection.
17 * @param <T> Type of the Collection.
18 * @param filter A Filter upon the Type of objects in the Collection.
19 * @param collection The Collection to filter.
20 * @return A List containing only those objects for which the Filter returned <code>true</code>.
21 */
22 public static <T> List<T> filter(Filter<T> filter, Collection<T> collection) {
23 List<T> list = new ArrayList<T>();
24 for (T obj : collection) {
25 if (filter.filter(obj)) {
26 list.add(obj);
27 }
28 }
29 return list;
30 }
31
32 /**
33 * Get a File Filter for files with the given extensions, ignoring case.
34 * @param extensions The extensions to filter.
35 * @return A File Filter.
36 */
37 public static Filter<File> getFileExtensionFilter(String... extensions) {
38 return new FileExtensionFilter(extensions);
39 }
40
41 /**
42 * Get a File Filter for directories.
43 * @return A File Filter.
44 */
45 public static Filter<File> getDirectoryFilter() {
46 return DirectoryFilter.INSTANCE;
47 }
48
49 /**
50 * Get a File Filter for directories or for files with the given extensions, ignoring case.
51 * @param extensions The extensions to filter.
52 * @return A File Filter.
53 */
54 public static Filter<File> getFileExtensionOrDirectoryFilter(String... extensions) {
55 return new OrFilter<File>(getFileExtensionFilter(extensions), getDirectoryFilter());
56 }
57
58 /**
59 * Given a String Filter, expose as a File Filter. The File paths are
60 * normalized to a standard pattern using <code>/</code> as a path separator
61 * which can be used cross platform easily in a regular expression based
62 * String Filter.
63 *
64 * @param filter A String Filter.
65 * @return A File Filter.
66 */
67 public static Filter<File> toNormalizedFileFilter(final Filter<String> filter) {
68 return new Filter<File>() {
69 public boolean filter(File file) {
70 String path = file.getPath();
71 path = path.replace('\\', '/');
72 return filter.filter(path);
73 }
74
75 public String toString() {
76 return filter.toString();
77 }
78 };
79 }
80
81 /**
82 * Given a String Filter, expose as a Filter on another type. The
83 * <code>toString()</code> method is called on the objects of the other
84 * type and delegated to the String Filter.
85 * @param <T> The desired type.
86 * @param filter The existing String Filter.
87 * @return A Filter on the desired type.
88 */
89 public static <T> Filter<T> fromStringFilter(final Filter<String> filter) {
90 return new Filter<T>() {
91 public boolean filter(T obj) {
92 return filter.filter(obj.toString());
93 }
94
95 public String toString() {
96 return filter.toString();
97 }
98 };
99 }
100
101 /**
102 * Given a File Filter, expose as a FilenameFilter.
103 * @param filter The File Filter.
104 * @return A FilenameFilter.
105 */
106 public static FilenameFilter toFilenameFilter(final Filter<File> filter) {
107 return new FilenameFilter() {
108 public boolean accept(File dir, String name) {
109 return filter.filter(new File(dir, name));
110 }
111
112 public String toString() {
113 return filter.toString();
114 }
115 };
116 }
117
118 /**
119 * Given a FilenameFilter, expose as a File Filter.
120 * @param filter The FilenameFilter.
121 * @return A File Filter.
122 */
123 public static Filter<File> toFileFilter(final FilenameFilter filter) {
124 return new Filter<File>() {
125 public boolean filter(File file) {
126 return filter.accept(file.getParentFile(), file.getName());
127 }
128
129 public String toString() {
130 return filter.toString();
131 }
132 };
133 }
134
135 /**
136 * Construct a String Filter using set of include and exclude regular
137 * expressions. If there are no include regular expressions provide, then
138 * a regular expression is added which matches every String by default.
139 * A String is included as long as it matches an include regular expression
140 * and does not match an exclude regular expression.
141 * <p>
142 * In other words, exclude patterns override include patterns.
143 *
144 * @param includeRegexes The include regular expressions. May be <code>null</code>.
145 * @param excludeRegexes The exclude regular expressions. May be <code>null</code>.
146 * @return A String Filter.
147 */
148 public static Filter<String> buildRegexFilterExcludeOverInclude(List<String> includeRegexes,
149 List<String> excludeRegexes) {
150 OrFilter<String> includeFilter = new OrFilter<String>();
151 if (includeRegexes == null || includeRegexes.size() == 0) {
152 includeFilter.addFilter(new RegexStringFilter(".*"));
153 } else {
154 for (String includeRegex : includeRegexes) {
155 includeFilter.addFilter(new RegexStringFilter(includeRegex));
156 }
157 }
158
159 OrFilter<String> excludeFilter = new OrFilter<String>();
160 if (excludeRegexes != null) {
161 for (String excludeRegex : excludeRegexes) {
162 excludeFilter.addFilter(new RegexStringFilter(excludeRegex));
163 }
164 }
165
166 return new AndFilter<String>(includeFilter, new NotFilter<String>(excludeFilter));
167 }
168
169 /**
170 * Construct a String Filter using set of include and exclude regular
171 * expressions. If there are no include regular expressions provide, then
172 * a regular expression is added which matches every String by default.
173 * A String is included as long as the case that there is an include which
174 * matches or there is not an exclude which matches.
175 * <p>
176 * In other words, include patterns override exclude patterns.
177 *
178 * @param includeRegexes The include regular expressions. May be <code>null</code>.
179 * @param excludeRegexes The exclude regular expressions. May be <code>null</code>.
180 * @return A String Filter.
181 */
182 public static Filter<String> buildRegexFilterIncludeOverExclude(List<String> includeRegexes,
183 List<String> excludeRegexes) {
184 OrFilter<String> includeFilter = new OrFilter<String>();
185 if (includeRegexes != null) {
186 for (String includeRegex : includeRegexes) {
187 includeFilter.addFilter(new RegexStringFilter(includeRegex));
188 }
189 }
190
191 OrFilter<String> excludeFilter = new OrFilter<String>();
192 if (excludeRegexes != null) {
193 for (String excludeRegex : excludeRegexes) {
194 excludeFilter.addFilter(new RegexStringFilter(excludeRegex));
195 }
196 }
197
198 return new OrFilter<String>(includeFilter, new NotFilter<String>(excludeFilter));
199 }
200 }