001package Torello.Java; 002 003import Torello.Java.StrFilter; 004 005import java.util.function.Predicate; 006import java.util.Iterator; 007 008/** 009 * A simple functional-interface (lambda) for filtering lists of <CODE>FileNode</CODE>. 010 * 011 * <EMBED CLASS='external-html' DATA-FILE-ID=FILENODE_FILTER> 012 * 013 * @see StrFilter 014 */ 015@FunctionalInterface 016public interface FileNodeFilter extends Predicate<FileNode>, java.io.Serializable 017{ 018 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUIDFI> */ 019 public static final long serialVersionUID = 1; 020 021 /** 022 * <EMBED CLASS='external-html' DATA-FILE-ID=FUNC_INTER_METH> 023 * 024 * @param fn Any file node 025 * 026 * @return A {@code TRUE} value should mean that the {@code FileNode} has passed the test 027 * (will be kept / retained). A return value of {@code FALSE} should indicate that the 028 * {@code FileNode} needs to be filtered. 029 */ 030 public boolean test(FileNode fn); 031 032 /** 033 * Standard Java-{@code Predicate}, Java Functional-Interface AND routine. 034 * 035 * <BR /><BR />Logically AND's <B>{@code 'this'}</B> {@code FileNodeFilter} with the filter 036 * parameter <B>{@code 'other'}</B> 037 * 038 * @param other A 2nd {@code FileNodeFilter} with which <B>{@code 'this'}</B> filter may be 039 * AND'ed. 040 * 041 * @return A new {@code FileNodeFilter} that is the logical-and of <B>{@code 'this'}</B> filter 042 * and <B>{@code 'other'}</B> 043 */ 044 default FileNodeFilter and(FileNodeFilter other) 045 { 046 // FAIL-FAST: Check that the lambda will not throw a null pointer exception prior to 047 // creating the lambda. 048 049 if (other == null) throw new NullPointerException 050 ("The parameter 'other' to FileNodeFilter.and(other) was null."); 051 052 return (FileNode f) -> this.test(f) && other.test(f); 053 } 054 055 /** 056 * Standard Java-{@code Predicate}, Java Functional-Interface OR routine. 057 * 058 * <BR /><BR />Logically OR's <B>{@code 'this'}</B> {@code FileNodeFilter} with the filter 059 * parameter <B>{@code 'other'}</B> 060 * 061 * @param other A 2nd {@code FileNodeFilter} with which <B>{@code 'this'}</B> filter may be 062 * or'ed. 063 * 064 * @return A new FileNodeFilter that is the logical-or of <B>{@code 'this'}</B> filter and 065 * <B>"other"</B> 066 */ 067 default FileNodeFilter or(FileNodeFilter other) 068 { 069 // FAIL-FAST: Check that the lambda will not throw a null pointer exception prior to 070 // creating the lambda. 071 072 if (other == null) throw new NullPointerException 073 ("The parameter 'other' to FileNodeFilter.or(other) was null.."); 074 075 return (FileNode f) -> this.test(f) || other.test(f); 076 } 077 078 /** 079 * Standard Java-{@code Predicate}, Java Functional-Interface NEGATE routine. 080 * 081 * <BR /><BR />Generates 's a {@code FileNodeFilter} that is the "logical-not" of 082 * <B>{@code 'this'}</B> filter. 083 * 084 * @return A new {@code FileNodeFilter} that would return {@code TRUE} whenever 085 * <B>{@code 'this'}</B> would return {@code FALSE}, and vice-versa. 086 */ 087 default FileNodeFilter negate() { return (FileNode f) -> ! this.test(f); } 088 089 /** 090 * This is similar to the java streams function {@code filter(Predicate<>)}. Elements that do 091 * not meet the criteria specified by this {@code FileNodeFilter} - <I>specifically, if an 092 * element of the input-parameter {@code 'urlList'} would evaluate to {@code FALSE}</I> - then 093 * that element shall be removed from the list. 094 * 095 * @param fileNodes An {@code Iterable} of {@code FileNode's} which the user would like 096 * filtered using {@code 'this'} filter. 097 * 098 * @return The number of elements that were removed from parameter {@code 'fileNodes'} based on 099 * the results of the {@code 'test(FileNode)'} lambda-method {@code FileNodeFilter.test()} of 100 * {@code 'this'} instance. 101 */ 102 public default int filter(Iterable<FileNode> fileNodes) 103 { 104 int removeCount = 0; 105 Iterator<FileNode> iter = fileNodes.iterator(); 106 107 // If the filter test returns FALSE, then remove the URL from the collection. 108 // Increment the removeCount Counter. 109 110 while (iter.hasNext()) if (! test(iter.next())) { removeCount++; iter.remove(); } 111 112 return removeCount; 113 } 114 115 /** 116 * This wraps a {@code StrFilter} inside of a {@code FileNodeFilter}. The 117 * {@code String}-comparison that is performed will use the full-path-name of the 118 * {@code FileNode}. 119 * 120 * @param sf This is a "String Predicate" that has (usually, but not required) been built by 121 * one of the many {@code String}-Filter Factory-Build static-methods of 122 * {@code class StrFilter}. The Predicate's that are constructed via the build methods of 123 * {@code StrFilter} call the {@code Object.toString()} method on the objects they receive for 124 * testing. 125 * 126 * @return FileNodeFilter This will return an instance of a {@code FileNodeFilter} that will 127 * test the full-path-name as a {@code String}. 128 * 129 * @see StrFilter 130 */ 131 public static FileNodeFilter fromStrFilter(StrFilter sf) 132 { 133 if (sf == null) throw new NullPointerException( 134 "The String-Filter Predicate Parameter 'sf' in static-factory builder method " + 135 "'fromStrFilter' was passed a null value." 136 ); 137 138 return (FileNode fn) -> sf.test(fn); 139 } 140}