Skip to content

Commit 4bb4624

Browse files
artembilanspring-builds
authored andcommitted
GH-9684: Auto-create temporary remote directory
Fixes: #9684 Issue link: #9684 The `RemoteFileTemplate` is missing to create a temporary remote directory * Fix `RemoteFileTemplate.sendFileToRemoteDirectory()` to create a `temporaryRemoteDirectory` as well if it is different from already created `remoteDirectory` * Add `SftpServerOutboundTests.autoCreateTemporaryDirectory()` to verify that `temporaryRemoteDirectory` is created and in-use * Some other `SftpServerOutboundTests` refactoring for better code style (cherry picked from commit a4b193f)
1 parent d8fb023 commit 4bb4624

File tree

3 files changed

+196
-173
lines changed

3 files changed

+196
-173
lines changed

spring-integration-file/src/main/java/org/springframework/integration/file/remote/RemoteFileTemplate.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,10 +570,17 @@ private void sendFileToRemoteDirectory(InputStream inputStream, String temporary
570570
if (this.autoCreateDirectory) {
571571
try {
572572
RemoteFileUtils.makeDirectories(remoteDirectory, session, this.remoteFileSeparator, this.logger);
573+
if (!temporaryRemoteDirectory.equals(remoteDirectory)) {
574+
RemoteFileUtils.makeDirectories(temporaryRemoteDirectory, session, this.remoteFileSeparator,
575+
this.logger);
576+
}
573577
}
574578
catch (@SuppressWarnings("unused") IllegalStateException e) {
575579
// Revert to old FTP behavior if recursive mkdir fails, for backwards compatibility
576580
session.mkdir(remoteDirectory);
581+
if (!temporaryRemoteDirectory.equals(remoteDirectory)) {
582+
session.mkdir(temporaryRemoteDirectory);
583+
}
577584
}
578585
}
579586

spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpServerOutboundTests-context.xml

Lines changed: 138 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<beans xmlns="http://www.springframework.org/schema/beans"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xmlns:int-sftp="http://www.springframework.org/schema/integration/sftp"
5-
xmlns:int="http://www.springframework.org/schema/integration"
6-
xmlns:int-file="http://www.springframework.org/schema/integration/file"
7-
xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp https://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:int-sftp="http://www.springframework.org/schema/integration/sftp"
5+
xmlns:int="http://www.springframework.org/schema/integration"
6+
xmlns:int-file="http://www.springframework.org/schema/integration/file"
7+
xsi:schemaLocation="http://www.springframework.org/schema/integration/sftp https://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd
88
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
99
http://www.springframework.org/schema/integration/file https://www.springframework.org/schema/integration/file/spring-integration-file.xsd
1010
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd">
1111

12-
<bean id="extraConfig" class="org.springframework.integration.sftp.outbound.SftpServerOutboundTests$Config" />
12+
<bean id="extraConfig" class="org.springframework.integration.sftp.outbound.SftpServerOutboundTests$Config"/>
1313

1414
<int:channel id="output">
1515
<int:queue/>
@@ -18,87 +18,88 @@
1818
<int:channel id="inboundGet"/>
1919

2020
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
21-
request-channel="inboundGet"
22-
command="get"
23-
command-options="-P"
24-
expression="payload"
25-
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory.toUpperCase()"
26-
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
27-
reply-channel="output"/>
21+
request-channel="inboundGet"
22+
command="get"
23+
command-options="-P"
24+
expression="payload"
25+
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory.toUpperCase()"
26+
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
27+
reply-channel="output"/>
2828

2929
<int:channel id="invalidDirExpression"/>
3030

3131
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
32-
request-channel="invalidDirExpression"
33-
command="get"
34-
expression="payload"
35-
local-directory-expression="T(java.io.File).separator + #remoteDirectory + '?:'"
36-
reply-channel="output"/>
32+
request-channel="invalidDirExpression"
33+
command="get"
34+
expression="payload"
35+
local-directory-expression="T(java.io.File).separator + #remoteDirectory + '?:'"
36+
reply-channel="output"/>
3737

3838
<int:channel id="inboundMGet"/>
3939

4040
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
41-
request-channel="inboundMGet"
42-
command="mget"
43-
command-options="-P"
44-
expression="payload"
45-
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
46-
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
47-
reply-channel="output"/>
41+
request-channel="inboundMGet"
42+
command="mget"
43+
command-options="-P"
44+
expression="payload"
45+
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
46+
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
47+
reply-channel="output"/>
4848

4949
<int:channel id="inboundMGetRecursive"/>
5050

5151
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
52-
request-channel="inboundMGetRecursive"
53-
command="mget"
54-
expression="payload"
55-
command-options="-R -P"
56-
mode="REPLACE_IF_MODIFIED"
57-
filter="dotStarDotTxtFilter"
58-
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
59-
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
60-
reply-channel="output"/>
52+
request-channel="inboundMGetRecursive"
53+
command="mget"
54+
expression="payload"
55+
command-options="-R -P"
56+
mode="REPLACE_IF_MODIFIED"
57+
filter="dotStarDotTxtFilter"
58+
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
59+
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
60+
reply-channel="output"/>
6161

6262
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
63-
request-channel="inboundLSRecursive"
64-
command="ls"
65-
expression="payload"
66-
command-options="-R -dirs"
67-
mode="REPLACE_IF_MODIFIED"
68-
filter="dotStarDotTxtFilter"
69-
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
70-
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
71-
reply-channel="output"/>
63+
request-channel="inboundLSRecursive"
64+
command="ls"
65+
expression="payload"
66+
command-options="-R -dirs"
67+
mode="REPLACE_IF_MODIFIED"
68+
filter="dotStarDotTxtFilter"
69+
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
70+
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
71+
reply-channel="output"/>
7272

7373
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
74-
request-channel="inboundLSRecursiveALL"
75-
command="ls"
76-
expression="payload"
77-
command-options="-a -R -dirs"
78-
mode="REPLACE_IF_MODIFIED"
79-
filter="dotStarDotTxtFilter"
80-
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
81-
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
82-
reply-channel="output"/>
74+
request-channel="inboundLSRecursiveALL"
75+
command="ls"
76+
expression="payload"
77+
command-options="-a -R -dirs"
78+
mode="REPLACE_IF_MODIFIED"
79+
filter="dotStarDotTxtFilter"
80+
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
81+
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
82+
reply-channel="output"/>
8383

8484
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
85-
request-channel="inboundLSRecursiveNoDirs"
86-
command="ls"
87-
expression="payload"
88-
command-options="-R"
89-
mode="REPLACE_IF_MODIFIED"
90-
filter="persistentFilter"
91-
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
92-
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
93-
reply-channel="output"/>
85+
request-channel="inboundLSRecursiveNoDirs"
86+
command="ls"
87+
expression="payload"
88+
command-options="-R"
89+
mode="REPLACE_IF_MODIFIED"
90+
filter="persistentFilter"
91+
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
92+
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
93+
reply-channel="output"/>
9494

9595
<bean id="dotStarDotTxtFilter"
96-
class="org.springframework.integration.sftp.filters.SftpRegexPatternFileListFilter">
97-
<constructor-arg value="^.*\.txt$" />
98-
<property name="alwaysAcceptDirectories" value="true" />
96+
class="org.springframework.integration.sftp.filters.SftpRegexPatternFileListFilter">
97+
<constructor-arg value="^.*\.txt$"/>
98+
<property name="alwaysAcceptDirectories" value="true"/>
9999
</bean>
100100

101-
<bean id="persistentFilter" class="org.springframework.integration.sftp.filters.SftpPersistentAcceptOnceFileListFilter">
101+
<bean id="persistentFilter"
102+
class="org.springframework.integration.sftp.filters.SftpPersistentAcceptOnceFileListFilter">
102103
<constructor-arg ref="store"/>
103104
<constructor-arg value="test"/>
104105
<property name="forRecursion" value="true"/>
@@ -107,89 +108,95 @@
107108

108109
<bean id="store" class="org.springframework.integration.metadata.PropertiesPersistingMetadataStore">
109110
<property name="baseDirectory"
110-
value="#{T(org.springframework.integration.file.remote.RemoteFileTestSupport).getScratchTempFolder().absolutePath}"/>
111+
value="#{T(org.springframework.integration.file.remote.RemoteFileTestSupport).getScratchTempFolder().absolutePath}"/>
111112
</bean>
112113

113114

114115
<int:channel id="inboundMGetRecursiveFiltered"/>
115116

116117
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
117-
request-channel="inboundMGetRecursiveFiltered"
118-
command="mget"
119-
expression="payload"
120-
command-options="-R"
121-
filename-regex="(subSftpSource|.*1.txt)"
122-
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
123-
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
124-
reply-channel="output"/>
118+
request-channel="inboundMGetRecursiveFiltered"
119+
command="mget"
120+
expression="payload"
121+
command-options="-R"
122+
filename-regex="(subSftpSource|.*1.txt)"
123+
local-directory-expression="@extraConfig.targetLocalDirectoryName + #remoteDirectory"
124+
local-filename-generator-expression="#remoteFileName.replaceFirst('sftpSource', 'localTarget')"
125+
reply-channel="output"/>
125126

126127
<int:channel id="inboundMPut"/>
127128

128129
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
129-
request-channel="inboundMPut"
130-
command="mput"
131-
auto-create-directory="true"
132-
filename-pattern="*.txt"
133-
expression="payload"
134-
chmod="600"
135-
remote-directory="sftpTarget"
136-
reply-channel="output"/>
130+
request-channel="inboundMPut"
131+
command="mput"
132+
auto-create-directory="true"
133+
filename-pattern="*.txt"
134+
expression="payload"
135+
chmod="600"
136+
remote-directory="sftpTarget"
137+
reply-channel="output"/>
137138

138139
<int:channel id="inboundMPutRecursive"/>
139140

140141
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
141-
request-channel="inboundMPutRecursive"
142-
command="mput"
143-
command-options="-R"
144-
auto-create-directory="true"
145-
filename-pattern="*.txt"
146-
expression="payload"
147-
remote-directory="sftpTarget"
148-
reply-channel="output"/>
142+
request-channel="inboundMPutRecursive"
143+
command="mput"
144+
command-options="-R"
145+
auto-create-directory="true"
146+
filename-pattern="*.txt"
147+
expression="payload"
148+
remote-directory="sftpTarget"
149+
reply-channel="output"/>
149150

150151
<int:channel id="inboundMPutRecursiveFiltered"/>
151152

152153
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
153-
request-channel="inboundMPutRecursiveFiltered"
154-
command="mput"
155-
command-options="-R"
156-
mput-regex="(.*1.txt|sub.*)"
157-
auto-create-directory="true"
158-
filename-pattern="*.txt"
159-
expression="payload"
160-
remote-directory="sftpTarget"
161-
reply-channel="output"/>
162-
163-
<int:channel id="appending" />
154+
request-channel="inboundMPutRecursiveFiltered"
155+
command="mput"
156+
command-options="-R"
157+
mput-regex="(.*1.txt|sub.*)"
158+
auto-create-directory="true"
159+
filename-pattern="*.txt"
160+
expression="payload"
161+
remote-directory="sftpTarget"
162+
reply-channel="output"/>
163+
164+
<int:channel id="appending"/>
164165

165166
<int-sftp:outbound-channel-adapter id="appender"
166-
session-factory="sftpSessionFactory"
167-
channel="appending"
168-
mode="APPEND"
169-
use-temporary-file-name="false"
170-
remote-directory="sftpTarget"
171-
auto-create-directory="true"
172-
remote-file-separator="/" />
167+
session-factory="sftpSessionFactory"
168+
channel="appending"
169+
mode="APPEND"
170+
use-temporary-file-name="false"
171+
remote-directory="sftpTarget"
172+
auto-create-directory="true"
173+
remote-file-separator="/"/>
173174

174-
<int:channel id="ignoring" />
175+
<int:channel id="ignoring"/>
175176

176177
<int-sftp:outbound-channel-adapter id="ignore"
177-
session-factory="sftpSessionFactory"
178-
channel="ignoring"
179-
mode="IGNORE"
180-
remote-directory="sftpTarget"
181-
auto-create-directory="true"
182-
remote-file-separator="/" />
178+
session-factory="sftpSessionFactory"
179+
channel="ignoring"
180+
mode="IGNORE"
181+
remote-directory="sftpTarget"
182+
auto-create-directory="true"
183+
remote-file-separator="/"/>
183184

184-
<int:channel id="failing" />
185+
<int:channel id="failing"/>
185186

186187
<int-sftp:outbound-channel-adapter id="fail"
187-
session-factory="sftpSessionFactory"
188-
channel="failing"
189-
mode="FAIL"
190-
remote-directory="sftpTarget"
191-
auto-create-directory="true"
192-
remote-file-separator="/" />
188+
session-factory="sftpSessionFactory"
189+
channel="failing"
190+
mode="FAIL"
191+
remote-directory="sftpTarget"
192+
auto-create-directory="true"
193+
remote-file-separator="/"/>
194+
195+
<int-sftp:outbound-channel-adapter id="sendFileChannel"
196+
session-factory="sftpSessionFactory"
197+
remote-directory="sftpTarget"
198+
temporary-remote-directory="sftpTarget_tmp"
199+
auto-create-directory="true"/>
193200

194201
<bean id="cachingSessionFactory" class="org.springframework.integration.file.remote.session.CachingSessionFactory">
195202
<constructor-arg name="sessionFactory" ref="sftpSessionFactory"/>
@@ -198,23 +205,23 @@
198205
</bean>
199206

200207
<int-sftp:outbound-gateway session-factory="cachingSessionFactory"
201-
request-channel="inboundGetStream"
202-
command="get"
203-
command-options="-stream"
204-
expression="payload"
205-
remote-directory="ftpTarget"
206-
reply-channel="stream" />
208+
request-channel="inboundGetStream"
209+
command="get"
210+
command-options="-stream"
211+
expression="payload"
212+
remote-directory="ftpTarget"
213+
reply-channel="stream"/>
207214

208215
<int:chain input-channel="stream">
209-
<int-file:splitter markers="true" />
216+
<int-file:splitter markers="true"/>
210217
<int:payload-type-router resolution-required="false" default-output-channel="output">
211218
<int:mapping type="org.springframework.integration.file.splitter.FileSplitter$FileMarker"
212-
channel="markers" />
219+
channel="markers"/>
213220
</int:payload-type-router>
214221
</int:chain>
215222

216223
<int:service-activator input-channel="markers"
217-
expression="payload.mark.toString().equals('END') ? headers['closeableResource'].close() : null"/>
224+
expression="payload.mark.toString().equals('END') ? headers['closeableResource'].close() : null"/>
218225

219226
<int-sftp:outbound-gateway
220227
session-factory="sftpSessionFactory"

0 commit comments

Comments
 (0)