<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>
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
This example shows a simple Mule 4 FTP configuration.
<ftp:config name="ftp">
<ftp:connection username="anonymous"
password="password" host="localhost"
port="${ftpPort}" workingDir="${workingDir}"/>
</ftp:config>
Migrating and SFTP Connection
<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"/>
<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.
<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.
<flow name="listener">
<ftp:inbound-endpoint address="ftp://anonymous:password@localhost:${port1}"
pollingFrequency="1000"/>
<flow-ref name="processFile" />
</flow>
<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 amode
parameter.
<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>
<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.
addSeqNo
<flow name="sftpSeqNumberOutbound">
<sftp:outbound-endpoint
address="sftp://.../data"
outputPattern="fileName.dat" duplicateHandling="addSeqNo"/>
</flow>
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.
tempDir
<flow name="sftpListener">
<sftp:inbound-endpoint address="sftp://.../testdir"
tempDir="tmp_sending" useTempFileTimestampSuffix="true"/>
...
</flow>
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.
file:write
to a Local Directory<flow>
<sftp:listener path="/a/b" />
<file:write path="#['archive/$(attributes.fileName})']" />
<flow-ref name="theRestOfYourIntegration" />
</flow>