* Add `local-filename-generator-expression` attribute to FTP and SFTP Outbound Gateway * Refactoring for `(S)FtpOutboundGatewayParser` * Add `local-filename-generator-expression` tests * Add 'What's New' and attribute description JIRA: https://jira.springsource.org/browse/INT-3129 Polishing Doc Polishing Assert attribute is only set for get/mget Move tests to the get gateways
498 lines
28 KiB
XML
498 lines
28 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="ftp"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>FTP/FTPS Adapters</title>
|
|
<para>
|
|
Spring Integration provides support for file transfer operations via FTP and FTPS.
|
|
</para>
|
|
<section id="ftp-intro">
|
|
<title>Introduction</title>
|
|
<para>
|
|
The File Transfer Protocol (FTP) is a simple network protocol which allows you to transfer files between two computers on the Internet.
|
|
</para>
|
|
<para>
|
|
There are two actors when it comes to FTP communication: <emphasis>client</emphasis> and <emphasis>server</emphasis>.
|
|
To transfer files with FTP/FTPS, you use a <emphasis>client</emphasis> which initiates a connection to a remote computer
|
|
that is running an FTP <emphasis>server</emphasis>. After the connection is established, the <emphasis>client</emphasis> can choose
|
|
to send and/or receive copies of files.
|
|
</para>
|
|
|
|
<para>
|
|
Spring Integration supports sending and receiving files over FTP/FTPS by providing three <emphasis>client</emphasis>
|
|
side endpoints: <emphasis>Inbound Channel Adapter</emphasis>, <emphasis>Outbound Channel Adapter</emphasis>, and
|
|
<emphasis>Outbound Gateway</emphasis>. It also provides
|
|
convenient namespace-based configuration options for defining these <emphasis>client</emphasis> components.
|
|
</para>
|
|
<para>
|
|
To use the <emphasis>FTP</emphasis> namespace, add the following to the header of your XML file:
|
|
<programlisting language="xml"><![CDATA[xmlns:int-ftp="http://www.springframework.org/schema/integration/ftp"
|
|
xsi:schemaLocation="http://www.springframework.org/schema/integration/ftp
|
|
http://www.springframework.org/schema/integration/ftp/spring-integration-ftp.xsd"
|
|
]]></programlisting>
|
|
</para>
|
|
</section>
|
|
|
|
|
|
<section id="ftp-session-factory">
|
|
<title>FTP Session Factory</title>
|
|
<important>
|
|
Starting with version 3.0, sessions are no longer cached by default. See <xref linkend="ftp-session-caching"/>.
|
|
</important>
|
|
<para>
|
|
Before configuring FTP adapters you must configure an <emphasis>FTP Session Factory</emphasis>. You can configure
|
|
the <emphasis>FTP Session Factory</emphasis> with a regular bean definition where the implementation class is <classname>org.springframework.integration.ftp.session.DefaultFtpSessionFactory</classname>:
|
|
Below is a basic configuration:
|
|
|
|
<programlisting language="xml"><![CDATA[<bean id="ftpClientFactory"
|
|
class="org.springframework.integration.ftp.session.DefaultFtpSessionFactory">
|
|
<property name="host" value="localhost"/>
|
|
<property name="port" value="22"/>
|
|
<property name="username" value="kermit"/>
|
|
<property name="password" value="frog"/>
|
|
<property name="clientMode" value="0"/>
|
|
<property name="fileType" value="2"/>
|
|
<property name="bufferSize" value="100000"/>
|
|
</bean>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
For FTPS connections all you need to do is use <classname>org.springframework.integration.ftp.session.DefaultFtpsSessionFactory</classname> instead.
|
|
Below is the complete configuration sample:
|
|
|
|
<programlisting language="xml"><![CDATA[<bean id="ftpClientFactory"
|
|
class="org.springframework.integration.ftp.client.DefaultFtpsClientFactory">
|
|
<property name="host" value="localhost"/>
|
|
<property name="port" value="22"/>
|
|
<property name="username" value="oleg"/>
|
|
<property name="password" value="password"/>
|
|
<property name="clientMode" value="1"/>
|
|
<property name="fileType" value="2"/>
|
|
<property name="useClientMode" value="true"/>
|
|
<property name="cipherSuites" value="a,b.c"/>
|
|
<property name="keyManager" ref="keyManager"/>
|
|
<property name="protocol" value="SSL"/>
|
|
<property name="trustManager" ref="trustManager"/>
|
|
<property name="prot" value="P"/>
|
|
<property name="needClientAuth" value="true"/>
|
|
<property name="authValue" value="oleg"/>
|
|
<property name="sessionCreation" value="true"/>
|
|
<property name="protocols" value="SSL, TLS"/>
|
|
<property name="implicit" value="true"/>
|
|
</bean>]]></programlisting>
|
|
</para>
|
|
|
|
<para>
|
|
Every time an adapter requests a session object from its <interfacename>SessionFactory</interfacename> the session is
|
|
returned from a session pool maintained by a caching wrapper around the factory. A Session in the session pool might go stale
|
|
(if it has been disconnected by the server due to inactivity) so the <interfacename>SessionFactory</interfacename>
|
|
will perform validation to make sure that it never returns a stale session to the adapter. If a stale session was encountered,
|
|
it will be removed from the pool, and a new one will be created.
|
|
<note>
|
|
If you experience connectivity problems and would like to trace Session creation as well as see which Sessions are
|
|
polled you may enable it by setting the logger to TRACE level (e.g., log4j.category.org.springframework.integration.file=TRACE)
|
|
</note>
|
|
</para>
|
|
|
|
<para>
|
|
Now all you need to do is inject these session factories into your adapters. Obviously the protocol (FTP or FTPS) that an adapter will
|
|
use depends on the type of session factory that has been injected into the adapter.
|
|
</para>
|
|
<para>
|
|
<note>
|
|
A more practical way to provide values for <emphasis>FTP/FTPS Session Factories</emphasis> is by using Spring's property
|
|
placeholder support (See: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-factory-placeholderconfigurer).
|
|
</note>
|
|
</para>
|
|
|
|
<para>
|
|
<emphasis>Advanced Configuration</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
<classname>DefaultFtpSessionFactory</classname> provides an abstraction over the underlying client API which, in the current release of
|
|
Spring Integration, is <ulink url="http://commons.apache.org/net/">Apache Commons Net</ulink>. This spares you from the low level configuration details
|
|
of the <classname>org.apache.commons.net.ftp.FTPClient</classname>. However there are times when access to lower level <classname>FTPClient</classname> details is
|
|
necessary to achieve more advanced configuration (e.g., setting data timeout, default timeout etc.). For that purpose, <classname>AbstractFtpSessionFactory</classname>
|
|
(the base class for all FTP Session Factories) exposes hooks, in the form of the two post-processing methods below.
|
|
<programlisting language="java"><![CDATA[/**
|
|
* Will handle additional initialization after client.connect() method was invoked,
|
|
* but before any action on the client has been taken
|
|
*/
|
|
protected void postProcessClientAfterConnect(T t) throws IOException {
|
|
// NOOP
|
|
}
|
|
/**
|
|
* Will handle additional initialization before client.connect() method was invoked.
|
|
*/
|
|
protected void postProcessClientBeforeConnect(T client) throws IOException {
|
|
// NOOP
|
|
}]]></programlisting>
|
|
As you can see, there is no default implementation for these two methods. However, by extending <classname>DefaultFtpSessionFactory</classname> you can override these methods
|
|
to provide more advanced configuration of the <classname>FTPClient</classname>. For example:
|
|
<programlisting language="java"><![CDATA[public class AdvancedFtpSessionFactory extends DefaultFtpSessionFactory {
|
|
|
|
protected void postProcessClientBeforeConnect(FTPClient ftpClient) throws IOException {
|
|
ftpClient.setDataTimeout(5000);
|
|
ftpClient.setDefaultTimeout(5000);
|
|
}
|
|
}]]></programlisting>
|
|
</para>
|
|
</section>
|
|
|
|
<section id="ftp-inbound">
|
|
<title>FTP Inbound Channel Adapter</title>
|
|
<para>
|
|
The <emphasis>FTP Inbound Channel Adapter</emphasis> is a special listener that will connect to the FTP server and will listen
|
|
for the remote directory events (e.g., new file created) at which point it will initiate a file transfer.
|
|
|
|
<programlisting language="xml"><![CDATA[<int-ftp:inbound-channel-adapter id="ftpInbound"
|
|
channel="ftpChannel"
|
|
session-factory="ftpSessionFactory"
|
|
charset="UTF-8"
|
|
auto-create-local-directory="true"
|
|
delete-remote-files="true"
|
|
filename-pattern="*.txt"
|
|
remote-directory="some/remote/path"
|
|
remote-file-separator="/"
|
|
local-filename-generator-expression="#this.toUpperCase() + '.a'"
|
|
local-filter="myFilter"
|
|
local-directory=".">
|
|
<int:poller fixed-rate="1000"/>
|
|
</int-ftp:inbound-channel-adapter>]]></programlisting>
|
|
|
|
As you can see from the configuration above you can configure an <emphasis>FTP Inbound Channel Adapter</emphasis> via the <code>inbound-channel-adapter</code>
|
|
element while also providing values for various attributes such as <code>local-directory</code>, <code>filename-pattern</code>
|
|
(which is based on simple pattern matching, not regular expressions), and of course the reference to a <code>session-factory</code>.
|
|
</para>
|
|
<para>
|
|
By default the transferred file will carry the same name as the original file. If you want to override this behavior you
|
|
can set the <code>local-filename-generator-expression</code> attribute which allows you to provide a SpEL Expression to generate
|
|
the name of the local file. Unlike outbound gateways and adapters where the root object of the SpEL Evaluation Context
|
|
is a <classname>Message</classname>, this inbound adapter does not yet have the Message at the time of evaluation since
|
|
that's what it ultimately generates with the transferred file as its payload. So, the root object of the SpEL Evaluation Context
|
|
is the original name of the remote file (String).
|
|
</para>
|
|
|
|
<para>
|
|
Sometimes file filtering based on the simple pattern specified via <code>filename-pattern</code> attribute might not be
|
|
sufficient. If this is the case, you can use the <code>filename-regex</code> attribute to specify a Regular Expression
|
|
(e.g. <code>filename-regex=".*\.test$"</code>). And of course if you need complete control you can use <code>filter</code>
|
|
attribute and provide a reference to any custom implementation of the
|
|
<classname>org.springframework.integration.file.filters.FileListFilter</classname>, a strategy interface for filtering a
|
|
list of files. This filter determines which remote files are retrieved.
|
|
</para>
|
|
<note>
|
|
Beginning with 3.0, you can also specify a filter used to filter the files locally, once they have
|
|
been retrieved. The default filter is an <classname>AcceptOnceFileListFilter</classname> which prevents processing
|
|
files with the same name multiple times in the same JVM execution; this can now be overridden
|
|
(for example with an <classname>AcceptAllFileListFilter</classname>), using the <code>local-filter</code> attribute.
|
|
Previously, the default <classname>AcceptOnceFileListFilter</classname> could not be overridden.
|
|
</note>
|
|
<para>
|
|
The 'remote-file-separator' attribute allows you to configure a
|
|
file separator character to use if the default '/' is not applicable for your particular environment.
|
|
</para>
|
|
<para>
|
|
Please refer to the schema for more details on these attributes.
|
|
</para>
|
|
<para>
|
|
It is also important to understand that the <emphasis>FTP Inbound Channel Adapter</emphasis> is a <emphasis>Polling Consumer</emphasis> and
|
|
therefore you must configure a poller (either via a global default or a local sub-element).
|
|
Once a file has been transferred, a Message with a <classname>java.io.File</classname> as its payload will be generated and sent to the channel
|
|
identified by the <code>channel</code> attribute.
|
|
</para>
|
|
<para>
|
|
<emphasis>More on File Filtering and Large Files</emphasis>
|
|
</para>
|
|
<para>
|
|
Sometimes the file that just appeared in the monitored (remote) directory is not complete. Typically such a file
|
|
will be written with temporary extension (e.g., foo.txt.writing) and then renamed after the writing process finished.
|
|
As a user in most cases you are only interested in files that are complete and would like to filter only files that are complete.
|
|
To handle these scenarios you can use the filtering support provided by the <code>filename-pattern</code>, <code>filename-regex</code>
|
|
and <code>filter</code> attributes. Here is an example that uses a custom Filter implementation.
|
|
|
|
<programlisting language="xml"><![CDATA[<int-ftp:inbound-channel-adapter
|
|
channel="ftpChannel"
|
|
session-factory="ftpSessionFactory"
|
|
filter="customFilter"
|
|
local-directory="file:/my_transfers">
|
|
remote-directory="some/remote/path"
|
|
<int:poller fixed-rate="1000"/>
|
|
</int-ftp:inbound-channel-adapter>
|
|
|
|
<bean id="customFilter" class="org.example.CustomFilter"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
<emphasis>Poller configuration notes for the inbound FTP adapter</emphasis>
|
|
</para>
|
|
<para>
|
|
The job of the inbound FTP adapter consists of two tasks:
|
|
<emphasis>1) Communicate with a remote server in order to transfer files from a remote directory to a local directory.</emphasis>
|
|
<emphasis>2) For each transferred file, generate a Message with that file as a payload and send it to the channel identified by the 'channel' attribute.</emphasis>
|
|
|
|
That is why they are called 'channel-adapters' rather than just 'adapters'. The main job of such an adapter is to generate a
|
|
Message to be sent to a Message Channel. Essentially, the second task mentioned above takes precedence in such a way that
|
|
*IF* your local directory already has one or more files it will first generate Messages from those, and *ONLY*
|
|
when all local files have been processed, will it initiate the remote communication to retrieve more files.
|
|
</para>
|
|
<para>
|
|
Also, when configuring a trigger on the poller you should pay close attention to the <code>max-messages-per-poll</code>
|
|
attribute. Its default value is 1 for all <classname>SourcePollingChannelAdapter</classname> instances (including FTP).
|
|
This means that as soon as one file is processed, it will wait for the next execution time as determined by your
|
|
trigger configuration. If you happened to have one or more files sitting in the <code>local-directory</code>, it would process
|
|
those files before it would initiate communication with the remote FTP server. And, if the <code>max-messages-per-poll</code>
|
|
were set to 1 (default), then it would be processing only one file at a time with intervals as defined by your trigger,
|
|
essentially working as <emphasis>one-poll = one-file</emphasis>.
|
|
</para>
|
|
<para>
|
|
For typical file-transfer use cases, you most likely want the opposite behavior: to process all the files you can for each
|
|
poll and only then wait for the next poll. If that is the case, set <code>max-messages-per-poll</code> to -1. Then, on
|
|
each poll, the adapter will attempt to generate as many Messages as it possibly can. In other words, it will process
|
|
everything in the local directory, and then it will connect to the remote directory to transfer everything that is available
|
|
there to be processed locally. Only then is the poll operation considered complete, and the poller will wait for the next execution time.
|
|
</para>
|
|
<para>
|
|
You can alternatively set the 'max-messages-per-poll' value to a positive value indicating the upward limit of Messages to be created
|
|
from files with each poll. For example, a value of 10 means that on each poll it will attempt to process no more than 10 files.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="ftp-outbound">
|
|
<title>FTP Outbound Channel Adapter</title>
|
|
|
|
<para>
|
|
The <emphasis>FTP Outbound Channel Adapter</emphasis> relies upon a <classname>MessageHandler</classname> implementation that will connect to the
|
|
FTP server and initiate an FTP transfer for every file it receives in the payload of incoming Messages. It also supports several
|
|
representations of the <emphasis>File</emphasis> so you are not limited only to java.io.File typed payloads.
|
|
The <emphasis>FTP Outbound Channel Adapter</emphasis>
|
|
supports the following payloads: 1) <classname>java.io.File</classname> - the actual file object;
|
|
2) <classname>byte[]</classname> - a byte array that represents the file contents; and 3) <classname>java.lang.String</classname> -
|
|
text that represents the file contents.
|
|
|
|
<programlisting language="xml"><![CDATA[<int-ftp:outbound-channel-adapter id="ftpOutbound"
|
|
channel="ftpChannel"
|
|
session-factory="ftpSessionFactory"
|
|
charset="UTF-8"
|
|
remote-file-separator="/"
|
|
auto-create-directory="true"
|
|
remote-directory-expression="headers.['remote_dir']"
|
|
temporary-remote-directory-expression="headers.['temp_remote_dir']"
|
|
filename-generator="fileNameGenerator"/>]]></programlisting>
|
|
|
|
As you can see from the configuration above you can configure an <emphasis>FTP Outbound Channel Adapter</emphasis> via the
|
|
<code>outbound-channel-adapter</code> element while also providing values for various attributes such as <code>filename-generator</code>
|
|
(an implementation of the <classname>org.springframework.integration.file.FileNameGenerator</classname> strategy interface),
|
|
a reference to a <code>session-factory</code>, as well as other attributes. You can also see
|
|
some examples of <code>*expression</code> attributes which allow you to use SpEL
|
|
to configure things like <code>remote-directory-expression</code>, <code>temporary-remote-directory-expression</code> and <code>remote-filename-generator-expression</code>
|
|
(a SpEL alternative to <code>filename-generator</code> shown above). As with any component that allows the usage of SpEL, access to Payload and Message Headers is available via
|
|
'payload' and 'headers' variables.
|
|
Please refer to the schema for more details on
|
|
the available attributes.
|
|
<note>
|
|
By default Spring Integration will use <classname>o.s.i.file.DefaultFileNameGenerator</classname> if none is specified.
|
|
<classname>DefaultFileNameGenerator</classname> will determine the file name based on the value of the <code>file_name</code> header (if it exists)
|
|
in the MessageHeaders, or if the payload of the Message is already a <classname>java.io.File</classname>, then it will use the original name of that file.
|
|
</note>
|
|
</para>
|
|
|
|
<para>
|
|
<important>
|
|
Defining certain values (e.g., remote-directory) might be platform/ftp server dependent. For example as it
|
|
was reported on this forum http://forum.springsource.org/showthread.php?p=333478&posted=1#post333478 on some
|
|
platforms you must add slash to the end of the directory definition (e.g., remote-directory="/foo/bar/"
|
|
instead of remote-directory="/foo/bar")
|
|
</important>
|
|
</para>
|
|
|
|
<para>
|
|
<emphasis>Avoiding Partially Written Files</emphasis>
|
|
</para>
|
|
<para>
|
|
One of the common problems, when dealing with file transfers, is the possibility of processing a <emphasis>partial file</emphasis> -
|
|
a file might appear in the file system before its transfer is actually complete.
|
|
</para>
|
|
<para>
|
|
To deal with this issue, Spring Integration FTP adapters use a very common algorithm where files are transferred
|
|
under a temporary name and then renamed once they are fully transferred.
|
|
</para>
|
|
<para>
|
|
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 <code>.writing</code>; this can be changed using the <code>temporary-file-suffix</code> attribute.
|
|
</para>
|
|
<para>
|
|
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 <code>use-temporary-file-name</code>
|
|
to <code>false</code> (default is <code>true</code>). When this attribute is <code>false</code>, 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.
|
|
</para>
|
|
</section>
|
|
<section id="ftp-outbound-gateway">
|
|
<title>FTP Outbound Gateway</title>
|
|
|
|
<para>
|
|
The <emphasis>FTP Outbound Gateway</emphasis> provides a limited set of commands to interact with a remote FTP/FTPS server.
|
|
<para>
|
|
Commands supported are:
|
|
<itemizedlist>
|
|
<listitem>ls (list files)</listitem>
|
|
<listitem>get (retrieve file)</listitem>
|
|
<listitem>mget (retrieve file(s))</listitem>
|
|
<listitem>rm (remove file(s))</listitem>
|
|
<listitem>mv (move/rename file)</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para><emphasis role="bold">ls</emphasis></para>
|
|
<para>
|
|
ls lists remote file(s) and supports the following options:
|
|
<itemizedlist>
|
|
<listitem>-1 - just retrieve a list of filenames, default is to retrieve a
|
|
list of <classname>FileInfo</classname> objects.</listitem>
|
|
<listitem>-a - include all files (including those starting with '.')</listitem>
|
|
<listitem>-f - do not sort the list</listitem>
|
|
<listitem>-dirs - include directories (excluded by default)</listitem>
|
|
<listitem>-links - include symbolic links (excluded by default)</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para>
|
|
In addition, filename filtering is provided, in the same manner as the
|
|
<classname>inbound-channel-adapter</classname>.
|
|
</para>
|
|
<para>
|
|
The message payload resulting from an <emphasis>ls</emphasis> operation is a list of file names,
|
|
or a list of <classname>FileInfo</classname> objects. These objects provide
|
|
information such as modified time, permissions etc.
|
|
</para>
|
|
<para>
|
|
The remote directory that the <emphasis>ls</emphasis> command acted on is provided
|
|
in the <classname>file_remoteDirectory</classname> header.
|
|
</para>
|
|
<para><emphasis role="bold">get</emphasis></para>
|
|
<para>
|
|
<emphasis>get</emphasis> retrieves a remote file and supports the following option:
|
|
<itemizedlist>
|
|
<listitem>-P - preserve the timestamp of the remote file</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para>
|
|
The message payload resulting from a <emphasis>get</emphasis> operation is a
|
|
<classname>File</classname> object representing the retrieved file.
|
|
</para>
|
|
<para>
|
|
The remote directory is provided in the <classname>file_remoteDirectory</classname> header, and the filename is
|
|
provided in the <classname>file_remoteFile</classname> header.
|
|
</para>
|
|
<para><emphasis role="bold">mget</emphasis></para>
|
|
<para>
|
|
<emphasis>mget</emphasis> retrieves multiple remote files based on a pattern and supports the following option:
|
|
<itemizedlist>
|
|
<listitem>-x - Throw an exception if no files match the pattern (otherwise an empty
|
|
list is returned)</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para>
|
|
The message payload resulting from an <emphasis>mget</emphasis> operation is a
|
|
<classname>List<File></classname> object - a List of File objects, each representing
|
|
a retrieved file.
|
|
</para>
|
|
<para>
|
|
The remote directory is provided in the <classname>file_remoteDirectory</classname> header, and the pattern
|
|
for the filenames is
|
|
provided in the <classname>file_remoteFile</classname> header.
|
|
</para>
|
|
<para><emphasis role="bold">rm</emphasis></para>
|
|
<para>
|
|
The <emphasis>rm</emphasis> command has no options.
|
|
</para>
|
|
<para>
|
|
The message payload resulting from an <emphasis>rm</emphasis> operation is Boolean.TRUE if the
|
|
remove was successful, Boolean.FALSE otherwise.
|
|
The remote directory is provided in the <classname>file_remoteDirectory</classname> header, and the filename is
|
|
provided in the <classname>file_remoteFile</classname> header.
|
|
</para>
|
|
<para><emphasis role="bold">mv</emphasis></para>
|
|
<para>
|
|
The <emphasis>mv</emphasis> command has no options.
|
|
</para>
|
|
<para>
|
|
The <emphasis>expression</emphasis> attribute defines the "from" path and the
|
|
<emphasis>rename-expression</emphasis> attribute defines the "to" path. By default, the
|
|
<emphasis>rename-expression</emphasis> is <code>headers['file_renameTo']</code>. This
|
|
expression must not evaluate to null, or an empty <code>String</code>. If necessary,
|
|
any remote directories needed will be created.
|
|
The payload of the result message is <code>Boolean.TRUE</code>.
|
|
The original remote directory is provided in the <code>file_remoteDirectory</code> header, and the filename is
|
|
provided in the <code>file_remoteFile</code> header. The new path is in
|
|
the <code>file_renameTo</code> header.
|
|
</para>
|
|
<para>
|
|
<emphasis role="bold">Additional Information</emphasis>
|
|
</para>
|
|
<para>
|
|
The <emphasis>get</emphasis> and <emphasis>mget</emphasis> commands support
|
|
the <emphasis>local-filename-generator-expression</emphasis> attribute. It
|
|
defines a SpEL expression to generate the name of local file(s) during the transfer.
|
|
The root object of the evaluation context is the request Message but, in addition, the <code>remoteFileName</code>
|
|
variable is also available, which is particularly useful for <emphasis>mget</emphasis>, for
|
|
example: <code>local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.foo"</code>
|
|
</para>
|
|
<para>
|
|
For all commands, the PATH that the command acts on is provided by the 'expression'
|
|
property of the gateway. For the mget command, the expression might evaluate to '*', meaning
|
|
retrieve all files, or 'somedirectory/*' etc.
|
|
</para>
|
|
</para>
|
|
<para>
|
|
Here is an example of a gateway configured for an ls command...
|
|
<programlisting language="xml"><![CDATA[<int-ftp:outbound-gateway id="gateway1"
|
|
session-factory="ftpSessionFactory"
|
|
request-channel="inbound1"
|
|
command="ls"
|
|
command-options="-1"
|
|
expression="payload"
|
|
reply-channel="toSplitter"/>]]></programlisting>
|
|
</para>
|
|
<para>
|
|
The payload of the message sent to the toSplitter channel is a list of String objects
|
|
containing the filename of each file. If the <classname>command-options</classname> was
|
|
omitted, it would be a list of <classname>FileInfo</classname> objects. Options are
|
|
provided space-delimited, e.g. <classname>command-options="-1 -dirs -links"</classname>.
|
|
</para>
|
|
</section>
|
|
<section id="ftp-session-caching">
|
|
<title>FTP Session Caching</title>
|
|
<important>
|
|
Starting with version 3.0, sessions are no longer cached by default; the <code>cache-sessions</code> attribute
|
|
is no longer supported on endpoints. You must now use a <classname>CachingSessionFactory</classname> (see below) if you
|
|
wish to cache sessions.
|
|
</important>
|
|
<para>
|
|
In versions prior to 3.0, the sessions were cached automatically by default. A <code>cache-sessions</code> attribute was available for
|
|
disabling the auto caching, but that solution did not provide a way to configure other session caching attributes. For example,
|
|
you could not limit on the number of sessions created. To support that requirement and other configuration options, a
|
|
<classname>CachingSessionFactory</classname> was provided. It provides <code>sessionCacheSize</code> and <code>sessionWaitTimeout</code>
|
|
properties. As its name suggests, the <code>sessionCacheSize</code> property controls how many active sessions the factory will
|
|
maintain in its cache (the DEFAULT is unbounded). If the <code>sessionCacheSize</code> threshold has been reached, any attempt to
|
|
acquire another session will block until either one of the cached sessions becomes available or until the wait time for a Session
|
|
expires (the DEFAULT wait time is Integer.MAX_VALUE). The <code>sessionWaitTimeout</code> property enables configuration of that value.
|
|
</para>
|
|
<para>
|
|
If you want your Sessions to be cached, simply configure your default Session Factory as described above and then
|
|
wrap it in an instance of <classname>CachingSessionFactory</classname> where you may provide those additional properties.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[<bean id="ftpSessionFactory" class="o.s.i.ftp.session.DefaultFtpSessionFactory">
|
|
<property name="host" value="localhost"/>
|
|
</bean>
|
|
|
|
<bean id="cachingSessionFactory" class="o.s.i.file.remote.session.CachingSessionFactory">
|
|
<constructor-arg ref="ftpSessionFactory"/>
|
|
<constructor-arg value="10"/>
|
|
<property name="sessionWaitTimeout" value="1000"/>
|
|
</bean>]]></programlisting>
|
|
<para>
|
|
In the above example you see a <classname>CachingSessionFactory</classname> created with the
|
|
<code>sessionCacheSize</code> set to 10 and the <code>sessionWaitTimeout</code> set to 1 second (its value is in millliseconds).
|
|
|
|
</para>
|
|
</section>
|
|
</chapter>
|