This example will demonstrate how to use Spring Integration for downloading files from a remote SFTP server. Two possible authentications could be used, i.e. public key or password.
Technologies used:
Spring Boot 2.0.4.RELEASE
Spring Integration 5.0.7.RELEASE (managed by Spring Boot)
Spring 5.0.8.RELEASE (managed by Spring Boot)
Quick overview:
Create SFTP Session Factory, i.e. DefaultSftpSessionFactory
Create and set up InboundChannelAdapter to regularly check a remote SFTP server for new files
Create MessageHandler to process incoming files
Project Structure
A final project directory structure
SftpConfig using Java Configuration
We have to configure SFTP Session Factory (DefaultSftpSessionFactory) with all required parameters, i.e. host, IP port, username and password (or private key with a passphrase). The same configuration was already used in the SFTP Upload Example.
After that, we have to create a MessageSource<File> bean and define it as a @InboundChannelAdapter. This component is responsible for regularly checking a remote SFTP server whether a new file exists. A regular period defines annotation @Poller inside definition of InboundChannelAdapter (Poller is defined by the cron expression).
Then, we need to create an instance of a SftpInboundFileSynchronizer (will be used by @InboundChannelAdapter), which defines a strategy of a synchronization mechanism, i.e. we are able to set remote filename filters (sftpRemoteDirectoryDownloadFilter), a remote directory path (sftpRemoteDirectoryDownload) or whether a remote file should be deleted after a successful transfer.
The last important bean is related to a general MessageHandler bean used as a @ServiceActivator. The MessageHandler processes incoming files.
I have used Spring Boot in my example, so annotation @SpringBootApplication is obvious. The more interesting annotation is @IntegrationComponentScan and @EnableIntegration which will enable all other configurations used in the previous configuration file.
Here you can see a basic use case. I have created an integration test using a real SFTP server with enabled public key authentication (i.e. without password). This test starts an asynchronous thread to check an existence of a downloaded file.
@RunWith(SpringRunner.class)@SpringBootTest@TestPropertySource(properties={"sftp.port = 10022","sftp.remote.directory.download.filter=*.xxx"})publicclassSpringSftpDownloadDemoApplicationTests{privatestaticEmbeddedSftpServerserver;privatestaticPathsftpFolder;@Value("${sftp.local.directory.download}")privateStringlocalDirectoryDownload;@BeforeClasspublicstaticvoidstartServer()throwsException{server=newEmbeddedSftpServer();server.setPort(10022);sftpFolder=Files.createTempDirectory("SFTP_DOWNLOAD_TEST");server.afterPropertiesSet();server.setHomeFolder(sftpFolder);// Starting SFTP
if(!server.isRunning()){server.start();}}@Before@Afterpublicvoidclean()throwsIOException{Files.walk(Paths.get(localDirectoryDownload)).filter(Files::isRegularFile).map(Path::toFile).forEach(File::delete);}@TestpublicvoidtestDownload()throwsIOException,InterruptedException,ExecutionException,TimeoutException{// Prepare phase
PathtempFile=Files.createTempFile(sftpFolder,"TEST_DOWNLOAD_",".xxx");// Run async task to wait for expected files to be downloaded to a file
// system from a remote SFTP server
Future<Boolean>future=Executors.newSingleThreadExecutor().submit(newCallable<Boolean>(){@OverridepublicBooleancall()throwsException{PathexpectedFile=Paths.get(localDirectoryDownload).resolve(tempFile.getFileName());while(!Files.exists(expectedFile)){Thread.sleep(200);}returntrue;}});// Validation phase
assertTrue(future.get(10,TimeUnit.SECONDS));assertTrue(Files.notExists(tempFile));}@AfterClasspublicstaticvoidstopServer(){if(server.isRunning()){server.stop();}}}
The source code of this project could be found on my public Github profile.