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:
@@ -16,10 +16,15 @@
|
||||
|
||||
package org.springframework.integration.smb.session;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jcifs.smb.NtStatus;
|
||||
import jcifs.smb.SmbException;
|
||||
import jcifs.smb.SmbFile;
|
||||
|
||||
import org.springframework.integration.file.remote.RemoteFileTemplate;
|
||||
import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* The SMB-specific {@link RemoteFileTemplate} implementation.
|
||||
@@ -30,12 +35,61 @@ import org.springframework.integration.file.remote.session.SessionFactory;
|
||||
*/
|
||||
public class SmbRemoteFileTemplate extends RemoteFileTemplate<SmbFile> {
|
||||
|
||||
protected static final List<Integer> NOT_DIRTY_STATUSES = // NOSONAR
|
||||
List.of(
|
||||
NtStatus.NT_STATUS_INVALID_HANDLE,
|
||||
NtStatus.NT_STATUS_END_OF_FILE,
|
||||
NtStatus.NT_STATUS_NO_SUCH_FILE,
|
||||
NtStatus.NT_STATUS_DUPLICATE_NAME,
|
||||
NtStatus.NT_STATUS_FILE_IS_A_DIRECTORY,
|
||||
NtStatus.NT_STATUS_NOT_A_DIRECTORY,
|
||||
NtStatus.NT_STATUS_NOT_FOUND,
|
||||
NtStatus.NT_STATUS_OBJECT_NAME_COLLISION,
|
||||
NtStatus.NT_STATUS_OBJECT_NAME_INVALID,
|
||||
NtStatus.NT_STATUS_OBJECT_NAME_NOT_FOUND,
|
||||
NtStatus.NT_STATUS_OBJECT_PATH_INVALID,
|
||||
NtStatus.NT_STATUS_OBJECT_PATH_NOT_FOUND,
|
||||
NtStatus.NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
|
||||
NtStatus.NT_STATUS_CANNOT_DELETE
|
||||
);
|
||||
|
||||
/**
|
||||
* Construct a {@link SmbRemoteFileTemplate} with the supplied session factory.
|
||||
*
|
||||
* @param sessionFactory the session factory.
|
||||
*/
|
||||
public SmbRemoteFileTemplate(SessionFactory<SmbFile> sessionFactory) {
|
||||
super(sessionFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldMarkSessionAsDirty(Exception ex) {
|
||||
SmbException smbException = findSmbException(ex);
|
||||
if (smbException != null) {
|
||||
return isStatusDirty(smbException.getNtStatus());
|
||||
}
|
||||
else {
|
||||
return super.shouldMarkSessionAsDirty(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if {@link SmbException#getNtStatus()} is treated as fatal.
|
||||
* @param status the value from {@link SmbException#getNtStatus()}.
|
||||
* @return true if {@link SmbException#getNtStatus()} is treated as fatal.
|
||||
* @since 6.0.8
|
||||
*/
|
||||
protected boolean isStatusDirty(int status) {
|
||||
return !NOT_DIRTY_STATUSES.contains(status);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static SmbException findSmbException(Throwable ex) {
|
||||
if (ex == null || ex instanceof SmbException) {
|
||||
return (SmbException) ex;
|
||||
}
|
||||
else {
|
||||
return findSmbException(ex.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
* Copyright 2012-2023 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.
|
||||
@@ -21,9 +21,14 @@ import java.io.IOException;
|
||||
import jcifs.smb.SmbFile;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.integration.file.remote.session.CachingSessionFactory;
|
||||
import org.springframework.integration.file.remote.session.Session;
|
||||
import org.springframework.integration.smb.SmbTestSupport;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -85,4 +90,24 @@ public class SmbSessionTests extends SmbTestSupport {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sessionIsNotDirtyOnNoSuchFileError() {
|
||||
CachingSessionFactory<SmbFile> cachingSessionFactory = new CachingSessionFactory<>(smbSessionFactory);
|
||||
Session<SmbFile> session = cachingSessionFactory.getSession();
|
||||
session.close();
|
||||
|
||||
SmbRemoteFileTemplate template = new SmbRemoteFileTemplate(cachingSessionFactory);
|
||||
|
||||
assertThatExceptionOfType(MessagingException.class)
|
||||
.isThrownBy(() -> template.rename("No_such_file1", "No_such_file2"))
|
||||
.withRootCauseInstanceOf(IOException.class)
|
||||
.withStackTraceContaining("The system cannot find the file specified");
|
||||
|
||||
Session<SmbFile> newSession = cachingSessionFactory.getSession();
|
||||
assertThat(TestUtils.getPropertyValue(newSession, "targetSession"))
|
||||
.isSameAs(TestUtils.getPropertyValue(session, "targetSession"));
|
||||
|
||||
newSession.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user