GH-3249: Fix RemoteFileTemplate dead lock in send

Fixes: https://github.com/spring-projects/spring-integration/issues/3249

When the `CachingSessionFactory` is configured with small enough pool
and it is very likely that dead lock may happen when `RemoteFileTemplate.send()`
is used.
The problem happens when we reach the `RemoteFileTemplate.exists()` call
which is done from the internal method called from already pulled from cache
`Session`

* Fix `RemoteFileTemplate` to use a `session.exists()` instead on the provided
into the method `Session`
* Demonstrate the problem in the `SftpRemoteFileTemplateTests.testNoDeadLockOnSend()`

**Cherry-pick to 5.2.x, 5.1.x & 4.3.x**

Fix RemoteFileOutboundGWTests for the proper mock
This commit is contained in:
Artem Bilan
2020-04-18 21:06:15 -04:00
committed by Gary Russell
parent aa65955e00
commit c00c319acb
3 changed files with 52 additions and 17 deletions

View File

@@ -389,7 +389,7 @@ public class RemoteFileTemplate<F> implements RemoteFileOperations<F>, Initializ
public boolean get(Message<?> message, InputStreamCallback callback) {
Assert.notNull(this.fileNameProcessor, "A 'fileNameExpression' is needed to use get");
String remotePath = this.fileNameProcessor.processMessage(message);
return this.get(remotePath, callback);
return get(remotePath, callback);
}
@Override
@@ -545,7 +545,7 @@ public class RemoteFileTemplate<F> implements RemoteFileOperations<F>, Initializ
session.append(inputStream, tempFilePath);
}
else {
if (exists(remoteFilePath)) {
if (session.exists(remoteFilePath)) {
if (FileExistsMode.FAIL.equals(mode)) {
throw new MessagingException(
"The destination file already exists at '" + remoteFilePath + "'.");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
@@ -845,14 +846,10 @@ public class RemoteFileOutboundGatewayTests {
SessionFactory<TestLsEntry> sessionFactory = mock(SessionFactory.class);
@SuppressWarnings("unchecked")
Session<TestLsEntry> session = mock(Session.class);
RemoteFileTemplate<TestLsEntry> template = new RemoteFileTemplate<TestLsEntry>(sessionFactory) {
@Override
public boolean exists(String path) {
return true;
}
};
willReturn(Boolean.TRUE)
.given(session)
.exists(anyString());
RemoteFileTemplate<TestLsEntry> template = new RemoteFileTemplate<>(sessionFactory);
template.setRemoteDirectoryExpression(new LiteralExpression("foo/"));
template.setBeanFactory(mock(BeanFactory.class));
template.afterPropertiesSet();