    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 *      https://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.FileFilter;
    021import java.io.Serializable;
    022import java.nio.file.FileVisitResult;
    023import java.nio.file.Path;
    024import java.nio.file.attribute.BasicFileAttributes;
    025import java.util.ArrayList;
    026import java.util.Collections;
    027import java.util.List;
    028import java.util.Objects;
    029import java.util.stream.Stream;
    030
    031/**
    032 * A {@link FileFilter} providing conditional OR logic across a list of file filters. This filter returns
    033 * {@code true} if any filters in the list return {@code true}. Otherwise, it returns {@code false}. Checking of the
    034 * file filter list stops when the first filter returns {@code true}.
    035 * <h2>Deprecating Serialization</h2>
    036 * <p>
    037 * <em>Serialization is deprecated and will be removed in 3.0.</em>
    038 * </p>
    039 *
    040 * @since 1.0
    041 * @see FileFilterUtils#or(IOFileFilter...)
    042 */
    043public class OrFileFilter extends AbstractFileFilter implements ConditionalFileFilter, Serializable {
    044
    045    private static final long serialVersionUID = 5767770777065432721L;
    046
    047    /** The list of file filters. */
    048    private final List<IOFileFilter> fileFilters;
    049
    050    /**
    051     * Constructs a new instance of {@link OrFileFilter}.
    052     *
    053     * @since 1.1
    054     */
    055    public OrFileFilter() {
    056        this(0);
    057    }
    058
    059    /**
    060     * Constructs a new instance with the given initial list.
    061     *
    062     * @param initialList the initial list.
    063     */
    064    private OrFileFilter(final ArrayList<IOFileFilter> initialList) {
    065        this.fileFilters = Objects.requireNonNull(initialList, "initialList");
    066    }
    067
    068    /**
    069     * Constructs a new instance with the given initial capacity.
    070     *
    071     * @param initialCapacity the initial capacity.
    072     */
    073    private OrFileFilter(final int initialCapacity) {
    074        this(new ArrayList<>(initialCapacity));
    075    }
    076
    077    /**
    078     * Constructs a new instance for the give filters.
    079     *
    080     * @param fileFilters filters to OR.
    081     * @since 2.9.0
    082     */
    083    public OrFileFilter(final IOFileFilter... fileFilters) {
    084        this(Objects.requireNonNull(fileFilters, "fileFilters").length);
    085        addFileFilter(fileFilters);
    086    }
    087
    088    /**
    089     * Constructs a new file filter that ORs the result of other filters.
    090     *
    091     * @param filter1 the first filter, must not be null.
    092     * @param filter2 the second filter, must not be null.
    093     * @throws IllegalArgumentException if either filter is null.
    094     */
    095    public OrFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) {
    096        this(2);
    097        addFileFilter(filter1);
    098        addFileFilter(filter2);
    099    }
    100
    101    /**
    102     * Constructs a new instance of {@link OrFileFilter} with the specified filters.
    103     *
    104     * @param fileFilters the file filters for this filter, copied.
    105     * @since 1.1
    106     */
    107    public OrFileFilter(final List<IOFileFilter> fileFilters) {
    108        this(new ArrayList<>(Objects.requireNonNull(fileFilters, "fileFilters")));
    109    }
    110
    111    /**
    112     * {@inheritDoc}
    113     */
    114    @Override
    115    public boolean accept(final File file) {
    116        return fileFilters.stream().anyMatch(fileFilter -> fileFilter.accept(file));
    117    }
    118
    119    /**
    120     * {@inheritDoc}
    121     */
    122    @Override
    123    public boolean accept(final File file, final String name) {
    124        return fileFilters.stream().anyMatch(fileFilter -> fileFilter.accept(file, name));
    125    }
    126
    127    /**
    128     * {@inheritDoc}
    129     */
    130    @Override
    131    public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) {
    132        return toDefaultFileVisitResult(fileFilters.stream().anyMatch(fileFilter -> fileFilter.accept(file, attributes) == FileVisitResult.CONTINUE));
    133    }
    134
    135    /**
    136     * {@inheritDoc}
    137     */
    138    @Override
    139    public void addFileFilter(final IOFileFilter fileFilter) {
    140        this.fileFilters.add(Objects.requireNonNull(fileFilter, "fileFilter"));
    141    }
    142
    143    /**
    144     * Adds the given file filters.
    145     *
    146     * @param fileFilters the filters to add.
    147     * @since 2.9.0
    148     */
    149    public void addFileFilter(final IOFileFilter... fileFilters) {
    150        Stream.of(Objects.requireNonNull(fileFilters, "fileFilters")).forEach(this::addFileFilter);
    151    }
    152
    153    /**
    154     * {@inheritDoc}
    155     */
    156    @Override
    157    public List<IOFileFilter> getFileFilters() {
    158        return Collections.unmodifiableList(this.fileFilters);
    159    }
    160
    161    /**
    162     * {@inheritDoc}
    163     */
    164    @Override
    165    public boolean removeFileFilter(final IOFileFilter fileFilter) {
    166        return this.fileFilters.remove(fileFilter);
    167    }
    168
    169    /**
    170     * {@inheritDoc}
    171     */
    172    @Override
    173    public void setFileFilters(final List<IOFileFilter> fileFilters) {
    174        this.fileFilters.clear();
    175        this.fileFilters.addAll(Objects.requireNonNull(fileFilters, "fileFilters"));
    176    }
    177
    178    /**
    179     * Provide a String representation of this file filter.
    180     *
    181     * @return a String representation.
    182     */
    183    @Override
    184    public String toString() {
    185        final StringBuilder buffer = new StringBuilder();
    186        buffer.append(super.toString());
    187        buffer.append("(");
    188        append(fileFilters, buffer);
    189        buffer.append(")");
    190        return buffer.toString();
    191    }
    192
    193}