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