user55926
user55926

Reputation: 315

How to validate the checksum of the file downloaded using Spring SFTP

In our application there are huge number of files downloaded from remote machine to local machine (server where code is running). We have opted to use Spring SFTP to do the download. Using below code I am able to download file from remote machine to local.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-sftp="http://www.springframework.org/schema/integration/sftp"
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd">

<import resource="SftpSampleCommon.xml"/>

<int:gateway id="downloadGateway" service-interface="com.rizwan.test.sftp_outbound_gateway.DownloadRemoteFileGateway"
    default-request-channel="toGet"/>

<int-sftp:outbound-gateway id="gatewayGet"
    local-directory="C:\Users\503017993\Perforce\rizwan.shaikh1_G7LGTPC2E_7419\NGI\DEV\Jetstream_Branches\C360_Falcon2_1_Main\sftp-outbound-gateway"
    session-factory="sftpSessionFactory"
    request-channel="toGet"
    remote-directory="/si.sftp.sample"
    command="get"
    command-options="-P"
    expression="payload"
    auto-create-local-directory="true"
    session-callback="downloadCallback">
    <int-sftp:request-handler-advice-chain>
        <int:retry-advice />
    </int-sftp:request-handler-advice-chain>
</int-sftp:outbound-gateway>
<!-- reply-channel="toRm" -->

<int:gateway id="deleteGateway" service-interface="com.rizwan.test.sftp_outbound_gateway.DeleteRemoteFileGateway"
    default-request-channel="toRm"/>

<int-sftp:outbound-gateway id="gatewayRM" 
    session-factory="sftpSessionFactory"
    expression="payload"
    request-channel="toRm"
    command="rm">
    <int-sftp:request-handler-advice-chain>
        <int:retry-advice />
    </int-sftp:request-handler-advice-chain>
</int-sftp:outbound-gateway>

</beans>

Java code

ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
            "classpath:/META-INF/spring-context.xml");
DownloadRemoteFileGateway downloadGateway = ctx.getBean(DownloadRemoteFileGateway.class);
DeleteRemoteFileGateway deleteGateway = ctx.getBean(DeleteRemoteFileGateway.class);
String downloadedFilePath = downloadGateway.downloadRemoteFile("si.sftp.sample/2ftptest");
System.out.println("downloadedFilePath: " + downloadedFilePath);

Boolean status = deleteGateway.deleteRemoteFile("si.sftp.sample/2ftptest");
System.out.println("deletion status: " + status);

Above code works as expected. It downloads the remote file and then deletes it. We already have checksum of the downloaded file with us. This checksum is calculated from the remote file. Is it possible to build a mechanism to calculate the checksum of the file after it is downloaded. We need to be able to compare expected checksum with checksum of file received and retry fixed number of times if there is a mismatch.

I am wondering if I can use RetryTemplate like below. It is untested pseudo code.

class Test {

    @Autowired
    DownloadRemoteFileGateway downloadGateway;

    public void init() {
        RetryTemplate template = new RetryTemplate();
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        backOffPolicy.setInitialInterval(Long.parseLong(initialInterval));
        backOffPolicy.setMaxInterval(Long.parseLong(initialInterval));
        template.setRetryPolicy(new SimpleRetryPolicy(Integer.parseInt(maxAttempts), exceptionMap));
        template.setBackOffPolicy(backOffPolicy);
    }

    void foo(){
        Object result = template.execute(new RetryCallback() {

        @Override
        public String doWithRetry(RetryContext retryContext) throws Exception {
            //Calculate received file checksum and compare with expected checksum
            if(mismatch) {
                downloadGateway.downloadRemoteFile(remoteFileName);
            }

        }, new RecoveryCallback() {
            //same logic
        });
    }//foo
}//Test

My question is how do I make my method foo() execute after file download completes. Is it also possible to get downloaded filename in foo().

Upvotes: 1

Views: 1262

Answers (1)

Artem Bilan
Artem Bilan

Reputation: 121212

I think what you need definitely can be done with AOP Advices. More over with the chain of them, where indeed the RequestHandlerRetryAdvice should be first to start a retry loop. The next Advice I would suggest to use as ExpressionEvaluatingRequestHandlerAdvice with its onSuccessExpression and propagateOnSuccessEvaluationFailures = true combination. This way you perform that checksum validation in the onSuccessExpression and if it doesn't match, throw an exception. That exception is going to be caught by the previous in stack RequestHandlerRetryAdvice and the retry logic will be performed.

See their JavaDocs and Reference Manual on the matter.

Also we have some Sample project to understand things better.

Upvotes: 1

Related Questions