001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.io.filefilter;
018
019import java.io.File;
020import java.io.Serializable;
021import java.nio.file.FileVisitResult;
022import java.nio.file.Path;
023import java.nio.file.attribute.BasicFileAttributes;
024import java.util.List;
025import java.util.Objects;
026
027import org.apache.commons.io.IOCase;
028
029/**
030 * Filters file names for a certain name.
031 * <p>
032 * For example, to print all files and directories in the
033 * current directory whose name is {@code Test}:
034 * </p>
035 * <h2>Using Classic IO</h2>
036 * <pre>
037 * File dir = new File(".");
038 * String[] files = dir.list(new NameFileFilter("Test"));
039 * for (String file : files) {
040 *     System.out.println(file);
041 * }
042 * </pre>
043 *
044 * <h2>Using NIO</h2>
045 * <pre>
046 * final Path dir = Paths.get("");
047 * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new NameFileFilter("Test"));
048 * //
049 * // Walk one dir
050 * Files.<b>walkFileTree</b>(dir, Collections.emptySet(), 1, visitor);
051 * System.out.println(visitor.getPathCounters());
052 * System.out.println(visitor.getFileList());
053 * //
054 * visitor.getPathCounters().reset();
055 * //
056 * // Walk dir tree
057 * Files.<b>walkFileTree</b>(dir, visitor);
058 * System.out.println(visitor.getPathCounters());
059 * System.out.println(visitor.getDirList());
060 * System.out.println(visitor.getFileList());
061 * </pre>
062 *
063 * @since 1.0
064 * @see FileFilterUtils#nameFileFilter(String)
065 * @see FileFilterUtils#nameFileFilter(String, IOCase)
066 */
067public class NameFileFilter extends AbstractFileFilter implements Serializable {
068
069    private static final long serialVersionUID = 176844364689077340L;
070
071    /** The file names to search for */
072    private final String[] names;
073
074    /** Whether the comparison is case sensitive. */
075    private final IOCase caseSensitivity;
076
077    /**
078     * Constructs a new case-sensitive name file filter for a list of names.
079     *
080     * @param names  the names to allow, must not be null
081     * @throws IllegalArgumentException if the name list is null
082     * @throws ClassCastException if the list does not contain Strings
083     */
084    public NameFileFilter(final List<String> names) {
085        this(names, null);
086    }
087
088    /**
089     * Constructs a new name file filter for a list of names specifying case-sensitivity.
090     *
091     * @param names  the names to allow, must not be null
092     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
093     * @throws IllegalArgumentException if the name list is null
094     * @throws ClassCastException if the list does not contain Strings
095     */
096    public NameFileFilter(final List<String> names, final IOCase caseSensitivity) {
097        if (names == null) {
098            throw new IllegalArgumentException("The list of names must not be null");
099        }
100        this.names = names.toArray(EMPTY_STRING_ARRAY);
101        this.caseSensitivity = toIOCase(caseSensitivity);
102    }
103
104    /**
105     * Constructs a new case-sensitive name file filter for a single name.
106     *
107     * @param name  the name to allow, must not be null
108     * @throws IllegalArgumentException if the name is null
109     */
110    public NameFileFilter(final String name) {
111        this(name, IOCase.SENSITIVE);
112    }
113
114    /**
115     * Constructs a new case-sensitive name file filter for an array of names.
116     * <p>
117     * The array is not cloned, so could be changed after constructing the
118     * instance. This would be inadvisable however.
119     * </p>
120     *
121     * @param names  the names to allow, must not be null
122     * @throws IllegalArgumentException if the names array is null
123     */
124    public NameFileFilter(final String... names) {
125        this(names, IOCase.SENSITIVE);
126    }
127
128    /**
129     * Construct a new name file filter specifying case-sensitivity.
130     *
131     * @param name  the name to allow, must not be null
132     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
133     * @throws IllegalArgumentException if the name is null
134     */
135    public NameFileFilter(final String name, final IOCase caseSensitivity) {
136        if (name == null) {
137            throw new IllegalArgumentException("The wildcard must not be null");
138        }
139        this.names = new String[] {name};
140        this.caseSensitivity = toIOCase(caseSensitivity);
141    }
142
143    /**
144     * Constructs a new name file filter for an array of names specifying case-sensitivity.
145     *
146     * @param names  the names to allow, must not be null
147     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
148     * @throws IllegalArgumentException if the names array is null
149     */
150    public NameFileFilter(final String[] names, final IOCase caseSensitivity) {
151        if (names == null) {
152            throw new IllegalArgumentException("The array of names must not be null");
153        }
154        this.names = new String[names.length];
155        System.arraycopy(names, 0, this.names, 0, names.length);
156        this.caseSensitivity = toIOCase(caseSensitivity);
157    }
158
159    /**
160     * Checks to see if the file name matches.
161     *
162     * @param file  the File to check
163     * @return true if the file name matches
164     */
165    @Override
166    public boolean accept(final File file) {
167        return acceptBaseName(file.getName());
168    }
169
170    /**
171     * Checks to see if the file name matches.
172     *
173     * @param dir  the File directory (ignored)
174     * @param name  the file name
175     * @return true if the file name matches
176     */
177    @Override
178    public boolean accept(final File dir, final String name) {
179        return acceptBaseName(name);
180    }
181
182    /**
183     * Checks to see if the file name matches.
184     * @param file  the File to check
185     *
186     * @return true if the file name matches
187     * @since 2.9.0
188     */
189    @Override
190    public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) {
191        return toFileVisitResult(acceptBaseName(Objects.toString(file.getFileName(), null)), file);
192    }
193
194    private boolean acceptBaseName(final String baseName) {
195        for (final String testName : names) {
196            if (caseSensitivity.checkEquals(baseName, testName)) {
197                return true;
198            }
199        }
200        return false;
201    }
202
203    private IOCase toIOCase(final IOCase caseSensitivity) {
204        return caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
205    }
206
207    /**
208     * Provide a String representation of this file filter.
209     *
210     * @return a String representation
211     */
212    @Override
213    public String toString() {
214        final StringBuilder buffer = new StringBuilder();
215        buffer.append(super.toString());
216        buffer.append("(");
217        if (names != null) {
218            for (int i = 0; i < names.length; i++) {
219                if (i > 0) {
220                    buffer.append(",");
221                }
222                buffer.append(names[i]);
223            }
224        }
225        buffer.append(")");
226        return buffer.toString();
227    }
228
229}