简体   繁体   中英

Citrus Framework - upload file via SFTP using Spring Integration

As part of a Citrus test I'd like to push a CSV file to a server via SFTP. It seems this should be possible using Spring Integration. I've attempted using the code below:

citrus-config.xml

<?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:citrus="http://www.citrusframework.org/schema/config"
       xmlns:citrus-test="http://www.citrusframework.org/schema/testcase"
       xmlns:context="http://www.springframework.org/schema/context"
       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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/integration/sftp http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd
       http://www.citrusframework.org/schema/config http://www.citrusframework.org/schema/config/citrus-config.xsd
       http://www.citrusframework.org/schema/testcase http://www.citrusframework.org/schema/testcase/citrus-testcase.xsd
">

    <!-- Common settings -->
    <context:property-placeholder location="classpath:citrus.properties"/>

    <citrus:schema-repository id="schemaRepository"/>   

    <!-- SFTP component -->
    <bean id="sftpSessionFactory" class="org.springframework.integration.file.remote.session.CachingSessionFactory">
        <constructor-arg ref="defaultSftpSessionFactory" />
    </bean>

    <bean id="defaultSftpSessionFactory"
          class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
        <property name="host" value="${sftp.host}"/>
        <property name="privateKey" value="${sftp.private.keyfile}"/>
        <property name="port" value="${sftp.port}"/>
        <property name="user" value="${sftp.username}"/>
        <property name="allowUnknownKeys" value="true"/>
    </bean>

    <int-sftp:outbound-channel-adapter id="sftpOutboundAdapter"
                                       session-factory="sftpSessionFactory"
                                       channel="inputChannel"
                                       remote-filename-generator-expression="payload.getName()"
                                       remote-directory="/tmp/citrus">
        <int-sftp:request-handler-advice-chain>
            <int:retry-advice />
        </int-sftp:request-handler-advice-chain>
    </int-sftp:outbound-channel-adapter>

    <int:channel id="inputChannel"/>

    <citrus:channel-endpoint id="sftpEndpoint" channel="inputChannel" />
</beans>

SftpTransferIT.java

public class SftpTransferIT extends TestNGCitrusTestDesigner {

    @Autowired
    ChannelEndpoint sftpEndpoint;

    @Test @Parameters("context")
    @CitrusTest(name = "SftpTransferIT.sendFileByFTP")
    public void sendFileByFTP(@Optional @CitrusResource TestContext context) {

        final File file = new File("C:\\Temp\\example.xml");
        final org.springframework.messaging.Message<File> message = MessageBuilder.withPayload(file).build();
        Message ftpMessage = new ChannelMessageConverter().convertInbound(message,sftpEndpoint.getEndpointConfiguration(),context);

        send(sftpEndpoint).message(ftpMessage);

    }
}

The following exception is thrown in this situation:

Caused by: org.springframework.messaging.MessagingException: Failed to write to '/tmp/citrus/example.xml.writing' while uploading the file; nested exception is org.springframework.core.NestedIOException: failed to write file; nested exception is 2: No such file
    at org.springframework.integration.file.remote.RemoteFileTemplate.sendFileToRemoteDirectory(RemoteFileTemplate.java:537)
    at org.springframework.integration.file.remote.RemoteFileTemplate.lambda$send$0(RemoteFileTemplate.java:310)
    ... 69 more
Caused by: org.springframework.core.NestedIOException: failed to write file; nested exception is 2: No such file
    at org.springframework.integration.sftp.session.SftpSession.write(SftpSession.java:158)
    at org.springframework.integration.file.remote.session.CachingSessionFactory$CachedSession.write(CachingSessionFactory.java:228)
    at org.springframework.integration.file.remote.RemoteFileTemplate.sendFileToRemoteDirectory(RemoteFileTemplate.java:509)
    ... 70 more
Caused by: 2: No such file
    at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2873)

I think the error is in how I'm sending the message via Citrus. Can someone please advise on how to send the org.springframework.messaging.Message correctly via Citrus?

Or is it better practice to use pure Spring Integration without Citrus' send() to perform tasks like this?

Try to configure use-temporary-file-name = "false" :

By default, every file that is in the process of being transferred will appear in the file system with an additional suffix which, by default, is .writing; this can be changed using the temporary-file-suffix attribute.

However, there may be situations where you don't want to use this technique (for example, if the server does not permit renaming files). For situations like this, you can disable this feature by setting use-temporary-file-name to false (default is true). When this attribute is false, the file is written with its final name and the consuming application will need some other mechanism to detect that the file is completely uploaded before accessing it.

And be sure that /tmp/citrus really exists on your SFTP.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM