Filters.java
001 package net.sourceforge.pmd.util.filter;
002 
003 import java.io.File;
004 import java.io.FilenameFilter;
005 import java.util.ArrayList;
006 import java.util.Collection;
007 import java.util.List;
008 
009 /**
010  * Utility class for working with Filters.  Contains builder style methods,
011  * apply methods, as well as mechanisms for adapting Filters and FilenameFilters.
012  */
013 public class Filters {
014 
015   /**
016    * Filter a given Collection.
017    @param <T> Type of the Collection.
018    @param filter A Filter upon the Type of objects in the Collection.
019    @param collection The Collection to filter.
020    @return A List containing only those objects for which the Filter returned <code>true</code>.
021    */
022   public static <T> List<T> filter(Filter<T> filter, Collection<T> collection) {
023     List<T> list = new ArrayList<T>();
024     for (T obj : collection) {
025       if (filter.filter(obj)) {
026         list.add(obj);
027       }
028     }
029     return list;
030   }
031 
032   /**
033    * Get a File Filter for files with the given extensions, ignoring case.
034    @param extensions The extensions to filter.
035    @return A File Filter.
036    */
037   public static Filter<File> getFileExtensionFilter(String... extensions) {
038     return new FileExtensionFilter(extensions);
039   }
040 
041   /**
042    * Get a File Filter for directories.
043    @return A File Filter.
044    */
045   public static Filter<File> getDirectoryFilter() {
046     return DirectoryFilter.INSTANCE;
047   }
048 
049   /**
050    * Get a File Filter for directories or for files with the given extensions, ignoring case.
051    @param extensions The extensions to filter.
052    @return A File Filter.
053    */
054   public static Filter<File> getFileExtensionOrDirectoryFilter(String... extensions) {
055     return new OrFilter<File>(getFileExtensionFilter(extensions), getDirectoryFilter());
056   }
057 
058   /**
059    * Given a String Filter, expose as a File Filter.  The File paths are
060    * normalized to a standard pattern using <code>/</code> as a path separator
061    * which can be used cross platform easily in a regular expression based
062    * String Filter.
063    
064    @param filter A String Filter.
065    @return A File Filter.
066    */
067   public static Filter<File> toNormalizedFileFilter(final Filter<String> filter) {
068     return new Filter<File>() {
069       public boolean filter(File file) {
070         String path = file.getPath();
071         path = path.replace('\\''/');
072         return filter.filter(path);
073       }
074 
075       public String toString() {
076         return filter.toString();
077       }
078     };
079   }
080 
081   /**
082    * Given a String Filter, expose as a Filter on another type.  The
083    <code>toString()</code> method is called on the objects of the other
084    * type and delegated to the String Filter.
085    @param <T> The desired type.
086    @param filter The existing String Filter.
087    @return A Filter on the desired type.
088    */
089   public static <T> Filter<T> fromStringFilter(final Filter<String> filter) {
090     return new Filter<T>() {
091       public boolean filter(T obj) {
092         return filter.filter(obj.toString());
093       }
094 
095       public String toString() {
096         return filter.toString();
097       }
098     };
099   }
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.isEmpty()) {
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 }