Can I provide a custom FileLocker for a FileWritingMessageHandler?

91 views Asked by At

I am using a FileReadingMessageSource with a custom FileLocker:

@Component
public class JdbcFileLocker implements FileLocker {
...
@Autowired
JdbcFileLocker jdbcFileLocker;

@Bean
@InboundChannelAdapter(value = "fileInputChannel", poller = @Poller(fixedDelay = "1000"))
public MessageSource<File> fileReadingMessageSource() {
    FileReadingMessageSource source = new FileReadingMessageSource();
    source.setDirectory(new File("/workspace/in"));
    source.setFilter(new SimplePatternFileListFilter("input"));
    source.getScanner().setLocker(jdbcFileLocker);
    return source;
}

Now I want to use the FileLocker jdbcFileLocker to unlock the file after handling it in the FileWritingMessageHandler:

@Bean
@ServiceActivator(inputChannel = "fileInputChannel")
  public MessageHandler fileWritingMessageHandler() {
    FileWritingMessageHandler fileWritingMessageHandler = 
      new FileWritingMessageHandler(new File("/workspace/out"));

Do I have to unlock the file in my own @ServiceActivator or can I give my FileLocker somehow to the FileWritingMessageHandler?


EDIT: Adding an ExpressionEvaluatingRequestHandlerAdvice

@Bean
ExpressionEvaluatingRequestHandlerAdvice unlockAdvice() {
  ExpressionEvaluatingRequestHandlerAdvice advice = 
    new ExpressionEvaluatingRequestHandlerAdvice();
  advice.setSuccessChannel(unlockChannel);
  return advice;
}

So I can add this Advice to my FileWritingMessageHandler:

@Autowired
ExpressionEvaluatingRequestHandlerAdvice unlockAdvice;

@Bean
@ServiceActivator(inputChannel = "fileInputChannel")
public MessageHandler fileWritingMessageHandler() {
  FileWritingMessageHandler handler = 
    new FileWritingMessageHandler(new File("/workspace/out"));
  handler.setFileExistsMode(FileExistsMode.REPLACE);
  handler.setDeleteSourceFiles(true);
  handler.setExpectReply(false);
  handler.setFileNameGenerator(message -> "output");
  handler.setAdviceChain(List.of(unlockAdvice));
  return handler;
}

The unlocking is then handled by a @ServiceActivator listening to the unlockChannel.

1

There are 1 answers

1
Artem Bilan On BEST ANSWER

First of all consider to use fileWritingMessageHandler.setExpectReply(false). Since by default a FileWritingMessageHandler behaves as a gateway and is going to try to produce a reply which is not handled in your flow and therefore some error is going to be thrown to your poller.

For your FileLocker use-case see an ExpressionEvaluatingRequestHandlerAdvice on your fileWritingMessageHandler service activator. Its onSuccessExpression could do an unlocking which is really going to be done after the FileWritingMessageHandler finishes its process. See docs for more info: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#message-handler-advice-chain

Another is to have a fileInputChannel as a PublishSubscribeChannel without changing a configuration for the current fileWritingMessageHandler. But you add another service activator subscriber to that channel which is going to perform FileLocker.unlock() logic. To ensure that second subscriber is called after the first, consider to add an @Order(100) for your unlocker service activator. Also see docs: https://docs.spring.io/spring-integration/docs/current/reference/html/core.html#channel-implementations-publishsubscribechannel