javaspringspring-integrationintegration-patterns

WatchEventType.DELETE doesn't seem to work


what I would like to do is to track the files removed and apply certain logic around this (get the id and update the entities). I've found that we can pass a list of watch events inside the channel adapter including

FileReadingMessageSource.WatchEventType.DELETE

but when I remove the file from the folder I do not see any events triggered and the transformer is never being applied

@Bean
public IntegrationFlow integrationFlow(FileToMovieTransformer fileToMovieTransformer) {

    return this.integrationFlowBuilder()
            .transform(fileToMovieTransformer)
            .channel(movieHandlerChannel())
            .get();

}

    private IntegrationFlowBuilder integrationFlowBuilder() {

    return IntegrationFlows.from(

            Files.inboundAdapter(new File(localFilmFolder))
                    .autoCreateDirectory(true)
                    .useWatchService(true)
                    .watchEvents(FileReadingMessageSource.WatchEventType.CREATE, FileReadingMessageSource.WatchEventType.DELETE)
                    .patternFilter("*.xml"),

            e -> e.poller(Pollers.fixedDelay(10, TimeUnit.SECONDS)
            ));
}

Solution

  • I would say that you treat DELETE wrong way:

    /**
     * Directory entry deleted.
     *
     * <p> When a directory is registered for this event then the {@link WatchKey}
     * is queued when it is observed that an entry is deleted or renamed out of
     * the directory. The event {@link WatchEvent#count count} for this event
     * is always {@code 1}.
     */
    public static final WatchEvent.Kind<Path> ENTRY_DELETE =
        new StdWatchEventKind<Path>("ENTRY_DELETE", Path.class);
    

    So, there is already nothing to emit as a message to downstream. We definitely talk here about a FileReadingMessageSource. But with DELETE there is nothing to read any more. Am I missing anything?

    And here is what we have in the Docs so far:

    The ENTRY_DELETE events have effect for the ResettableFileListFilter implementations and, therefore, their files are provided for the remove() operation. This means that (when this event is enabled), filters such as the AcceptOnceFileListFilter will have the file removed, meaning that, if a file with the same name appears, it will pass the filter and be sent as a message.

    Therefore to achieve whatever you would like to do in case of DELETE event, you need to implement ResettableFileListFilter and together with SimplePatternFileListFilter you should composite them into the CompositeFileListFilter.

    When file is deleted , that DELETE event is emitted and we end up with the logic like:

    if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
        if (getFilter() instanceof ResettableFileListFilter) {
            ((ResettableFileListFilter<File>) getFilter()).remove(file);
        }
    

    Where the mentioned CompositeFileListFilter definitely implements this ResettableFileListFilter one and will delegate to your own implementation.