Connecting to FTP server with Spring Integration

by Roberto van der LindenJuly 21, 2010

For one of our project I needed to read zip files from a FTP server and import the content in a system. In this post I will explain how I have used the Spring Integration to connect with a FTP server and retrieve Zip files.

FTP Client Factory

As the FTP extension for Spring Integration has no official release yet, I have used the latest build which can be found at the Spring Integration Adapters site.

The extension provides a client factory that allows you to connect with a client. The class I have used is the DefaultFTPClientFactory which implements the interface FTPClientFactory.

When you have copied these files to your own project, you can configure a client by using the following code:

    <bean id="defaultClient" class="nl.jteam.importer.ftp.DefaultFTPClientFactory">
        <property value="${ftp.remotedir}" name="remoteWorkingDirectory"></property>
        <property value="${ftp.username}" name="username"></property>
        <property value="${ftp.password}" name="password"></property>
        <property value="${ftp.port}" name="port"></property>
        <property value="${ftp.host}" name="host"></property>
    </bean>

Reading the files

Now that the client is configured, we can read the files from the FTP server. In the method getFilesFromFTPClient() we get a FTPClient by calling the getClient() method on the client factory. The client API provides you with the possibility to retrieve, delete, rename or store files. The API offers a lot more, but I won’t discuss all the methods here. In our case we wanted to retrieve only zip files. As the client does not provide you the functionality to retrieve files from a specific extension, you have to do it yourself by, for example, checking the extension of each file.

Don’t forget to close the connection with the FTP client once you are done with handling files.

Because we want use Spring Integration to send the files to the class that handles the zip files, we create a Message with the list of zip files.

The (partial) code of the FTPInboundAdapter class:

    public FTPInboundAdapter(FTPClientFactory clientFactory, String localTmpDirName) throws IOException {
        Assert.notNull(localTmpDirName, "The directory name to write the files to can not be null");
        this.clientFactory = clientFactory;
        localDirectory = ImportUtils.ensureTempDirExists(localTmpDirName);
    }

    public Message<list><file>&gt; getFilesFromFTPClient() {
        FTPClient client = null;
        try {
            client = clientFactory.getClient();

            List<file> localZipFiles = retrieveRemoteZipFiles(client);

            return MessageBuilder.withPayload(localZipFiles).build();
        } catch (IOException e) {
            throw new MessagingException("Problem occurred while trying to retrieve files.", e);
        } finally {
            closeFtpClient(client);
        }
    }

    private void closeFtpClient(FTPClient client) {
        if (client != null &amp;&amp; client.isConnected()) {
            try {
                client.disconnect();
            } catch (IOException e) {
                logger.warn("Error occurred when disconnection FTP client", e);
            }
        }
    }

The configuration code for the adapter:

    <bean id="ftpInboundAdapter" class="nl.jteam.importer.ftp.FTPInboundAdapter">
        <constructor-arg ref="defaultClient" />
        <constructor-arg value="someLocalDirectory" />
    </bean>

Checking the FTP directory

If you want Spring Integration to check the FTP server on a regular base for new files, you can wire up an inbound channel adapter with a cron expression like this:

    <si:inbound-channel-adapter id="zipInboundChannelAdapter" ref="ftpInboundAdapter" method="getFilesFromFTPClient" channel="zipFilesChannel">
        <si:poller max-messages-per-poll="1">
            <si:cron-trigger expression="0 0/5 * ? * *" />
        </si:poller>
    </si:inbound-channel-adapter>

The channel attribute of the inbound channel adapter specifies the output channel. So in our case this will be the message with the list of zip files that is put onto this channel. This channel can then be used to send the message to wherever you want.

As you could see, it was relatively easy to connect with a FTP server and retrieve the files. I hope this post helped you in setting up your own FTP connection with Spring Integration. All that rests us is waiting for official release of the Spring Integration Adapters.