Contact Us 1-800-596-4880

Migrating to the FTP and SFTP Connectors

Standard Support for Mule 4.1 ended on November 2, 2020, and this version of Mule reached its End of Life on November 2, 2022, when Extended Support ended.

Deployments of new applications to CloudHub that use this version of Mule are no longer allowed. Only in-place updates to applications are permitted.

MuleSoft recommends that you upgrade to the latest version of Mule 4 that is in Standard Support so that your applications run with the latest fixes and security enhancements.

The FTP and SFTP transports were completely rewritten. They evolved away from the Mule 3 transport model into an operation based connector. This enables many new capabilities:

  • The ability to read files or fully list directory contents on demand, unlike the old transport, which only provided a polling inbound endpoint.

  • Top-level support for common file system operations such as copying, moving, renaming, deleting, creating directories, and more.

  • Support for locking files at the file system level.

  • Advanced file matching functionality.

Furthermore, they were designed to be completely symmetrical. This means that, except for the connection configuration, they look and behave alike and have the exact same feature set. Furthermore, they also match the features and behavior of the File connector.

Connecting to an FTP or SFTP Server

Migrating an FTP Connection

Mule 3 Example: FTP Inbound Connection with Polling
<ftp:inbound-endpoint host="localhost"
 port="21" path="path/to/file"
 user="myusername" password="maypassword"
 pollingFrequency="4000" responseTimeout="10000"  metadata:id="5571009e-a278-4a01-ac1d-4102113b52ad"
 doc:name="FTP">
    <reconnect-forever frequency="3000"/>
</ftp:inbound-endpoint>

This example shows a simple Mule 4 FTP configuration.

Mule 4 Example: FTP Connection
<ftp:config name="ftp">
  <ftp:connection username="anonymous"
   password="password" host="localhost"
   port="${ftpPort}" workingDir="${workingDir}"/>
</ftp:config>

Migrating and SFTP Connection

Mule 3 Example: SFTP Inbound Endpoint
<sftp:inbound-endpoint host="localhost"
 port="22" path="path/to/file"
 user="myuser" password="mypassword"
 responseTimeout="10000"
 pollingFrequency="2000" fileAge="50"
 sizeCheckWaitTime="10" doc:name="SFTP"/>
Mule 4 Example: SFTP Connection Configuration
<sftp:config name="sftp">
  <sftp:connection username="myusername"
   password="mypassword"
   host="localhost"
   port="${sftpPort}"
   workingDir="${workingDir}"/>
</sftp:config>

The SFTP connection also supports a connection through a proxy.

Mule 4 Example: SFTP Connection through a Proxy
<sftp:config name="sftp">
  <sftp:connection username="muletest1" password="muletest1"
   host="127.0.0.100" port="${SFTP_PORT}" workingDir="${workingDir}">
    <sftp:sftp-proxy-config host="localhost" port="${proxyPort}" protocol="HTTP"/>
   </sftp:connection>
</sftp:config>

Migrating an Inbound Endpoint

In Mule 3 a <ftp:inbound-endpoint> and <sftp:inbound-endpoint> message sources were used to poll a directory for files. For each file found, a new message was triggered. The message would hold the file’s content in the payload plus a number of file attributes as system properties. To avoid picking the same files over and over, autoDelete and moveTo parameters were provided, so that the files would leave the polled directory after being picked.

Mule 4 offers an improved way of doing that. The <ftp:listener> and <sftp:listener> components (shown as On New File in the Studio palette) polls a directory and triggers a new message just like its predecessor did. However it has the following added capabilities:

  • You can use a <ftp:matcher> and <sftp:matcher> to only accept files with match a certain criteria

  • You’re no longer forced to either delete or move the file, although the option to do that is still available.

  • You can use any of the connector’s operation to change processed files in such a way that they no longer meet the matching criteria.

  • Watermark is automatically supported, allowing you to optionally filter automatically based on the file’s timestamp.

Mule 3 Example: Inbound endpoint
<flow name="listener">
  <ftp:inbound-endpoint address="ftp://anonymous:password@localhost:${port1}"
    pollingFrequency="1000"/>

  <flow-ref name="processFile" />
</flow>
Mule 4 Example: On New File
<ftp:config name="ftp">
  <ftp:connection host="localhost" user="anonymous" password="password" workingDir="${workingDir}"/>
</file:config>

<flow name="listenWithScheduler" initialState="stopped">
    <ftp:listener config-ref="ftp" directory=".">
      <scheduling-strategy>
        <fixed-frequency frequency="1000"/>
      </scheduling-strategy>
    </file:listener>

    <flow-ref name="processFile" />
