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