Documentation For new SMB components
* Updated SMB Module documentation for new components `SmbStreamingMessageSource` and `SmbOutboundGateway` * Update based on PR review feedback * Omit XML config examples based on PR review feedback
This commit is contained in:
@@ -175,10 +175,10 @@ The following table summarizes the various endpoints with quick links to the app
|
||||
| <<./sftp.adoc#sftp-outbound-gateway,SFTP Outbound Gateway>>
|
||||
|
||||
| *SMB*
|
||||
| <<./smb.adoc#smb-inbound,SMB Inbound Channel Adapter>>
|
||||
| <<./smb.adoc#smb-inbound,SMB Inbound Channel Adapter>>, <<./smb.adoc#smb-streaming-inbound,SMB Streaming Inbound Channel Adapter>>
|
||||
| <<./smb.adoc#smb-outbound,SMB Outbound Channel Adapter>>
|
||||
| N
|
||||
| N
|
||||
| <<./smb.adoc#smb-outbound-gateway,SMB Outbound Gateway>>
|
||||
|
||||
| *STOMP*
|
||||
| <<./stomp.adoc#stomp-inbound-adapter,STOMP Inbound Channel Adapter>>
|
||||
|
||||
@@ -32,6 +32,21 @@ Its `SmbFile` abstraction is simply wrapped to the Spring Integration "Remote Fi
|
||||
The SMB Channel Adapters and support classes implementations are fully similar to existing components for (S)FTP or AWS S3 protocols.
|
||||
So, if you familiar with those components it is pretty straightforward to use.
|
||||
|
||||
Spring Integration supports sending and receiving files over SMB by providing three client-side endpoints: inbound channel adapter, outbound channel adapter, and outbound gateway.
|
||||
It also provides convenient namespace-based configuration options for defining these client components.
|
||||
|
||||
To use the SMB namespace, add the following to the header of your XML file:
|
||||
|
||||
====
|
||||
[source,xml]
|
||||
----
|
||||
xmlns:int-smb="http://www.springframework.org/schema/integration/smb"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/smb
|
||||
https://www.springframework.org/schema/integration/smb/spring-integration-smb.xsd"
|
||||
|
||||
----
|
||||
====
|
||||
|
||||
[[smb-session-factory]]
|
||||
=== SMB Session Factory
|
||||
|
||||
@@ -171,6 +186,116 @@ public class SmbJavaApplication {
|
||||
----
|
||||
====
|
||||
|
||||
[[smb-streaming-inbound]]
|
||||
=== SMB Streaming Inbound Channel Adapter
|
||||
|
||||
This adapter produces message with payloads of type `InputStream`, letting files be fetched without writing to the local file system.
|
||||
Since the session remains open, the consuming application is responsible for closing the session when the file has been consumed.
|
||||
The session is provided in the `closeableResource` header (`IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE`).
|
||||
Standard framework components, such as the `FileSplitter` and `StreamTransformer`, automatically close the session.
|
||||
See <<./file.adoc#file-splitter,File Splitter>> and <<./transformer.adoc#stream-transformer,Stream Transformer>> for more information about these components.
|
||||
|
||||
The `SmbStreamingMessageSource` adapter prevents duplicates for remote files with `SmbPersistentAcceptOnceFileListFilter` based on the in-memory `SimpleMetadataStore`.
|
||||
By default, this filter is also applied with the filename pattern (or regex).
|
||||
If you need to allow duplicates, you can use `AcceptAllFileListFilter`.
|
||||
Any other use cases can be handled by `CompositeFileListFilter` (or `ChainFileListFilter`).
|
||||
The Java configuration (<<smb-streaming-java,later in the document>>) shows one technique to remove the remote file after processing to avoid duplicates.
|
||||
|
||||
For more information about the `SmbPersistentAcceptOnceFileListFilter`, and how it is used, see <<./file.adoc#remote-persistent-flf,Remote Persistent File List Filters>>.
|
||||
|
||||
Use the `max-fetch-size` attribute to limit the number of files fetched on each poll when a fetch is necessary.
|
||||
Set it to `1` and use a persistent filter when running in a clustered environment.
|
||||
See <<smb-max-fetch>> for more information.
|
||||
|
||||
The adapter puts the remote directory and file name in the `FileHeaders.REMOTE_DIRECTORY` and `FileHeaders.REMOTE_FILE` headers, respectively.
|
||||
The `FileHeaders.REMOTE_FILE_INFO` header provides additional remote file information (represented in JSON by default).
|
||||
If you set the `fileInfoJson` property on the `SmbStreamingMessageSource` to `false`, the header contains an `SmbFileInfo` object.
|
||||
|
||||
[[smb-streaming-java]]
|
||||
==== Configuring with Java Configuration
|
||||
|
||||
The following Spring Boot application shows an example of how to configure the inbound adapter with Java configuration:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@SpringBootApplication
|
||||
public class SmbJavaApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder(SmbJavaApplication.class)
|
||||
.web(false)
|
||||
.run(args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@InboundChannelAdapter(channel = "stream")
|
||||
public MessageSource<InputStream> smbMessageSource() {
|
||||
SmbStreamingMessageSource messageSource = new SmbStreamingMessageSource(template());
|
||||
messageSource.setRemoteDirectory("smbSource/");
|
||||
messageSource.setFilter(new AcceptAllFileListFilter<>());
|
||||
messageSource.setMaxFetchSize(1);
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Transformer(inputChannel = "stream", outputChannel = "data")
|
||||
public org.springframework.integration.transformer.Transformer transformer() {
|
||||
return new StreamTransformer("UTF-8");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SmbRemoteFileTemplate template() {
|
||||
return new SmbRemoteFileTemplate(smbSessionFactory());
|
||||
}
|
||||
|
||||
@ServiceActivator(inputChannel = "data", adviceChain = "after")
|
||||
@Bean
|
||||
public MessageHandler handle() {
|
||||
return System.out::println;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ExpressionEvaluatingRequestHandlerAdvice after() {
|
||||
ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
|
||||
advice.setOnSuccessExpression(
|
||||
"@template.remove(headers['file_remoteDirectory'] + headers['file_remoteFile'])");
|
||||
advice.setPropagateEvaluationFailures(true);
|
||||
return advice;
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Notice that, in this example, the message handler downstream of the transformer has an `advice` that removes the remote file after processing.
|
||||
|
||||
[[smb-max-fetch]]
|
||||
=== Inbound Channel Adapters: Controlling Remote File Fetching
|
||||
|
||||
There are two properties that you should consider when you configure inbound channel adapters.
|
||||
`max-messages-per-poll`, as with all pollers, can be used to limit the number of messages emitted on each poll (if more than the configured value are ready).
|
||||
`max-fetch-size` can limit the number of files retrieved from the remote server at one time.
|
||||
|
||||
The following scenarios assume the starting state is an empty local directory:
|
||||
|
||||
* `max-messages-per-poll=2` and `max-fetch-size=1`: The adapter fetches one file, emits it, fetches the next file, emits it, and then sleeps until the next poll.
|
||||
* `max-messages-per-poll=2` and `max-fetch-size=2`): The adapter fetches both files and then emits each one.
|
||||
* `max-messages-per-poll=2` and `max-fetch-size=4`: The adapter fetches up to four files (if available) and emits the first two (if there are at least two).
|
||||
The next two files are emitted on the next poll.
|
||||
* `max-messages-per-poll=2` and `max-fetch-size` not specified: The adapter fetches all remote files and emits the first two (if there are at least two).
|
||||
The subsequent files are emitted on subsequent polls (two at a time).
|
||||
When all files are consumed, the remote fetch is attempted again, to pick up any new files.
|
||||
|
||||
IMPORTANT: When you deploy multiple instances of an application, we recommend a small `max-fetch-size`, to avoid one instance "`grabbing`" all the files and starving other instances.
|
||||
|
||||
Another use for `max-fetch-size` is if you want to stop fetching remote files but continue to process files that have already been fetched.
|
||||
Setting the `maxFetchSize` property on the `MessageSource` (programmatically, with JMX, or with a <<./control-bus.adoc#control-bus,control bus>>) effectively stops the adapter from fetching more files but lets the poller continue to emit messages for files that have previously been fetched.
|
||||
If the poller is active when the property is changed, the change takes effect on the next poll.
|
||||
|
||||
The synchronizer can be provided with a `Comparator<SmbFile>`.
|
||||
This is useful when restricting the number of files fetched with `maxFetchSize`.
|
||||
|
||||
[[smb-outbound]]
|
||||
=== SMB Outbound Channel Adapter
|
||||
|
||||
@@ -246,3 +371,356 @@ public class SmbJavaApplication {
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[[smb-outbound-gateway]]
|
||||
=== SMB Outbound Gateway
|
||||
|
||||
The SMB outbound gateway provides a limited set of commands to interact with a remote SMB server.
|
||||
The supported commands are:
|
||||
|
||||
* `ls` (list files)
|
||||
* `nlst` (list file names)
|
||||
* `get` (retrieve file)
|
||||
* `mget` (retrieve file(s))
|
||||
* `rm` (remove file(s))
|
||||
* `mv` (move/rename file)
|
||||
* `put` (send file)
|
||||
* `mput` (send multiple files)
|
||||
|
||||
==== Using the `ls` Command
|
||||
|
||||
`ls` lists remote files and supports the following options:
|
||||
|
||||
* `-1`: Retrieve a list of filenames.
|
||||
The default is to retrieve a list of `FileInfo` objects
|
||||
* `-a`: Include all files (including those starting with '.')
|
||||
* `-f`: Do not sort the list
|
||||
* `-dirs`: Include directories (excluded by default)
|
||||
* `-links`: Include symbolic links (excluded by default)
|
||||
* `-R`: List the remote directory recursively
|
||||
|
||||
In addition, filename filtering is provided in the same manner as the `inbound-channel-adapter`.
|
||||
|
||||
The message payload resulting from an `ls` operation is a list of file names or a list of `FileInfo` objects (depending on whether you usr the `-1` switch).
|
||||
These objects provide information such as modified time, permissions, and others.
|
||||
|
||||
The remote directory that the `ls` command acted on is provided in the `file_remoteDirectory` header.
|
||||
|
||||
When using the recursive option (`-R`), the `fileName` includes any subdirectory elements and represents the relative path to the file (relative to the remote directory).
|
||||
If you use the `-dirs` option, each recursive directory is also returned as an element in the list.
|
||||
In this case, we recommend that you not use the `-1` option, because you would not be able to distinguish files from directories, which you can do when you use `FileInfo` objects.
|
||||
|
||||
==== Using `nlst` Command
|
||||
|
||||
`nlst` lists remote file names and supports only one option:
|
||||
|
||||
* `-f`: Do not sort the list
|
||||
|
||||
The message payload resulting from an `nlst` operation is a list of file names.
|
||||
|
||||
The `file_remoteDirectory` header holds the remote directory on which the `nlst` command acted.
|
||||
|
||||
==== Using the `get` Command
|
||||
|
||||
`get` retrieves a remote file and supports the following options:
|
||||
|
||||
* `-P`: Preserve the timestamp of the remote file.
|
||||
* `-stream`: Retrieve the remote file as a stream.
|
||||
* `-D`: Delete the remote file after successful transfer.
|
||||
The remote file is not deleted if the transfer is ignored, because the `FileExistsMode` is `IGNORE` and the local file already exists.
|
||||
|
||||
The `file_remoteDirectory` header holds the remote directory, and the `file_remoteFile` header holds the filename.
|
||||
|
||||
The message payload resulting from a `get` operation is a `File` object representing the retrieved file.
|
||||
If you use the `-stream` option, the payload is an `InputStream` rather than a `File`.
|
||||
For text files, a common use case is to combine this operation with a <<./file.adoc#file-splitter,file splitter>> or a <<./transformer.adoc#stream-transformer,stream transformer>>.
|
||||
When consuming remote files as streams, you are responsible for closing the `Session` after the stream is consumed.
|
||||
For convenience, the `Session` is provided in the `closeableResource` header, and `IntegrationMessageHeaderAccessor` offers convenience method:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
Closeable closeable = new IntegrationMessageHeaderAccessor(message).getCloseableResource();
|
||||
if (closeable != null) {
|
||||
closeable.close();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
Framework components, such as the <<./file.adoc#file-splitter,File Splitter>> and <<./transformer.adoc#stream-transformer,Stream Transformer>>, automatically close the session after the data is transferred.
|
||||
|
||||
NOTE: If you consume the input stream in a custom component, you must close the `Session`.
|
||||
|
||||
==== Using the `mget` Command
|
||||
|
||||
`mget` retrieves multiple remote files based on a pattern and supports the following options:
|
||||
|
||||
* `-P`: Preserve the timestamps of the remote files.
|
||||
|
||||
* `-R`: Retrieve the entire directory tree recursively.
|
||||
|
||||
* `-x`: Throw an exception if no files match the pattern (otherwise, an empty list is returned).
|
||||
|
||||
* `-D`: Delete each remote file after successful transfer.
|
||||
If the transfer is ignored, the remote file is not deleted, because the `FileExistsMode` is `IGNORE` and the local file already exists.
|
||||
|
||||
The message payload resulting from an `mget` operation is a `List<File>` object (that is, a `List` of `File` objects, each representing a retrieved file).
|
||||
|
||||
IMPORTANT: If the `FileExistsMode` is `IGNORE`, the payload of the output message no longer contain files that were not fetched due to the file already existing.
|
||||
Previously, the array contained all files, including those that already existed.
|
||||
|
||||
The expression you use determine the remote path should produce a result that ends with `*` for example `myfiles/*` fetches the complete tree under `myfiles`.
|
||||
|
||||
You can use a recursive `MGET`, combined with the `FileExistsMode.REPLACE_IF_MODIFIED` mode, to periodically synchronize an entire remote directory tree locally.
|
||||
This mode sets the local file's last modified timestamp to the remote file's timestamp, regardless of the `-P` (preserve timestamp) option.
|
||||
|
||||
.Notes for when using recursion (`-R`)
|
||||
[IMPORTANT]
|
||||
=====
|
||||
|
||||
The pattern is ignored and `*` is assumed.
|
||||
By default, the entire remote tree is retrieved.
|
||||
However, you can filter files in the tree by providing a `FileListFilter`.
|
||||
You can also filter directories in the tree this way.
|
||||
A `FileListFilter` can be provided by reference or by `filename-pattern` or `filename-regex` attributes.
|
||||
For example, `filename-regex="(subDir|.*1.txt)"` retrieves all files ending with `1.txt` in the remote directory and the subdirectory `subDir`.
|
||||
However, we describe an alternative available after this note.
|
||||
|
||||
If you filter a subdirectory, no additional traversal of that subdirectory is performed.
|
||||
|
||||
The `-dirs` option is not allowed (the recursive `mget` uses the recursive `ls` to obtain the directory tree and the directories themselves cannot be included in the list).
|
||||
|
||||
Typically, you would use the `#remoteDirectory` variable in the `local-directory-expression` so that the remote directory structure is retained locally.
|
||||
=====
|
||||
|
||||
The persistent file list filters now have a boolean property `forRecursion`.
|
||||
Setting this property to `true`, also sets `alwaysAcceptDirectories`, which means that the recursive operation on the outbound gateways (`ls` and `mget`) will now always traverse the full directory tree each time.
|
||||
This is to solve a problem where changes deep in the directory tree were not detected.
|
||||
In addition, `forRecursion=true` causes the full path to files to be used as the metadata store keys; this solves a problem where the filter did not work properly if a file with the same name appears multiple times in different directories.
|
||||
IMPORTANT: This means that existing keys in a persistent metadata store will not be found for files beneath the top level directory.
|
||||
For this reason, the property is `false` by default; this may change in a future release.
|
||||
|
||||
You can configure the `SmbSimplePatternFileListFilter` and `SmbRegexPatternFileListFilter` to always pass directories by setting the `alwaysAcceptDirectorties` to `true`.
|
||||
Doing so allows recursion for a simple pattern.
|
||||
You can provide one of these filters by using the `filter` property on the gateway.
|
||||
|
||||
See also <<smb-partial>>.
|
||||
|
||||
[[smb-put-command]]
|
||||
==== Using the `put` Command
|
||||
|
||||
`put` sends a file to the remote server.
|
||||
The payload of the message can be a `java.io.File`, a `byte[]`, or a `String`.
|
||||
A `remote-filename-generator` (or expression) is used to name the remote file.
|
||||
Other available attributes include `remote-directory`, `temporary-remote-directory` and their `*-expression` equivalents: `use-temporary-file-name` and `auto-create-directory`.
|
||||
See the https://github.com/spring-projects/spring-integration/tree/main/spring-integration-core/src/main/resources/org/springframework/integration/config[schema documentation] for more information.
|
||||
|
||||
The message payload resulting from a `put` operation is a `String` that contains the full path of the file on the server after transfer.
|
||||
|
||||
==== Using the `mput` Command
|
||||
|
||||
`mput` sends multiple files to the server and supports the following option:
|
||||
|
||||
* `-R`: Recursive -- send all files (possibly filtered) in the directory and subdirectories
|
||||
|
||||
The message payload must be a `java.io.File` (or `String`) that represents a local directory.
|
||||
A collection of `File` or `String` is also supported.
|
||||
|
||||
The same attributes as the <<smb-put-command,`put` command>> are supported.
|
||||
In addition, you can filter files in the local directory with one of `mput-pattern`, `mput-regex`, `mput-filter`, or `mput-filter-expression`.
|
||||
The filter works with recursion, as long as the subdirectories themselves pass the filter.
|
||||
Subdirectories that do not pass the filter are not recursed.
|
||||
|
||||
The message payload resulting from an `mput` operation is a `List<String>` object (that is, a `List` of remote file paths resulting from the transfer).
|
||||
|
||||
See also <<smb-partial>>.
|
||||
|
||||
==== Using the `rm` Command
|
||||
|
||||
The `rm` command has no options.
|
||||
|
||||
If the remove operation was successful, the resulting message payload is `Boolean.TRUE`.
|
||||
Otherwise, the message payload is `Boolean.FALSE`.
|
||||
The `file_remoteDirectory` header holds the remote directory, and the `file_remoteFile` header holds the file name.
|
||||
|
||||
==== Using the `mv` Command
|
||||
|
||||
The `mv` command has no options.
|
||||
|
||||
The `expression` attribute defines the "`from`" path, and the `rename-expression` attribute defines the "`to`" path.
|
||||
By default, the `rename-expression` is `headers['file_renameTo']`.
|
||||
This expression must not evaluate to null or an empty `String`.
|
||||
If necessary, any remote directories needed are created.
|
||||
The payload of the result message is `Boolean.TRUE`.
|
||||
The `file_remoteDirectory` header holds the original remote directory, and the `file_remoteFile` header holds the filename.
|
||||
The `file_renameTo` header holds the new path.
|
||||
|
||||
The `remoteDirectoryExpression` can be used in the `mv` command for convenience.
|
||||
If the "`from`" file is not a full file path, the result of `remoteDirectoryExpression` is used as the remote directory.
|
||||
The same applies for the "`to`" file, for example, if the task is just to rename a remote file in some directory.
|
||||
|
||||
==== Additional Command Information
|
||||
|
||||
The `get` and `mget` commands support the `local-filename-generator-expression` attribute.
|
||||
It defines a SpEL expression to generate the names of local files during the transfer.
|
||||
The root object of the evaluation context is the request message.
|
||||
The `remoteFileName` variable is also available.
|
||||
It is particularly useful for `mget` (for example: `local-filename-generator-expression="#remoteFileName.toUpperCase() + headers.foo"`).
|
||||
|
||||
The `get` and `mget` commands support the `local-directory-expression` attribute.
|
||||
It defines a SpEL expression to generate the names of local directories during the transfer.
|
||||
The root object of the evaluation context is the request message.
|
||||
The `remoteDirectory` variable is also available.
|
||||
It is particularly useful for mget (for example: `local-directory-expression="'/tmp/local/' + #remoteDirectory.toUpperCase() + headers.myheader"`).
|
||||
This attribute is mutually exclusive with the `local-directory` attribute.
|
||||
|
||||
For all commands, the 'expression' property of the gateway holds the path on which the command acts.
|
||||
For the `mget` command, the expression might evaluate to `*`, meaning to retrieve all files, `somedirectory/*`, and other values that end with `*`.
|
||||
|
||||
The `GET`, `MGET`, `PUT`, and `MPUT` commands support a `FileExistsMode` property (`mode` when using the namespace support).
|
||||
This affects the behavior when the local file exists (`GET` and `MGET`) or the remote file exists (`PUT` and `MPUT`).
|
||||
The supported modes are `REPLACE`, `APPEND`, `FAIL`, and `IGNORE`.
|
||||
For backwards compatibility, the default mode for `PUT` and `MPUT` operations is `REPLACE`.
|
||||
For `GET` and `MGET` operations, the default is `FAIL`.
|
||||
|
||||
==== Configuring with Java Configuration
|
||||
|
||||
The following Spring Boot application shows an example of how to configure the outbound gateway with Java configuration:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@SpringBootApplication
|
||||
public class SmbJavaApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder(SmbJavaApplication.class)
|
||||
.web(false)
|
||||
.run(args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SmbSessionFactory smbSessionFactory() {
|
||||
SmbSessionFactory smbSession = new SmbSessionFactory();
|
||||
smbSession.setHost("myHost");
|
||||
smbSession.setPort(445);
|
||||
smbSession.setDomain("myDomain");
|
||||
smbSession.setUsername("myUser");
|
||||
smbSession.setPassword("myPassword");
|
||||
smbSession.setShareAndDir("myShareAndDir");
|
||||
smbSession.setSmbMinVersion(DialectVersion.SMB210);
|
||||
smbSession.setSmbMaxVersion(DialectVersion.SMB311);
|
||||
return smbSession;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "smbChannel")
|
||||
public MessageHandler handler() {
|
||||
SmbOutboundGateway smbOutboundGateway =
|
||||
new SmbOutboundGateway(smbSessionFactory(), "'my_remote_dir/'");
|
||||
smbOutboundGateway.setOutputChannelName("replyChannel");
|
||||
return smbOutboundGateway;
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
==== Configuring with the Java DSL
|
||||
|
||||
The following Spring Boot application shows an example of how to configure the outbound gateway with the Java DSL:
|
||||
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@SpringBootApplication
|
||||
public class SmbJavaApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder(SmbJavaApplication.class)
|
||||
.web(false)
|
||||
.run(args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SmbSessionFactory smbSessionFactory() {
|
||||
SmbSessionFactory smbSession = new SmbSessionFactory();
|
||||
smbSession.setHost("myHost");
|
||||
smbSession.setPort(445);
|
||||
smbSession.setDomain("myDomain");
|
||||
smbSession.setUsername("myUser");
|
||||
smbSession.setPassword("myPassword");
|
||||
smbSession.setShareAndDir("myShareAndDir");
|
||||
smbSession.setSmbMinVersion(DialectVersion.SMB210);
|
||||
smbSession.setSmbMaxVersion(DialectVersion.SMB311);
|
||||
return smbSession;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SmbOutboundGatewaySpec smbOutboundGateway() {
|
||||
return Smb.outboundGateway(smbSessionFactory(),
|
||||
AbstractRemoteFileOutboundGateway.Command.MGET, "payload")
|
||||
.options(AbstractRemoteFileOutboundGateway.Option.RECURSIVE)
|
||||
.regexFileNameFilter("(subSmbSource|.*.txt)")
|
||||
.localDirectoryExpression("'localDirectory/' + #remoteDirectory")
|
||||
.localFilenameExpression("#remoteFileName.replaceFirst('smbSource', 'localTarget')");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IntegrationFlow smbFlow(AbstractRemoteFileOutboundGateway<SmbFile> smbOutboundGateway) {
|
||||
return f -> f
|
||||
.handle(smbOutboundGateway)
|
||||
.channel(c -> c.queue("remoteFileOutputChannel"));
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[[smb-partial]]
|
||||
==== Outbound Gateway Partial Success (`mget` and `mput`)
|
||||
|
||||
When performing operations on multiple files (by using `mget` and `mput`) an exception can occur some time after one or more files have been transferred.
|
||||
In this case a `PartialSuccessException` is thrown.
|
||||
As well as the usual `MessagingException` properties (`failedMessage` and `cause`), this exception has two additional properties:
|
||||
|
||||
* `partialResults`: The successful transfer results.
|
||||
* `derivedInput`: The list of files generated from the request message (such as local files to transfer for an `mput`).
|
||||
|
||||
These attributes let you determine which files were successfully transferred and which were not.
|
||||
|
||||
In the case of a recursive `mput`, the `PartialSuccessException` may have nested `PartialSuccessException` instances.
|
||||
|
||||
Consider the following directory structure:
|
||||
|
||||
====
|
||||
[source]
|
||||
----
|
||||
root/
|
||||
|- file1.txt
|
||||
|- subdir/
|
||||
| - file2.txt
|
||||
| - file3.txt
|
||||
|- zoo.txt
|
||||
----
|
||||
====
|
||||
|
||||
If the exception occurs on `file3.txt`, the `PartialSuccessException` thrown by the gateway has `derivedInput` of `file1.txt`, `subdir`, and `zoo.txt` and `partialResults` of `file1.txt`.
|
||||
Its `cause` is another `PartialSuccessException` with `derivedInput` of `file2.txt` and `file3.txt` and `partialResults` of `file2.txt`.
|
||||
|
||||
[[smb-remote-file-info]]
|
||||
=== Remote File Information
|
||||
|
||||
The `SmbStreamingMessageSource` (<<smb-streaming-inbound>>), `SmbInboundFileSynchronizingMessageSource` (<<smb-inbound>>) and "read"-commands of the `SmbOutboundGateway` (<<smb-outbound-gateway>>) provide additional headers in the message to produce with an information about the remote file:
|
||||
|
||||
* `FileHeaders.REMOTE_HOST_PORT` - the host:port pair the remote session has been connected to during file transfer operation;
|
||||
* `FileHeaders.REMOTE_DIRECTORY` - the remote directory the operation has been performed;
|
||||
* `FileHeaders.REMOTE_FILE` - the remote file name; applicable only for single file operations.
|
||||
|
||||
Since the `SmbInboundFileSynchronizingMessageSource` doesn't produce messages against remote files, but using a local copy, the `AbstractInboundFileSynchronizer` stores an information about remote file in the `MetadataStore` (which can be configured externally) in the URI style (`protocol://host:port/remoteDirectory#remoteFileName`) during synchronization operation.
|
||||
This metadata is retrieved by the `SmbInboundFileSynchronizingMessageSource` when local file is polled.
|
||||
When local file is deleted, it is recommended to remove its metadata entry.
|
||||
The `AbstractInboundFileSynchronizer` provides a `removeRemoteFileMetadata()` callback for this purpose.
|
||||
In addition, there is a `setMetadataStorePrefix()` to be used in the metadata keys.
|
||||
It is recommended to have this prefix be different from the one used in the `MetadataStore`-based `FileListFilter` implementations, when the same `MetadataStore` instance is shared between these components, to avoid entry overriding because both filter and `AbstractInboundFileSynchronizer` use the same local file name for the metadata entry key.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ See <<./graphql.adoc#graphql,GraphQL Support>> for more information.
|
||||
[[x6.0-smb]]
|
||||
=== SMB Support
|
||||
|
||||
SMB support has been added from the Spring Integration Extensions project, including support for Java .
|
||||
SMB support has been added from the Spring Integration Extensions project.
|
||||
The Java DSL (see `org.springframework.integration.smb.dsl.Smb` factory) also has been added to this module.
|
||||
An `SmbStreamingMessageSource` and `SmbOutboundGateway` implementation are introduced.
|
||||
See <<./smb.adoc#smb,SMB Support>> for more information.
|
||||
|
||||
Reference in New Issue
Block a user