Search code examples
springspring-bootspring-integrationspring-integration-dsl

Spring integration - Use afterCommit expression to write file to a processed directory


My spring integration application reads files from a fileshare, does some processing including api calls etc. In case something goes wrong in between I would like to use a afterRollbakExpression to write the file to a failed directory in the file share/ftp/sftp etc.

I found an example of doing the same to a local file directory as follows,

@Bean
TransactionSynchronizationFactory transactionSynchronizationFactory() {
    ExpressionParser parser = new SpelExpressionParser();
    ExpressionEvaluatingTransactionSynchronizationProcessor syncProcessor =
            new ExpressionEvaluatingTransactionSynchronizationProcessor();
    syncProcessor.setBeanFactory(applicationContext.getAutowireCapableBeanFactory());
    //afterCommit expression moves the file to a processed directory
    syncProcessor.setAfterCommitExpression(parser.parseExpression("payload.renameTo(new java.io.File(@inboundProcessedDirectory.path "
            + " + T(java.io.File).separator + payload.name))"));
    //afterRollback expression moves the file to a failed directory
    syncProcessor.setAfterRollbackExpression(parser.parseExpression("payload.renameTo(new java.io.File(@inboundFailedDirectory.path "
            + " + T(java.io.File).separator + payload.name))"));
    return new DefaultTransactionSynchronizationFactory(syncProcessor);
}

I would like to do the same thing but write the file to the fileshare/ftp/sftp during a rollback scenario and not to a local directory.

I have a messageHandler which I invoke to write files using the integration flow to the smb fileshare. I dont know how do i invoke the following messagehandler as a AfterRollbackExpression,

@Bean(name = SMB_FILE_ERROR_MESSAGE_HANDLER)
public MessageHandler smbMessageHandler() {
    FileTransferringMessageHandler<SmbFile> handler =
            new FileTransferringMessageHandler<>(smbSessionFactory);
    handler.setRemoteDirectoryExpression(
            new LiteralExpression("/INPUT/ERROR"));
    handler.setFileNameGenerator(m ->
            m.getHeaders().get(FileHeaders.FILENAME, String.class) + "." + DateTimeFormatter.ofPattern(dateFormat).format(LocalDateTime.now()));
    handler.setAutoCreateDirectory(true);
    return handler;
}

Solution

  • You just mark that smbMessageHandler bean with the @ServiceActivator(inputChannel = "smbStoreChannel") and this ExpressionEvaluatingTransactionSynchronizationProcessor may just have a setAfterRollbackChannel(smbStoreChannel). So, when rollback happens a failed message is going to be sent to that channel where your FileTransferringMessageHandler will consume it from the channel and probably send to SMB. Consider also to use a TransactionSynchronizationFactoryBean for convenience.