INT-4067: Cover empty file case in FileSplitter
JIRA: https://jira.spring.io/browse/INT-4067 When `FileSplitter` is configured with `markers = true` and file is empty, an `iterator` for file throws `IOException: Stream closed`, because we close the `buffer` just after the first `readLine()` attempt, but still return `true` from the first `hasNext()` call where the `this.sof` and `this.eof` are `true` for markers. Add logic to mark internal splitter `iterator` as `done` where we don't have content and still in `sof` state.
This commit is contained in:
committed by
Gary Russell
parent
2cb5a0704a
commit
4cef58bc86
12
build.gradle
12
build.gradle
@@ -3,22 +3,20 @@ buildscript {
|
||||
maven { url 'https://repo.spring.io/plugins-release' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'io.spring.gradle:spring-io-plugin:0.0.4.RELEASE'
|
||||
classpath 'io.spring.gradle:spring-io-plugin:0.0.5.RELEASE'
|
||||
classpath 'io.spring.gradle:docbook-reference-plugin:0.3.1'
|
||||
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.0'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "org.sonarqube" version "1.2"
|
||||
id 'java'
|
||||
id 'base'
|
||||
id 'org.sonarqube' version '1.2'
|
||||
}
|
||||
|
||||
description = 'Spring Integration'
|
||||
|
||||
apply plugin: 'base'
|
||||
apply plugin: 'idea'
|
||||
|
||||
|
||||
def docsDir = 'src/reference/asciidoc' // Will be default with newer asciidoctor plugin
|
||||
|
||||
ext {
|
||||
@@ -141,7 +139,7 @@ subprojects { subproject ->
|
||||
springSecurityVersion = '4.1.0.RELEASE'
|
||||
springSocialTwitterVersion = '1.1.2.RELEASE'
|
||||
springRetryVersion = '1.1.2.RELEASE'
|
||||
springVersion = project.hasProperty('springVersion') ? project.springVersion : '4.3.1.BUILD-SNAPSHOT'
|
||||
springVersion = project.hasProperty('springVersion') ? project.springVersion : '4.3.1.RELEASE'
|
||||
springWsVersion = '2.3.0.RELEASE'
|
||||
xmlUnitVersion = '1.6'
|
||||
xstreamVersion = '1.4.7'
|
||||
|
||||
@@ -235,6 +235,9 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
if (!ready) {
|
||||
if (this.markers) {
|
||||
this.eof = true;
|
||||
if (this.sof) {
|
||||
this.done = true;
|
||||
}
|
||||
}
|
||||
bufferedReader.close();
|
||||
}
|
||||
|
||||
@@ -207,6 +207,34 @@ public class FileSplitterTests {
|
||||
assertEquals(2, fileMarker.getLineCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarkersEmptyFile() throws IOException {
|
||||
QueueChannel outputChannel = new QueueChannel();
|
||||
FileSplitter splitter = new FileSplitter(true, true);
|
||||
splitter.setOutputChannel(outputChannel);
|
||||
File file = File.createTempFile("empty", ".txt");
|
||||
splitter.handleMessage(new GenericMessage<File>(file));
|
||||
Message<?> received = outputChannel.receive(0);
|
||||
assertNotNull(received);
|
||||
assertNull(received.getHeaders().get(IntegrationMessageHeaderAccessor.SEQUENCE_SIZE));
|
||||
assertEquals("START", received.getHeaders().get(FileHeaders.MARKER));
|
||||
assertThat(received.getPayload(), instanceOf(FileSplitter.FileMarker.class));
|
||||
FileMarker fileMarker = (FileSplitter.FileMarker) received.getPayload();
|
||||
assertEquals(FileMarker.Mark.START, fileMarker.getMark());
|
||||
assertEquals(file.getAbsolutePath(), fileMarker.getFilePath());
|
||||
assertEquals(0, fileMarker.getLineCount());
|
||||
|
||||
received = outputChannel.receive(0);
|
||||
assertNotNull(received);
|
||||
|
||||
assertEquals("END", received.getHeaders().get(FileHeaders.MARKER));
|
||||
assertThat(received.getPayload(), instanceOf(FileSplitter.FileMarker.class));
|
||||
fileMarker = (FileSplitter.FileMarker) received.getPayload();
|
||||
assertEquals(FileMarker.Mark.END, fileMarker.getMark());
|
||||
assertEquals(file.getAbsolutePath(), fileMarker.getFilePath());
|
||||
assertEquals(0, fileMarker.getLineCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarkersJson() throws Exception {
|
||||
JsonObjectMapper<?, ?> objectMapper = JsonObjectMapperProvider.newInstance();
|
||||
|
||||
@@ -820,7 +820,8 @@ Markers are messages with `FileSplitter.FileMarker` payloads (with `START` and `
|
||||
Markers might be used when sequentially processing files in a downstream flow where some lines are filtered.
|
||||
They enable the downstream processing to know when a file has been completely processed.
|
||||
In addition, a header `file_marker` containing `START` or `END` are added to these messages.
|
||||
The 'END' marker includes a line count.
|
||||
The `END` marker includes a line count.
|
||||
If the file is empty, only `START` and `END` markers are emitted with `0` as the `lineCount`.
|
||||
Default: `false`.
|
||||
When `true`, `apply-sequence` is `false` by default.
|
||||
Also see `markers-json`.
|
||||
|
||||
Reference in New Issue
Block a user