This component provides access to remote file systems over the FTP and SFTP protocols.
ftp://[username@]hostname[:port]/filename[?options] sftp://[username@]hostname[:port]/filename[?options]
Where filename represents the underlying file name or directory. Can contain nested folders. The username is currently only possible to provide in the hostname parameter.
If no username is provided then
anonymous
login is attempted using no password. If no port number is provided. FUSE Mediation Router will provide
default values according to the protocol. (ftp = 21, sftp = 22)
![]() | FUSE Mediation Router 2.x |
---|---|
See FTP2 as the File component in FUSE Mediation Router 2.x has been greatly enhanced, and has a lot of changes and new features. |
ftp://[email protected]/public/upload/images/holiday2008?password=secret&binary=true
ftp://[email protected]:12049/reports/2008/budget.txt?password=secret&binary=false&directory=false
ftp://publicftpserver.com/download
![]() | Timestamp |
---|---|
In FUSE Mediation Router 1.4 or older the FTP consumer uses an internal timestamp for last polling. This timestamp is used to match for new remote files: if remote file modified timestamp > last poll timestamp => file can be consumed. In FUSE Mediation Router 1.5 this algorithm has been disabled by default as its not reliable over the FTP protocol. FTP Servers only return file modified timestamps using HH:mm (not seconds). And of course the clocks between the client and server can also be out of sync. Bottom line is that timestamp check for FTP protocol should not be used. That is why this feature is marked as @deprecated and will be removed in FUSE Mediation Router 2.0. We encourage you to use a different strategy for matching new remote files: such as deleting or moving the file after download. |
Name | Default Value | Description |
---|---|---|
directory | true | indicates whether or not the given file name should be interpreted by default as a directory or file (as it sometimes hard to be sure with some FTP servers) |
password | null | specifies the password to use to login to the remote file system |
binary | false | specifies the file transfer mode BINARY or ASCII. Default is ASCII. |
ftpClientConfig | null | FUSE Mediation Router 1.5: Reference to a bean in the registry as a
org.apache.commons.net.ftp.FTPClientConfig class. Use
this option if you need to configure the client according to the FTP Server date
format, locale, timezone, platform etc. See the javadoc FTPClientConfig for more documentation. |
consumer.recursive | true/false | if a directory, will look for changes in files in all the sub directories. Is true as default for FUSE Mediation Router 1.4 or older. Will change to false as default value as of FUSE Mediation Router 1.5 |
consumer.setNames | true |
@deprecated Used by FTPConsumer. If true FUSE
Mediation Router will use the filename the file has on the FTP server. The
filename is stored on the IN message in the header
FileComponent.HEADER_FILE_NAME . Note: In FUSE Mediation Router 1.4 the default value has changed
to true. |
consumer.delay | 500 | Delay in millis between each poll |
consumer.initialDelay | 1000 | Millis before polling starts |
consumer.userFixedDelay | false | true to use fixed delay between pools, otherwise fixed rate is used. See ScheduledExecutorService in JDK for details. |
consumer.regexPattern | null | Used by FTPConsumer. Regular expression to use for matching files when consuming. |
consumer.exclusiveReadLock | false | FUSE Mediation Router 1.5: Used by FTPConsumer. If set to true FUSE Mediation Router will only poll the ftp files if it has exclusive read to the file (= the file is not in progress of being written). FUSE Mediation Router will wait until it is granted, testing once every second. The test is implemented by FUSE Mediation Router will try to rename the file. Setting to false FUSE Mediation Router will poll the file even if its in progress of being written. |
consumer.deleteFile | false | FUSE Mediation Router 1.5: Used by FTPConsumer. Flag to set if the consumed file should be deleted after it has been downloaded. |
consumer.moveNamePrefix | null | FUSE Mediation Router 1.5: Used by FTPConsumer. The prefix String perpended to the filename when moving it. For example to move processed files into the done directory, set this value to 'done/' |
consumer.moveNamePostfix | null | FUSE Mediation Router 1.5: Used by FTPConsumer. The postfix String appended to the filename when moving it. For example to rename processed files from foo to foo.old set this value to '.old' |
consumer.excludedNamePrefix | null | FUSE Mediation Router 1.5: Used by FTPConsumer. Is used to exclude files if filename is starting with the given prefix. |
consumer.excludedNamePostfix | null | FUSE Mediation Router 1.5: Used by FTPConsumer. Is used to exclude files if filename is ending with the given postfix. |
consumer.timestamp | false | FUSE Mediation Router 1.5: @deprecated will be removed in FUSE Mediation Router 2.0. This option is only for backwards comparability. |
expression | null | FUSE Mediation Router 1.5: Use expression to dynamically set the filename. This
allows you to very easily set dynamic pattern style filenames. If an expression
is set it take precedes over the org.apache.camel.file.name
header. (Note: The header can itself also be an expression). The expression
options supports both String and Expression types. If the expression is a String
type then its always evaluated using the File Language. If the expression is an Expression type
then this type is of course used as it - this allows for instance to use OGNL as expression too. |
passiveMode | false | FUSE Mediation Router 1.5.1/2.0: Set whether to use passive mode connections. Default is active. This feature is only for regular FTP, not SFTP. |
knownHosts | null | FUSE Mediation Router 1.5.1/2.0: Sets the known_hosts file so that the SFTP endpoint can do host key verification. |
privateKeyFile | null | FUSE Mediation Router 1.5.1/2.0: Set the private key file to that the SFTP endpoint can do private key verification. |
privateKeyFilePassphrase | null | FUSE Mediation Router 1.5.1/2.0: Set the private key file passphrase to that the SFTP endpoint can do private key verification. |
The consumer will always skip any file which name starts with a dot, such as
".", ".camel", ".m2" or ".groovy"
. Only files (not directories)
is matched for valid filename if options such as: consumer.regexPattern,
consumer.excludeNamePrefix, consumer.excludeNamePostfix
is used.
The consumer recursive option will be changed from true to false as the default value. We don't feel that FUSE Mediation Router out-of-the-box should recursive poll.
The consumer will not use timestamp algorithm for
determine if a remote file is a new file - see warning section above. To use the old
behavior of FUSE Mediation Router 1.4 or older you can use the option
consumer.timestamp=true
.
The option readLock can be used to force FUSE Mediation Router not to consume files that is currently in the progress of being written. However this option is default turned off, as it requires that the user has write access. There are other solutions to avoid consuming files that are currently being written over FTP, for instance you can write the a temporary destination and move the file after it has been written.
The following message headers can be used to affect the behavior of the component
Header | Description |
---|---|
org.apache.camel.file.name | Specifies the output file name (relative to the endpoint directory) to be used for the output message when sending to the endpoint. If this is not present and no expression either then a generated message Id is used as filename instead. |
org.apache.camel.file.name.produced | New in FUSE Mediation Router 1.5: The actual absolute filepath (path + name) for the output file that was written. This header is set by FUSE Mediation Router and its purpose is providing end-users the name of the file that was written. |
org.apache.camel.file.total | FUSE Mediation Router 2.0: Current index out of total number of files being consumed in this batch. |
org.apache.camel.file.index | FUSE Mediation Router 2.0: Total number of files being consumed in this batch. |
file.remote.host | The hostname of the remote server |
file.remote.name | The name of the file consumed from the remote server |
file.remote.fullName | The fullname of the file consumed from the remote server |
When using FTPConsumer (downloading files from a FTP Server) the consumer specific properties from the File component should be prefixed with "consumer.". For example the delay option from File Component should be specified as "consumer.delay=30000" in the URI. See the samples or some of the unit tests of this component.
In FUSE Mediation Router 1.5 we have support for setting the filename using an
expression. This can be set either using the expression
option or as a string based File Language expression in the
org.apache.camel.file.name
header. See the File Language for some samples.
See the timestamp warning.
When consuming files (downloading) you must use type conversation to either String or to InputStream for ASCII and BINARY file types. In FUSE Mediation Router 1.4 this is fixed, as there are build in type converters for the ASCII and BINARY file types, meaning that you do not need the convertBodyTo expression.
In FUSE Mediation Router 1.4 or below FUSE Mediation Router FTPConsumer will poll files regardless if the file is currently being written. See the consumer.exclusiveReadLock option.
Also in FUSE Mediation Router 1.3 since setNames is default false then you must explicitly set the filename using the setHeader expression when consuming from FTP directly to File. The code below illustrates this:
private String ftpUrl = "ftp://camelrider@localhost:21/public/downloads?password=admin&binary=false"; private String fileUrl = "file:myfolder/?append=false&noop=true"; return new RouteBuilder() { public void configure() throws Exception { from(ftpUrl).setHeader(FileComponent.HEADER_FILE_NAME, constant("downloaded.txt")).convertBodyTo(String.class).to(fileUrl); } };
Or you can set the option to true as illustrated below:
private String ftpUrl = "ftp://camelrider@localhost:21/public/downloads?password=admin&binary=false&consumer.setNames=true"; private String fileUrl = "file:myfolder/?append=false&noop=true"; return new RouteBuilder() { public void configure() throws Exception { from(ftpUrl).convertBodyTo(String.class).to(fileUrl); } };
In the sample below we setup FUSE Mediation Router to download all the reports from the FTP server once every hour (60 min) as BINARY content and store it as files on the local file system.
protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { public void configure() throws Exception { // we use a delay of 60 minutes (eg. once pr. hour we poll the FTP server long delay = 60 * 60 * 1000L; // from the given FTP server we poll (= download) all the files // from the public/reports folder as BINARY types and store this as files // in a local directory. Camel will use the filenames from the FTPServer // notice that the FTPConsumer properties must be prefixed with "consumer." in the URL // the delay parameter is from the FileConsumer component so we should use consumer.delay as // the URI parameter name. The FTP Component is an extension of the File Component. from("ftp://scott@localhost/public/reports?password=tiger&binary=true&consumer.delay=" + delay). to("file://target/test-reports"); } }; }
And the route using Spring DSL:
<route> <from uri="ftp://scott@localhost/public/reports?password=tiger&binary=true&consumer.delay=60000"/> <to uri="file://target/test-reports"/> </route>
In this sample we want to move consumed files to a backup folder using today's date as a sub foldername. Notice that the move happens on the remote FTP server. If you want to store the downloaded file on your local disk then route it to the File component as the sample above illustrates.
from(ftpUrl + "&expression=backup/${date:now:yyyyMMdd}/${file:name}").to("...");
See File Language for more samples.
The FTP consumer is build as a scheduled consumer to be used in the from route. However if you want to start consuming from a FTP server triggered within a route it's a bit cumbersome to do this in FUSE Mediation Router 1.x (we plan to improve this in FUSE Mediation Router 2.x). However it's possible as this code below demonstrates.
In the sample we have a Seda queue where a message arrives that holds a message containing a filename to poll from a remote FTP server. So we setup a basic FTP url as:
// we use delay=5000 to use 5 sec delay between pools to avoid polling a second time before we stop the consumer // this is because we only want to run a single poll and get the file private String getFtpUrl() { return "ftp://admin@localhost:" + getPort() + "/getme?password=admin&binary=false&delay=5000"; }
And then we have the route where we use Processor within the route so we can use Java code. In this Java code we create the ftp consumer that downloads the file we want. And after the download we can get the content of the file and put it in the original exchange that continues being routed. As this is based on an unit test it routes to a Mock endpoint.
from("seda:start").process(new Processor() { public void process(final Exchange exchange) throws Exception { // get the filename from our custome header we want to get from a remote server String filename = exchange.getIn().getHeader("myfile", String.class); // construct the total url for the ftp consumer // add the fileName option with the file we want to consume String url = getFtpUrl() + "&fileName=" + filename; // create a ftp endpoint Endpoint ftp = context.getEndpoint(url); // create a polling consumer where we can poll the myfile from the ftp server PollingConsumer consumer = ftp.createPollingConsumer(); // must start the consumer before we can receive consumer.start(); // poll the file from the ftp server Exchange result = consumer.receive(); // the result is the response from the FTP consumer (the downloaded file) // replace the outher exchange with the content from the downloaded file exchange.getIn().setBody(result.getIn().getBody()); // stop the consumer consumer.stop(); } }).to("mock:result");