I'm trying to move files on remote SFTP once the batch has successfully processed the files using Spring integration and Java DSL.
What would be the best way to achieve that?
- Adding a step in batch to move remote files ?
- Or using FTP Outbound Gateway and provide the MV command ?
I tend to prefer the second solution and let the batch focus on the logic only, but I've hard times trying to implement it with java dsl.
I've read http://docs.spring.io/spring-integration/reference/html/ftp.html#ftp-outbound-gateway and tried to implement like that :
@Bean
public MessageHandler ftpOutboundGateway() {
return Sftp.outboundGateway(SftpSessionFactory(),
AbstractRemoteFileOutboundGateway.Command.MV, "payload")
.localDirectory(new File("/home/blabla/"))
.get();
}
@Bean
public IntegrationFlow ftpInboundFlow() {
return IntegrationFlows
.from(
Sftp.inboundAdapter(SftpSessionFactory())
.regexFilter(".*\\.xml.mini$")
...
,
e -> e.id("sftpInboundAdapter")
.poller(
Pollers.fixedRate(intCfg.getSftpPollerInMinutes(), TimeUnit.MINUTES)
.maxMessagesPerPoll(-1)
.advice(retryAdvice())
)
)
.enrichHeaders( h -> h
.header(FileHeaders.REMOTE_DIRECTORY,"/home/filedrop/")
.header(FileHeaders.REMOTE_FILE, "/home/filedrop/OFFERS.xml.mini")
.header(FileHeaders.RENAME_TO, "/home/filedrop/done/OFFERS.xml.mini")
)
.transform(fileToJobLaunchRequestTransformer())
.handle(jobLaunchingGw()))
.transform(jobExecutionToFileStringTransformer())
.handle(ftpOutboundGateway())
.handle(logger())
.get();
}
I know my headers should be dynamic but I don't know how to do it so for now I use the name of an existing file. I get this error message (he's trying to delete the file in the destination directory!):
Caused by: org.springframework.messaging.MessagingException: Failed to execute on session; nested exception is org.springframework.core.NestedIOException: Failed to delete file /home/filedrop/done/OFFERS.xml.mini; nested exception is org.springframework.core.NestedIOException: Failed to remove file: 2: No such file at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:343)
at org.springframework.integration.file.remote.RemoteFileTemplate.rename(RemoteFileTemplate.java:290)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.doMv(AbstractRemoteFileOutboundGateway.java:482)
at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.handleRequestMessage(AbstractRemoteFileOutboundGateway.java:400)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:99)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
... 94 more
Caused by: org.springframework.core.NestedIOException: Failed to delete file /home/filedrop/done/OFFERS.xml.mini; nested exception is org.springframework.core.NestedIOException: Failed to remove file: 2: No such file
at org.springframework.integration.sftp.session.SftpSession.rename(SftpSession.java:211)
at org.springframework.integration.file.remote.RemoteFileTemplate$3.doInSessionWithoutResult(RemoteFileTemplate.java:300)
at org.springframework.integration.file.remote.SessionCallbackWithoutResult.doInSession(SessionCallbackWithoutResult.java:34)
at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:334)
... 100 more
Caused by: org.springframework.core.NestedIOException: Failed to remove file: 2: No such file
at org.springframework.integration.sftp.session.SftpSession.remove(SftpSession.java:83)
at org.springframework.integration.sftp.session.SftpSession.rename(SftpSession.java:205)
... 103 more
Thanks for any help!
EDIT working flow, I've then simplified it a lot but here the solution of myprevious problem:
@Bean
public IntegrationFlow ftpInboundFlow() {
return IntegrationFlows
.from(
Sftp.inboundAdapter(SftpSessionFactory())
.regexFilter(".*\\.xml$")
...
,
e -> e.id("sftpInboundAdapter")
.poller(Pollers.fixedRate(intCfg.getSftpPollerInMinutes(), TimeUnit.MINUTES)
.maxMessagesPerPoll(-1)
)
)
.enrichHeaders( h -> h
// headers necessary for moving remote files (ftpOutboundGateway)
.headerExpression(FileHeaders.RENAME_TO, "'/home/blabla/done/' + payload.getName()")
.headerExpression(FileHeaders.REMOTE_FILE, "payload.getName()")
.header(FileHeaders.REMOTE_DIRECTORY,"/home/blabla/")
// headers necessary for moving local files (fileOutboundGateway_MoveToProcessedDirectory)
.headerExpression(FileHeaders.ORIGINAL_FILE, "payload.getAbsolutePath()" )
.headerExpression(FileHeaders.FILENAME, "payload.getName()")
)
.transform(fileToJobLaunchRequestTransformer())
.handle(jobLaunchingGw(), e-> e.advice(retryAdvice()))
.<JobExecution, Boolean>route(p -> BatchStatus.COMPLETED.equals(p.getStatus()),
mapping -> mapping
.subFlowMapping("true", sf -> sf
.handle(org.springframework.batch.core.JobExecution.class,
(p, h) -> myServiceActivator.jobExecutionToString(p,
(String) h.get(FileHeaders.REMOTE_DIRECTORY),
(String) h.get(FileHeaders.REMOTE_FILE)))
.handle(ftpOutboundGateway())
.handle(Boolean.class,
(p, h) -> myServiceActivator.BooleanToString(p,
(String) h.get(FileHeaders.FILENAME)))
.handle(fileOutboundGateway_MoveToProcessedDirectory())
)
.subFlowMapping("false", sf -> sf
.channel("nullChannel")
)
)
.handle(logger())
.get();
}
@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata poller() {
return Pollers.fixedRate(500).get();
}
@Bean
public MessageHandler ftpOutboundGateway() {
return Sftp
.outboundGateway(SftpSessionFactory(),
AbstractRemoteFileOutboundGateway.Command.MV,
"payload")
.renameExpression("headers['file_renameTo']").get();
}