</flow>

Migrating an Outbound Endpoint

The Mule 3 transport uses the <ftp:outbound-endpoint> component to write the current payload to a file. The Mule 4 connector uses the <ftp:write> operation instead.

The most important differences are:

  • The <ftp:outbound-endpoint> required the content to be written in the message payload at the moment of execution. The <ftp:write> operation can embed a DataWeave transformation that generates the content to be written.

  • The Mule 3 transport has the outputAppend parameter set at the config level, while the <ftp:write> operation has a mode parameter.

Mule 3 Example: Outbound Endpoint
<ftp:connector name="file" outputAppend="true" />

<flow name="greetings">
  <http:listener path="greet" method="POST"/>
  <set-payload value="Hello #[payload.name]" />
  <ftp:outbound-endpoint path="greet.txt" connector-ref="file" />
</flow>
Mule 4 Example: Write Operation
<flow name="greetings">
  <http:listener path="greet" method="POST"/>
  <ftp:write path="greet.txt" mode="APPEND">
    <ftp:content>#['Hello $(payload.name)']</file:content>
  </file:write>
</flow>

To use FTP in the SFTP connector, simply add it to your application using the Studio palette, or add the following dependency in your pom.xml file:

<dependency>
    <groupId>org.mule.connectors</groupId>
    <artifactId>mule-ftp-connector</artifactId>
    <version>1.1.0</version> <!-- or newer -->
    <classifier>mule-plugin</classifier>
</dependency>

<dependency>
    <groupId>org.mule.connectors</groupId>
    <artifactId>mule-sftp-connector</artifactId>
    <version>1.1.0</version> <!-- or newer -->
    <classifier>mule-plugin</classifier>
</dependency>

SFTP Outbound 'addSeqNo' Duplicate Handling

In Mule 3, using duplicateHandling="addSeqNo" iterates though the file names until an unused index is found.

In Mule 4, you need to replace this with a unique index, for example, through an Object Store or UUID.

Mule 3 Example: Outbound SFTP Endpoint addSeqNo
<flow name="sftpSeqNumberOutbound">
    <sftp:outbound-endpoint
        address="sftp://.../data"
        outputPattern="fileName.dat" duplicateHandling="addSeqNo"/>
</flow>
Mule 4 Example: sftp:write with uuid() in the path
<flow name="sftpSeqNumberOutbound">
    <sftp:write config-ref="sftpConfig" path="#['data/fileName_' ++ uuid() ++ '.dat']"/>
</flow>

Migrating the SFTP tempDir

In Mule 3, the SFTP transport allows for configuration of temporary directories to use when reading or writing files. The properties that allow this are:

  • In the sftp:connector:

    • tempDirInbound

    • tempDirOutbound

    • useTempFileTimestampSuffix

  • In the sftp:inbound-endpoint:

    • tempDir

    • useTempFileTimestampSuffix

  • In the sftp:outbound-endpoint:

    • tempDir

    • useTempFileTimestampSuffix

These configurations are not allowed in the Mule 4 SFTP connector. However, the connector provides the sftp:move operation that you can use to replace this kind of configuration.

Mule 3 Example: Inbound SFTP Endpoint tempDir
<flow name="sftpListener">
    <sftp:inbound-endpoint address="sftp://.../testdir"
        tempDir="tmp_sending" useTempFileTimestampSuffix="true"/>

    ...
</flow>
Mule 4 Example: sftp:move to a Temporary Directory
<flow name="sftpListener">
    <sftp:listener config-ref="sftpConfig" directory="testdir"/>

    <!-- This DataWeave generates the same filename as the Mule 3 transport when using the tempDir attribute -->
    <sftp:move config-ref="sftpConfig" sourcePath="#['testdir/' ++ attributes.name]" targetPath="#['tmp_sending/' ++ joinBy(flatMap(splitBy(attributes.name, '.'), (item, index) -> (if (index == 0) item ++ '_' ++ now() as String{format: 'yyyyMMddHHmmssSSS'} else item)), '.')]"/>
    ...
</flow>

Archiving Files to a Local Drive

In Mule 4, the moveToDirectory attribute on the listener in the SFTP connector only archives to another directory on the SFTP server, not to a local directory.

You can archive files to a local drive by using the Write operation (file:write) in the File connector.

Mule 4 Example: file:write to a Local Directory
<flow>
   <sftp:listener path="/a/b" />
   <file:write path="#['archive/$(attributes.fileName})']" />
   <flow-ref name="theRestOfYourIntegration" />
</flow>