-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GH-9869: Introduce
AbstractRecentFileListFilter
strategy
Fixes: #9869 Currently, FileListFilters on the last modified attribute of a file are limited to the use case of discarding files that are too young. It would be great to have a filter implementation which would accept files which are not old enough. * Implement `AbstractRecentFileListFilter` for all the supported file protocols
- Loading branch information
1 parent
7680e02
commit 8bfb5d2
Showing
14 changed files
with
517 additions
and
2 deletions.
There are no files selected for viewing
81 changes: 81 additions & 0 deletions
81
.../main/java/org/springframework/integration/file/filters/AbstractRecentFileListFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Copyright 2025 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.integration.file.filters; | ||
|
||
import java.time.Duration; | ||
import java.time.Instant; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
/** | ||
* The {@link FileListFilter} to accept only files which are recent according to provided {@code age}: | ||
* the {@code lastModified} of the file is more than the age in comparison with the current time. | ||
* In other words, accept those files which are not old enough yet. | ||
* | ||
* @param <F> The type that will be filtered. | ||
* | ||
* @author Artem Bilan | ||
* | ||
* @since 6.5 | ||
*/ | ||
public abstract class AbstractRecentFileListFilter<F> implements FileListFilter<F> { | ||
|
||
protected static final long ONE_SECOND = 1000; | ||
|
||
private final Duration age; | ||
|
||
/** | ||
* Construct an instance with default age as 1 day. | ||
*/ | ||
public AbstractRecentFileListFilter() { | ||
this(Duration.ofDays(1)); | ||
} | ||
|
||
public AbstractRecentFileListFilter(Duration age) { | ||
this.age = age; | ||
} | ||
|
||
@Override | ||
public boolean supportsSingleFileFiltering() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public List<F> filterFiles(F[] files) { | ||
List<F> list = new ArrayList<>(); | ||
Instant now = Instant.now(); | ||
for (F file : files) { | ||
if (!fileIsAged(file, now)) { | ||
list.add(file); | ||
} | ||
} | ||
|
||
return list; | ||
} | ||
|
||
@Override | ||
public boolean accept(F file) { | ||
return !fileIsAged(file, Instant.now()); | ||
} | ||
|
||
protected boolean fileIsAged(F file, Instant now) { | ||
return getLastModified(file).plus(this.age).isBefore(now); | ||
} | ||
|
||
protected abstract Instant getLastModified(F remoteFile); | ||
|
||
} |
44 changes: 44 additions & 0 deletions
44
...file/src/main/java/org/springframework/integration/file/filters/RecentFileListFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* Copyright 2025 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.integration.file.filters; | ||
|
||
import java.io.File; | ||
import java.time.Duration; | ||
import java.time.Instant; | ||
|
||
/** | ||
* The {@link AbstractRecentFileListFilter} implementation for local file system. | ||
* | ||
* @author Artem Bilan | ||
* | ||
* @since 6.5 | ||
*/ | ||
public class RecentFileListFilter extends AbstractRecentFileListFilter<File> { | ||
|
||
public RecentFileListFilter() { | ||
} | ||
|
||
public RecentFileListFilter(Duration age) { | ||
super(age); | ||
} | ||
|
||
@Override | ||
protected Instant getLastModified(File file) { | ||
return Instant.ofEpochSecond(file.lastModified() / ONE_SECOND); | ||
} | ||
|
||
} |
56 changes: 56 additions & 0 deletions
56
...src/test/java/org/springframework/integration/file/filters/RecentFileListFilterTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* Copyright 2025 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.integration.file.filters; | ||
|
||
import java.io.File; | ||
import java.io.FileOutputStream; | ||
import java.time.Duration; | ||
import java.time.Instant; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.io.TempDir; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
/** | ||
* @author Artem Bilan | ||
* | ||
* @since 6.5 | ||
* | ||
*/ | ||
public class RecentFileListFilterTests { | ||
|
||
@TempDir | ||
public File folder; | ||
|
||
@Test | ||
public void testAge() throws Exception { | ||
RecentFileListFilter filter = new RecentFileListFilter(Duration.ofHours(20)); | ||
File testFile = new File(folder, "test.tmp"); | ||
FileOutputStream fileOutputStream = new FileOutputStream(testFile); | ||
fileOutputStream.write("x".getBytes()); | ||
fileOutputStream.close(); | ||
assertThat(filter.filterFiles(new File[] {testFile})).hasSize(1); | ||
assertThat(filter.accept(testFile)).isTrue(); | ||
|
||
testFile.setLastModified(Instant.now().minus(Duration.ofDays(1)).toEpochMilli()); | ||
|
||
assertThat(filter.filterFiles(new File[] {testFile})).hasSize(0); | ||
assertThat(filter.accept(testFile)).isFalse(); | ||
} | ||
|
||
} |
48 changes: 48 additions & 0 deletions
48
...tp/src/main/java/org/springframework/integration/ftp/filters/FtpRecentFileListFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright 2025 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.integration.ftp.filters; | ||
|
||
import java.time.Duration; | ||
import java.time.Instant; | ||
|
||
import org.apache.commons.net.ftp.FTPFile; | ||
|
||
import org.springframework.integration.file.filters.AbstractRecentFileListFilter; | ||
|
||
/** | ||
* The {@link AbstractRecentFileListFilter} implementation for FTP protocol. | ||
* | ||
* @author Artem Bilan | ||
* | ||
* @since 6.5 | ||
*/ | ||
public class FtpRecentFileListFilter extends AbstractRecentFileListFilter<FTPFile> { | ||
|
||
public FtpRecentFileListFilter() { | ||
super(); | ||
} | ||
|
||
public FtpRecentFileListFilter(Duration age) { | ||
super(age); | ||
} | ||
|
||
@Override | ||
protected Instant getLastModified(FTPFile remoteFile) { | ||
return remoteFile.getTimestampInstant(); | ||
} | ||
|
||
} |
57 changes: 57 additions & 0 deletions
57
...c/test/java/org/springframework/integration/ftp/filters/FtpRecentFileListFilterTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* Copyright 2025 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.integration.ftp.filters; | ||
|
||
import java.time.Duration; | ||
import java.util.Calendar; | ||
|
||
import org.apache.commons.net.ftp.FTPFile; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
/** | ||
* @author Artem Bilan | ||
* | ||
* @since 6.5 | ||
*/ | ||
public class FtpRecentFileListFilterTests { | ||
|
||
@Test | ||
public void testAge() { | ||
FtpRecentFileListFilter filter = new FtpRecentFileListFilter(Duration.ofHours(20)); | ||
FTPFile ftpFile1 = new FTPFile(); | ||
ftpFile1.setName("foo"); | ||
ftpFile1.setTimestamp(Calendar.getInstance()); | ||
FTPFile ftpFile2 = new FTPFile(); | ||
ftpFile2.setName("bar"); | ||
ftpFile2.setTimestamp(Calendar.getInstance()); | ||
FTPFile[] files = new FTPFile[] {ftpFile1, ftpFile2}; | ||
assertThat(filter.filterFiles(files)).hasSize(2); | ||
assertThat(filter.accept(ftpFile1)).isTrue(); | ||
assertThat(filter.accept(ftpFile2)).isTrue(); | ||
|
||
// Make a file as of yesterday's | ||
final Calendar calendar = Calendar.getInstance(); | ||
calendar.add(Calendar.DATE, -1); | ||
ftpFile2.setTimestamp(calendar); | ||
|
||
assertThat(filter.filterFiles(files)).hasSize(1); | ||
assertThat(filter.accept(ftpFile1)).isTrue(); | ||
} | ||
|
||
} |
48 changes: 48 additions & 0 deletions
48
.../src/main/java/org/springframework/integration/sftp/filters/SftpRecentFileListFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright 2025 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.integration.sftp.filters; | ||
|
||
import java.time.Duration; | ||
import java.time.Instant; | ||
|
||
import org.apache.sshd.sftp.client.SftpClient; | ||
|
||
import org.springframework.integration.file.filters.AbstractRecentFileListFilter; | ||
|
||
/** | ||
* The {@link AbstractRecentFileListFilter} implementation for SFTP protocol. | ||
* | ||
* @author Artem Bilan | ||
* | ||
* @since 6.5 | ||
*/ | ||
public class SftpRecentFileListFilter extends AbstractRecentFileListFilter<SftpClient.DirEntry> { | ||
|
||
public SftpRecentFileListFilter() { | ||
super(); | ||
} | ||
|
||
public SftpRecentFileListFilter(Duration age) { | ||
super(age); | ||
} | ||
|
||
@Override | ||
protected Instant getLastModified(SftpClient.DirEntry remoteFile) { | ||
return remoteFile.getAttributes().getModifyTime().toInstant(); | ||
} | ||
|
||
} |
59 changes: 59 additions & 0 deletions
59
...test/java/org/springframework/integration/sftp/filters/SftpRecentFileListFilterTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Copyright 2025 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. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.integration.sftp.filters; | ||
|
||
import java.nio.file.attribute.FileTime; | ||
import java.time.Duration; | ||
import java.time.Instant; | ||
|
||
import org.apache.sshd.sftp.client.SftpClient; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
/** | ||
* @author Artem Bilan | ||
* | ||
* @since 6.5 | ||
*/ | ||
public class SftpRecentFileListFilterTests { | ||
|
||
@Test | ||
public void testAge() { | ||
SftpRecentFileListFilter filter = new SftpRecentFileListFilter(Duration.ofHours(20)); | ||
SftpClient.Attributes attributes1 = new SftpClient.Attributes(); | ||
attributes1.setModifyTime(FileTime.from(Instant.now())); | ||
SftpClient.Attributes attributes2 = new SftpClient.Attributes(); | ||
attributes2.setModifyTime(FileTime.from(Instant.now())); | ||
|
||
SftpClient.DirEntry sftpFile1 = new SftpClient.DirEntry("foo", "foo", attributes1); | ||
SftpClient.DirEntry sftpFile2 = new SftpClient.DirEntry("bar", "bar", attributes2); | ||
|
||
SftpClient.DirEntry[] files = new SftpClient.DirEntry[] {sftpFile1, sftpFile2}; | ||
|
||
assertThat(filter.filterFiles(files)).hasSize(2); | ||
assertThat(filter.accept(sftpFile1)).isTrue(); | ||
assertThat(filter.accept(sftpFile2)).isTrue(); | ||
|
||
FileTime fileTime = FileTime.from(Instant.now().minus(Duration.ofDays(1))); | ||
sftpFile2.getAttributes().setModifyTime(fileTime); | ||
assertThat(filter.filterFiles(files)).hasSize(1); | ||
assertThat(filter.accept(sftpFile1)).isTrue(); | ||
assertThat(filter.accept(sftpFile2)).isFalse(); | ||
} | ||
|
||
} |
Oops, something went wrong.