GH-8745: Add RFT.shouldMarkSessionAsDirty() (#8759)
* GH-8745: Add RFT.shouldMarkSessionAsDirty() Fixes https://github.com/spring-projects/spring-integration/issues/8745 Not all errors caught in the `RemoteFileTemplate.execute()` are fatal to mark session as dirty and physically close the target session in the cache * Introduce a `RemoteFileTemplate.shouldMarkSessionAsDirty()` to consult with an exception if it is really a fatal error to close the session in the end. * Override `shouldMarkSessionAsDirty()` in the `RemoteFileTemplate` implementations to check statuses of respective protocol errors **Cherry-pick to `6.1.x` & `6.0.x`** * * Fix tests for pool interaction * * Fix language in Javadocs * Add more `not dirty` statuses to `SftpRemoteFileTemplate` & `SmbRemoteFileTemplate`
This commit is contained in:
@@ -451,27 +451,42 @@ public class RemoteFileTemplate<F> implements RemoteFileOperations<F>, Initializ
|
||||
}
|
||||
return callback.doInSession(session);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (session != null) {
|
||||
catch (Exception ex) {
|
||||
if (session != null && shouldMarkSessionAsDirty(ex)) {
|
||||
session.dirty();
|
||||
}
|
||||
if (e instanceof MessagingException) { // NOSONAR
|
||||
throw (MessagingException) e;
|
||||
if (ex instanceof MessagingException messagingException) { // NOSONAR
|
||||
throw messagingException;
|
||||
}
|
||||
throw new MessagingException("Failed to execute on session", e);
|
||||
throw new MessagingException("Failed to execute on session", ex);
|
||||
}
|
||||
finally {
|
||||
if (!invokeScope && session != null) {
|
||||
try {
|
||||
session.close();
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
this.logger.debug("failed to close Session", ignored);
|
||||
catch (Exception ex) {
|
||||
this.logger.debug("failed to close Session", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether {@link Session#dirty()} should be called
|
||||
* in the {@link #execute(SessionCallback)} when an exception is thrown from the callback.
|
||||
* By default, this method returns {@code true}.
|
||||
* Remote file protocol extensions can override this method to provide
|
||||
* a specific strategy against the thrown exception, e.g. {@code file not found} error
|
||||
* is not a signal that session is broken.
|
||||
* @param ex the exception to check if {@link Session} must be marked as dirty.
|
||||
* @return true if {@link Session#dirty()} should be called.
|
||||
* @since 6.0.8
|
||||
*/
|
||||
protected boolean shouldMarkSessionAsDirty(Exception ex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T invoke(OperationsCallback<F, T> action) {
|
||||
Session<F> contextSession = this.contextSessions.get();
|
||||
@@ -503,8 +518,7 @@ public class RemoteFileTemplate<F> implements RemoteFileOperations<F>, Initializ
|
||||
private StreamHolder payloadToInputStream(Message<?> message) throws MessageDeliveryException {
|
||||
Object payload = message.getPayload();
|
||||
try {
|
||||
if (payload instanceof File) {
|
||||
File inputFile = (File) payload;
|
||||
if (payload instanceof File inputFile) {
|
||||
if (inputFile.exists()) {
|
||||
return new StreamHolder(
|
||||
new BufferedInputStream(new FileInputStream(inputFile)), inputFile.getAbsolutePath());
|
||||
@@ -526,8 +540,7 @@ public class RemoteFileTemplate<F> implements RemoteFileOperations<F>, Initializ
|
||||
else if (payload instanceof InputStream) {
|
||||
return new StreamHolder((InputStream) payload, "InputStream payload");
|
||||
}
|
||||
else if (payload instanceof Resource) {
|
||||
Resource resource = (Resource) payload;
|
||||
else if (payload instanceof Resource resource) {
|
||||
String filename = resource.getFilename();
|
||||
return new StreamHolder(resource.getInputStream(), filename != null ? filename : "Resource payload");
|
||||
}
|
||||
@@ -619,16 +632,7 @@ public class RemoteFileTemplate<F> implements RemoteFileOperations<F>, Initializ
|
||||
}
|
||||
}
|
||||
|
||||
private static final class StreamHolder {
|
||||
|
||||
private final InputStream stream;
|
||||
|
||||
private final String name;
|
||||
|
||||
StreamHolder(InputStream stream, String name) {
|
||||
this.stream = stream;
|
||||
this.name = name;
|
||||
}
|
||||
private record StreamHolder(InputStream stream, String name) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user