org.springframework.integration.file.filters.CompositeFileListFilter.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.integration.file.filters.CompositeFileListFilter.java

Source

/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.integration.file.filters;

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

/**
 * Simple {@link FileListFilter} that predicates its matches against <b>all</b> of the
 * configured {@link FileListFilter}.
 * <p>
 * Note: when {@link #discardCallback} is provided, it is populated to all the
 * {@link DiscardAwareFileListFilter} delegates. In this case, since this filter
 * matches the files against all delegates, the {@link #discardCallback} may be
 * called several times for the same file.
 *
 * @param <F> The type that will be filtered.
 *
 * @author Iwein Fuld
 * @author Josh Long
 * @author Gary Russell
 * @author Artem Bilan
 */
public class CompositeFileListFilter<F> implements ReversibleFileListFilter<F>, ResettableFileListFilter<F>,
        DiscardAwareFileListFilter<F>, Closeable {

    protected final Set<FileListFilter<F>> fileFilters; // NOSONAR

    private Consumer<F> discardCallback;

    private boolean allSupportAccept = true;

    public CompositeFileListFilter() {
        this.fileFilters = new LinkedHashSet<>();
    }

    public CompositeFileListFilter(Collection<? extends FileListFilter<F>> fileFilters) {
        this.fileFilters = new LinkedHashSet<>(fileFilters);
        this.allSupportAccept = fileFilters.stream().allMatch(FileListFilter<F>::supportsSingleFileFiltering);
    }

    @Override
    public void close() throws IOException {
        for (FileListFilter<F> filter : this.fileFilters) {
            if (filter instanceof Closeable) {
                ((Closeable) filter).close();
            }
        }
    }

    public CompositeFileListFilter<F> addFilter(FileListFilter<F> filter) {
        this.allSupportAccept &= filter.supportsSingleFileFiltering();
        return addFilters(Collections.singletonList(filter));
    }

    /**
     * @param filters one or more new filters to add
     * @return this CompositeFileFilter instance with the added filters
     * @see #addFilters(Collection)
     */
    @SafeVarargs
    @SuppressWarnings("varargs")
    public final CompositeFileListFilter<F> addFilters(FileListFilter<F>... filters) {
        List<FileListFilter<F>> asList = Arrays.asList(filters);
        return addFilters(asList);
    }

    /**
     * Not thread safe. Only a single thread may add filters at a time.
     * <p>
     * Add the new filters to this CompositeFileListFilter while maintaining the existing filters.
     *
     * @param filtersToAdd a list of filters to add
     * @return this CompositeFileListFilter instance with the added filters
     */
    public CompositeFileListFilter<F> addFilters(Collection<? extends FileListFilter<F>> filtersToAdd) {
        for (FileListFilter<F> elf : filtersToAdd) {
            if (elf instanceof DiscardAwareFileListFilter) {
                ((DiscardAwareFileListFilter<F>) elf).addDiscardCallback(this.discardCallback);
            }
            if (elf instanceof InitializingBean) {
                try {
                    ((InitializingBean) elf).afterPropertiesSet();
                } catch (Exception e) {
                    throw new IllegalStateException(e);
                }
            }
        }
        this.fileFilters.addAll(filtersToAdd);
        if (this.allSupportAccept) {
            this.allSupportAccept = filtersToAdd.stream().allMatch(FileListFilter<F>::supportsSingleFileFiltering);
        }
        return this;
    }

    @Override
    public void addDiscardCallback(Consumer<F> discardCallbackToSet) {
        this.discardCallback = discardCallbackToSet;
        if (this.discardCallback != null) {
            this.fileFilters.stream().filter(DiscardAwareFileListFilter.class::isInstance)
                    .map(f -> (DiscardAwareFileListFilter<F>) f)
                    .forEach(f -> f.addDiscardCallback(discardCallbackToSet));
        }
    }

    @Override
    public List<F> filterFiles(F[] files) {
        Assert.notNull(files, "'files' should not be null");
        List<F> results = new ArrayList<>(Arrays.asList(files));
        for (FileListFilter<F> fileFilter : this.fileFilters) {
            List<F> currentResults = fileFilter.filterFiles(files);
            results.retainAll(currentResults);
        }
        return results;
    }

    @Override
    public boolean accept(F file) {
        AtomicBoolean allAccept = new AtomicBoolean(true);
        // we can't use stream().allMatch() because we have to call all filters for this filter's contract
        this.fileFilters.forEach(f -> allAccept.compareAndSet(true, f.accept(file)));
        return allAccept.get();
    }

    @Override
    public boolean supportsSingleFileFiltering() {
        return this.allSupportAccept;
    }

    @Override
    public void rollback(F file, List<F> files) {
        for (FileListFilter<F> fileFilter : this.fileFilters) {
            if (fileFilter instanceof ReversibleFileListFilter) {
                ((ReversibleFileListFilter<F>) fileFilter).rollback(file, files);
            }
        }
    }

    @Override
    public boolean remove(F f) {
        boolean removed = false;
        for (FileListFilter<F> fileFilter : this.fileFilters) {
            if (fileFilter instanceof ResettableFileListFilter) {
                ((ResettableFileListFilter<F>) fileFilter).remove(f);
                removed = true;
            }
        }
        return removed;
    }

}