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.util.List;
022
023import org.apache.commons.io.FilenameUtils;
024import org.apache.commons.io.IOCase;
025
026/**
027 * Filters files using the supplied wildcards.
028 * <p>
029 * This filter selects files and directories based on one or more wildcards.
030 * Testing is case-sensitive by default, but this can be configured.
031 * </p>
032 * <p>
033 * The wildcard matcher uses the characters '?' and '*' to represent a
034 * single or multiple wildcard characters.
035 * This is the same as often found on Dos/Unix command lines.
036 * The check is case-sensitive by default.
037 * See {@link FilenameUtils#wildcardMatchOnSystem(String,String)} for more information.
038 * </p>
039 * <p>
040 * For example:
041 * </p>
042 * <pre>
043 * File dir = new File(".");
044 * FileFilter fileFilter = new WildcardFileFilter("*test*.java~*~");
045 * File[] files = dir.listFiles(fileFilter);
046 * for (int i = 0; i &lt; files.length; i++) {
047 *   System.out.println(files[i]);
048 * }
049 * </pre>
050 *
051 * @since 1.3
052 */
053public class WildcardFileFilter extends AbstractFileFilter implements Serializable {
054
055    private static final long serialVersionUID = -7426486598995782105L;
056    /** The wildcards that will be used to match file names. */
057    private final String[] wildcards;
058    /** Whether the comparison is case sensitive. */
059    private final IOCase caseSensitivity;
060
061    /**
062     * Construct a new case-sensitive wildcard filter for a single wildcard.
063     *
064     * @param wildcard  the wildcard to match
065     * @throws IllegalArgumentException if the pattern is null
066     */
067    public WildcardFileFilter(final String wildcard) {
068        this(wildcard, IOCase.SENSITIVE);
069    }
070
071    /**
072     * Construct a new wildcard filter for a single wildcard specifying case-sensitivity.
073     *
074     * @param wildcard  the wildcard to match, not null
075     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
076     * @throws IllegalArgumentException if the pattern is null
077     */
078    public WildcardFileFilter(final String wildcard, final IOCase caseSensitivity) {
079        if (wildcard == null) {
080            throw new IllegalArgumentException("The wildcard must not be null");
081        }
082        this.wildcards = new String[] { wildcard };
083        this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
084    }
085
086    /**
087     * Construct a new case-sensitive wildcard filter for an array of wildcards.
088     * <p>
089     *
090     * @param wildcards  the array of wildcards to match
091     * @throws IllegalArgumentException if the pattern array is null
092     */
093    public WildcardFileFilter(final String... wildcards) {
094        this(wildcards, IOCase.SENSITIVE);
095    }
096
097    /**
098     * Construct a new wildcard filter for an array of wildcards specifying case-sensitivity.
099     * <p>
100     *
101     * @param wildcards  the array of wildcards to match, not null
102     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
103     * @throws IllegalArgumentException if the pattern array is null
104     */
105    public WildcardFileFilter(final String[] wildcards, final IOCase caseSensitivity) {
106        if (wildcards == null) {
107            throw new IllegalArgumentException("The wildcard array must not be null");
108        }
109        this.wildcards = new String[wildcards.length];
110        System.arraycopy(wildcards, 0, this.wildcards, 0, wildcards.length);
111        this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
112    }
113
114    /**
115     * Construct a new case-sensitive wildcard filter for a list of wildcards.
116     *
117     * @param wildcards  the list of wildcards to match, not null
118     * @throws IllegalArgumentException if the pattern list is null
119     * @throws ClassCastException if the list does not contain Strings
120     */
121    public WildcardFileFilter(final List<String> wildcards) {
122        this(wildcards, IOCase.SENSITIVE);
123    }
124
125    /**
126     * Construct a new wildcard filter for a list of wildcards specifying case-sensitivity.
127     *
128     * @param wildcards  the list of wildcards to match, not null
129     * @param caseSensitivity  how to handle case sensitivity, null means case-sensitive
130     * @throws IllegalArgumentException if the pattern list is null
131     * @throws ClassCastException if the list does not contain Strings
132     */
133    public WildcardFileFilter(final List<String> wildcards, final IOCase caseSensitivity) {
134        if (wildcards == null) {
135            throw new IllegalArgumentException("The wildcard list must not be null");
136        }
137        this.wildcards = wildcards.toArray(EMPTY_STRING_ARRAY);
138        this.caseSensitivity = caseSensitivity == null ? IOCase.SENSITIVE : caseSensitivity;
139    }
140
141    //-----------------------------------------------------------------------
142    /**
143     * Checks to see if the file name matches one of the wildcards.
144     *
145     * @param dir  the file directory (ignored)
146     * @param name  the file name
147     * @return true if the file name matches one of the wildcards
148     */
149    @Override
150    public boolean accept(final File dir, final String name) {
151        for (final String wildcard : wildcards) {
152            if (FilenameUtils.wildcardMatch(name, wildcard, caseSensitivity)) {
153                return true;
154            }
155        }
156        return false;
157    }
158
159    /**
160     * Checks to see if the file name matches one of the wildcards.
161     *
162     * @param file  the file to check
163     * @return true if the file name matches one of the wildcards
164     */
165    @Override
166    public boolean accept(final File file) {
167        final String name = file.getName();
168        for (final String wildcard : wildcards) {
169            if (FilenameUtils.wildcardMatch(name, wildcard, caseSensitivity)) {
170                return true;
171            }
172        }
173        return false;
174    }
175
176    /**
177     * Provide a String representation of this file filter.
178     *
179     * @return a String representation
180     */
181    @Override
182    public String toString() {
183        final StringBuilder buffer = new StringBuilder();
184        buffer.append(super.toString());
185        buffer.append("(");
186        if (wildcards != null) {
187            for (int i = 0; i < wildcards.length; i++) {
188                if (i > 0) {
189                    buffer.append(",");
190                }
191                buffer.append(wildcards[i]);
192            }
193        }
194        buffer.append(")");
195        return buffer.toString();
196    }
197
198}