Search code examples
javaspringspring-integrationsftpspring-integration-sftp

Copy and move a file from SFTP using Java config in Spring Integration


I am new to Spring integration. I've this requirement to first move a file from /files folder to /process folder in SFTP location and then copy that file to local. I am suggested to use gateway and configuration has to be in java using annotations. I have tried seeking for answers here on stackoverflow but couldn't find something relevant. However I was able to copy the file using @InboundChannelAdapter and by configuring other beans.

Below is the code I have written so far

Configuration public class SftpConfiguration {

@Value("${ftp.file.host}")
private String host;

@Value("${ftp.file.port")
private int port;

@Value("${ftp.file.user")
private String user;

@Value("${ftp.file.password")
private String password;

@Value("${directorry.file.remote")
private String remoteDir;

@Value("${directorry.file.in.pollerDelay")
final private String pollerDelay = "1000";

@Value("${directory.file.remote.move}")
private String toMoveDirectory;

@Bean
public SessionFactory<LsEntry> sftpSessionFactory() {
    DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
    factory.setHost(host);
    factory.setPort(port);
    factory.setUser(user);
    factory.setPassword(password);
    factory.setAllowUnknownKeys(true);
    return new CachingSessionFactory<LsEntry>(factory);
}

@Bean
public SftpInboundFileSynchronizer sftpInboundFileSynchronizer() {
    SftpInboundFileSynchronizer fileSynchronizer = new SftpInboundFileSynchronizer(sftpSessionFactory());
    fileSynchronizer.setDeleteRemoteFiles(false);
    fileSynchronizer.setRemoteDirectory(remoteDir);
    fileSynchronizer.setFilter(new SftpSimplePatternFileListFilter("*.xlsx"));
    return fileSynchronizer;
}

@Bean
@InboundChannelAdapter(channel = "sftpChannel", poller = @Poller(fixedDelay = pollerDelay))
public MessageSource<File> sftpMessageSource() {
    SftpInboundFileSynchronizingMessageSource source = new SftpInboundFileSynchronizingMessageSource(
            sftpInboundFileSynchronizer());
    source.setLocalDirectory(new File("ftp-inbound"));
    source.setAutoCreateLocalDirectory(true);
    source.setLocalFilter(new AcceptOnceFileListFilter<File>());

    return source;
}

@Bean
@ServiceActivator(inputChannel = "sftpChannel")
public MessageHandler handler() {
    return new MessageHandler() {

        @Override
        public void handleMessage(Message<?> message) throws MessagingException {
            try {
                new FtpOrderRequestHandler().handle((File) message.getPayload());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    };
}

@Bean
@ServiceActivator(inputChannel = "sftpChannel")
public MessageHandler handlerOut() {
    return new SftpOutboundGateway(sftpSessionFactory(), "mv", toMoveDirectory);
}

}

I will appreciate any tips or suggestion . Thanks.


Solution

  • I tried and the following worked for me.

    @Configuration
    @EnableIntegration
    public class SftpConfiguration {
    
        @Value("${config.adapter.ftp.host}")
        private String host;
    
        @Value("${config.adapter.ftp.port}")
        private int port;
    
        @Value("${config.adapter.ftp.user}")
        private String user;
    
        @Value("${config.adapter.ftp.password}")
        private String password;
    
        @Autowired
        private FtpOrderRequestHandler handler;
    
        @Autowired
        ConfigurableApplicationContext context;
    
        @Value("${config.adapter.ftp.excel.sourceFolder}")
        private String sourceDir;
    
        @Value("${config.adapter.ftp.excel.localFolder}")
        private String localDir;
    
        @Value("${config.adapter.ftp.excel.backupFolder}")
        private String backupDir;
    
        @Value("${config.adapter.ftp.statusExcel.destinationFolder}")
        private String statusDest;
    
        private static final Logger LOGGER = LoggerFactory.getLogger(SftpConfiguration.class);
    
    
        @Bean
        public SessionFactory<LsEntry> sftpSessionFactory() {
            DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
            factory.setHost(host);
            factory.setPort(port);
            factory.setUser(user);
            factory.setPassword(password);
            factory.setAllowUnknownKeys(true);
            return new CachingSessionFactory<LsEntry>(factory);
        }
    
        @Bean
        public SftpInboundFileSynchronizer sftpInboundFileSynchronizer() {
            SftpInboundFileSynchronizer fileSynchronizer = new SftpInboundFileSynchronizer(sftpSessionFactory());
            fileSynchronizer.setDeleteRemoteFiles(true);
            fileSynchronizer.setRemoteDirectory(sourceDir);
            fileSynchronizer.setFilter(new SftpSimplePatternFileListFilter("*.xlsx"));
            return fileSynchronizer;
        }
    
        @Bean
        @InboundChannelAdapter(channel = "sftpChannel", poller = @Poller(cron = "${config.cron.cataligent.order}"), autoStartup = "true")
        public MessageSource<File> sftpMessageSource() {
            SftpInboundFileSynchronizingMessageSource source = new SftpInboundFileSynchronizingMessageSource(
                    sftpInboundFileSynchronizer());
            source.setLocalDirectory(new File(localDir));
            source.setAutoCreateLocalDirectory(true);
            source.setLocalFilter(new AcceptOnceFileListFilter<File>());
            return source;
        }
    
    
        @Bean
        @ServiceActivator(inputChannel = "sftpChannel")
        public MessageHandler handlerOrder() {
            return new MessageHandler() {
                @Override
                public void handleMessage(Message<?> message) throws MessagingException {
                    try {
                        SFTPGateway gateway = context.getBean(SFTPGateway.class);
                        final File orderFile = (File) message.getPayload();
                        gateway.sendToSftp(orderFile);
                        LOGGER.debug("{} is picked by scheduler and moved to {} folder",orderFile.getName(),backupDir);
                        handler.handle((File) message.getPayload());
                        handler.deleteFileFromLocal((File) message.getPayload());
                        LOGGER.info("Processing of file {} is completed",orderFile.getName());
                    } catch (IOException e) {
                        LOGGER.error("Error occurred while processing order file exception is {}",e.getMessage());
                    }
                }
    
            };
        }
    
        @Bean
        @ServiceActivator(inputChannel = "sftpChannelDest")
        public MessageHandler handlerOrderBackUp() {
            SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
            handler.setRemoteDirectoryExpression(new LiteralExpression(backupDir));
            return handler;
        }
    
        @Bean
        @ServiceActivator(inputChannel = "sftpChannelStatus")
        public MessageHandler handlerOrderStatusUS() {
            SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
            handler.setRemoteDirectoryExpression(new LiteralExpression(statusDest));
            return handler;
        }
    
    
    
        @MessagingGateway
        public interface SFTPGateway {
            @Gateway(requestChannel = "sftpChannelDest")
            void sendToSftp(File file);
    
            @Gateway(requestChannel = "sftpChannelStatus")
            void sendToSftpOrderStatus(File file);
    
        }
    
    }
    

    I have used this for picking up a file from SFTP location. Saving it at local. Then moving the file to backup folder and then processing the whole file. After processing deleted the file from the local.

    I have used gateway(@MessagingGateway) for file movement and I have two different methods in that interface. One for moving the same file to backup folder and other method is to move another file(a status file) in my code to desired SFTP location. I've tried to keep the code clean for better understanding.