WatchEventType.DELETE не работает

То, что я хотел бы сделать, это отслеживать удаленные файлы и применять определенную логику вокруг этого (получить идентификатор и обновить сущности). Я обнаружил, что мы можем передать список событий наблюдения внутри адаптера канала, включая

FileReadingMessageSource.WatchEventType.DELETE

но когда я удаляю файл из папки, я не вижу никаких сработавших событий, и преобразователь никогда не применяется

@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)
            ));
}

2 ответа

Решение

Я бы сказал, что вы относитесь к DELETE Неправильный путь:

/**
 * 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);

Так что уже нет ничего, что можно было бы выбросить в качестве сообщения для нижестоящих. Мы определенно поговорим здесь о FileReadingMessageSource, Но с DELETE читать больше нечего. Я что-то пропустил?

И вот что мы имеем в Документах:

ENTRY_DELETE события влияют на ResettableFileListFilter реализации и, следовательно, их файлы предоставляются для remove() операция. Это означает, что (когда это событие включено), фильтры, такие как AcceptOnceFileListFilter удалит файл, а это означает, что, если появится файл с таким же именем, он пройдет фильтр и будет отправлен как сообщение.

Поэтому добиться того, что вы хотели бы сделать в случае DELETE событие, вам нужно реализовать ResettableFileListFilter и вместе с SimplePatternFileListFilter вы должны объединить их в CompositeFileListFilter,

Когда файл удален, это DELETE событие генерируется, и мы получаем логику

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

Где упомянутое CompositeFileListFilter определенно реализует это ResettableFileListFilter один и делегировать к вашей собственной реализации.

Спасибо за @Artem, вот полный пример кода, который мне подходит

    private IntegrationFlowBuilder integrationFlowBuilder() {

    final List<FileListFilter<File>> defaultFilters = new ArrayList<>(2);

    defaultFilters.add(new IgnoreHiddenFileListFilter());
    defaultFilters.add(new AcceptOnceFileListFilter<>());
    defaultFilters.add(new SimplePatternFileListFilter("*.xml"));
    defaultFilters.add(myCustomRemovalFilter);

    CompositeFileListFilter fileListFilter = new CompositeFileListFilter<>(defaultFilters);

    return IntegrationFlows.from(

            Files.inboundAdapter(new File(localFilmFolder))
                    .autoCreateDirectory(true)
                    .filter(fileListFilter)
                    .useWatchService(true)
                    .watchEvents(FileReadingMessageSource.WatchEventType.CREATE, FileReadingMessageSource.WatchEventType.DELETE),

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

и фильтр выглядит

@Component
public class MyCustomRemovalFilter implements ResettableFileListFilter<File> {

private static final Logger LOGGER = LogManager.getLogger(MyCustomRemovalFilter.class);

@Override
public boolean remove(File xmlFile) {

    if (xmlFile == null) {
        return true;
    }
    // TODO you own on removal logic 
}

@Override
public List<File> filterFiles(File[] files) {

    if (files == null || files.length == 0) {
        return Collections.emptyList();
    }
    return Arrays.asList(files);
}
}
Другие вопросы по тегам