/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.util.filter;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Utility class for working with Filters. Contains builder style methods, apply
* methods, as well as mechanisms for adapting Filters and FilenameFilters.
*/
public class Filters {
private Filters() { }
/**
* Filter a given Collection.
*
* @param <T>
* Type of the Collection.
* @param filter
* A Filter upon the Type of objects in the Collection.
* @param collection
* The Collection to filter.
* @return A List containing only those objects for which the Filter
* returned <code>true</code>.
*/
public static <T> List<T> filter(Filter<T> filter, Collection<T> collection) {
List<T> list = new ArrayList<>();
for (T obj : collection) {
if (filter.filter(obj)) {
list.add(obj);
}
}
return list;
}
/**
* Get a File Filter for files with the given extensions, ignoring case.
*
* @param extensions
* The extensions to filter.
* @return A File Filter.
*/
public static Filter<File> getFileExtensionFilter(String... extensions) {
return new FileExtensionFilter(extensions);
}
/**
* Get a File Filter for directories.
*
* @return A File Filter.
*/
public static Filter<File> getDirectoryFilter() {
return DirectoryFilter.INSTANCE;
}
/**
* Get a File Filter for directories or for files with the given extensions,
* ignoring case.
*
* @param extensions
* The extensions to filter.
* @return A File Filter.
*/
public static Filter<File> getFileExtensionOrDirectoryFilter(String... extensions) {
return new OrFilter<>(getFileExtensionFilter(extensions), getDirectoryFilter());
}
/**
* Given a String Filter, expose as a File Filter. The File paths are
* normalized to a standard pattern using <code>/</code> as a path separator
* which can be used cross platform easily in a regular expression based
* String Filter.
*
* @param filter
* A String Filter.
* @return A File Filter.
*/
public static Filter<File> toNormalizedFileFilter(final Filter<String> filter) {
return new Filter<File>() {
@Override
public boolean filter(File file) {
String path = file.getPath();
path = path.replace('\\', '/');
return filter.filter(path);
}
@Override
public String toString() {
return filter.toString();
}
};
}
/**
* Given a String Filter, expose as a Filter on another type. The
* <code>toString()</code> method is called on the objects of the other type
* and delegated to the String Filter.
*
* @param <T>
* The desired type.
* @param filter
* The existing String Filter.
* @return A Filter on the desired type.
*/
public static <T> Filter<T> fromStringFilter(final Filter<String> filter) {
return new Filter<T>() {
@Override
public boolean filter(T obj) {
return filter.filter(obj.toString());
}
@Override
public String toString() {
return filter.toString();
}
};
}
/**
* Given a File Filter, expose as a FilenameFilter.
*
* @param filter
* The File Filter.
* @return A FilenameFilter.
*/
public static FilenameFilter toFilenameFilter(final Filter<File> filter) {
return new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return filter.filter(new File(dir, name));
}
@Override
public String toString() {
return filter.toString();
}
};
}
/**
* Given a FilenameFilter, expose as a File Filter.
*
* @param filter
* The FilenameFilter.
* @return A File Filter.
*/
public static Filter<File> toFileFilter(final FilenameFilter filter) {
return new Filter<File>() {
@Override
public boolean filter(File file) {
return filter.accept(file.getParentFile(), file.getName());
}
@Override
public String toString() {
return filter.toString();
}
};
}
/**
* Construct a String Filter using set of include and exclude regular
* expressions. If there are no include regular expressions provide, then a
* regular expression is added which matches every String by default. A
* String is included as long as it matches an include regular expression
* and does not match an exclude regular expression.
* <p>
* In other words, exclude patterns override include patterns.
*
* @param includeRegexes
* The include regular expressions. May be <code>null</code>.
* @param excludeRegexes
* The exclude regular expressions. May be <code>null</code>.
* @return A String Filter.
*/
public static Filter<String> buildRegexFilterExcludeOverInclude(List<String> includeRegexes,
List<String> excludeRegexes) {
OrFilter<String> includeFilter = new OrFilter<>();
if (includeRegexes == null || includeRegexes.isEmpty()) {
includeFilter.addFilter(new RegexStringFilter(".*"));
} else {
for (String includeRegex : includeRegexes) {
includeFilter.addFilter(new RegexStringFilter(includeRegex));
}
}
OrFilter<String> excludeFilter = new OrFilter<>();
if (excludeRegexes != null) {
for (String excludeRegex : excludeRegexes) {
excludeFilter.addFilter(new RegexStringFilter(excludeRegex));
}
}
return new AndFilter<>(includeFilter, new NotFilter<>(excludeFilter));
}
/**
* Construct a String Filter using set of include and exclude regular
* expressions. If there are no include regular expressions provide, then a
* regular expression is added which matches every String by default. A
* String is included as long as the case that there is an include which
* matches or there is not an exclude which matches.
* <p>
* In other words, include patterns override exclude patterns.
*
* @param includeRegexes
* The include regular expressions. May be <code>null</code>.
* @param excludeRegexes
* The exclude regular expressions. May be <code>null</code>.
* @return A String Filter.
*/
public static Filter<String> buildRegexFilterIncludeOverExclude(List<String> includeRegexes,
List<String> excludeRegexes) {
OrFilter<String> includeFilter = new OrFilter<>();
if (includeRegexes != null) {
for (String includeRegex : includeRegexes) {
includeFilter.addFilter(new RegexStringFilter(includeRegex));
}
}
OrFilter<String> excludeFilter = new OrFilter<>();
if (excludeRegexes != null) {
for (String excludeRegex : excludeRegexes) {
excludeFilter.addFilter(new RegexStringFilter(excludeRegex));
}
}
return new OrFilter<>(includeFilter, new NotFilter<>(excludeFilter));
}
}