Search code examples
javaspringspring-integrationspring-integration-ftp

Spring Integration CompositeFileListFilter


I am using CompositeFileListFilter to add two filters. Firstly, I want to execute AbstractPersistentFileListFilter with the default implementation, thereby protecting it from duplication. Second, I use my own implementation, which checks the database for the existence of a file, protecting me from duplicates in the event of a system restart

How can this approach be released? So that the default implementation of AbstractPersistentFileListFilter with the internal memory of the MetadataStore is executed first

The goal is to reduce database calls to check for the existence of a file. Perhaps there is a better approach to the solution. Thanks for any help!

FtpConfiguration.java

@Bean
    CompositeFileListFilter<FTPFile> getCompositeFileListFilter() {
        CompositeFileListFilter<FTPFile> compositeFileListFilter = new CompositeFileListFilter<>();
        compositeFileListFilter.addFilters(new CustomFileFilter(messageRepo));
        return compositeFileListFilter;
    }

    @Bean
    public IntegrationFlow ftpIntegrationFlow() {
        return IntegrationFlows.from(
                Ftp.inboundStreamingAdapter(template())
                        .filter(getCompositeFileListFilter())
                        .remoteDirectory("."),
                e -> e.poller(Pollers.fixedDelay(500).advice(advice())))
                .transform(new StreamTransformer("UTF-8"))
                .handle(messageService::unmarshall)
                .get();
    }

CustomFileFilter.java

@Component
@Log4j2
public class CustomFileFilter implements FileListFilter<FTPFile> {

    private final MessageRepo messageRepo;

    public CustomFileFilter(MessageRepo messageRepo) {
        this.messageRepo = messageRepo;
    }

    @Override
    public List<FTPFile> filterFiles(FTPFile[] files) {
        return null;
    }

    @Override
    public boolean accept(FTPFile file) {
        String fileName = file.getName();
        log.info("file filter get name: {}", fileName);

        Integer fileCheck = messageRepo.checkExistsMessage(fileName);
        log.info("fileCheck: {}", fileCheck);

        return fileCheck != 1;
    }

    @Override
    public boolean supportsSingleFileFiltering() {
        return true;
    }
}


Solution

  • Use the ChainFileListFilter instead:

    /**
     * The {@link CompositeFileListFilter} extension which chains the result
     * of the previous filter to the next one. If a filter in the chain returns
     * an empty list, the remaining filters are not invoked.
     *
     * @param <F> The type that will be filtered.
     *
     * @author Artem Bilan
     * @author Gary Russell
     * @author Cengis Kocaurlu
     *
     * @since 4.3.7
     *
     */
    public class ChainFileListFilter<F> extends CompositeFileListFilter<F> {
    

    https://docs.spring.io/spring-integration/docs/current/reference/html/file.html#file-reading

    Starting with version 4.3.7, a ChainFileListFilter (an extension of CompositeFileListFilter) has been introduced to allow scenarios when subsequent filters should only see the result of the previous filter. (With the CompositeFileListFilter, all filters see all the files, but it passes only files that have passed all filters). ...