INT-4297: Add FileSplitter.setFirstLineAsHeader()
JIRA: https://jira.spring.io/browse/INT-4297 * Add `FileSplitter.setFirstLineAsHeader()` and extract the first line from the context before `iterator`. * Populate the extracted header to each subsequent line * Don't use `Streams` to read first line * Add XSD and Java DSL option for the `firstLineAsHeader` * Document the feature * Add Java DSL sample for the `Files.slitter()` Add a note about more complex header enrichment Doc Polishing and fix field name.
This commit is contained in:
committed by
Gary Russell
parent
5216dc2b02
commit
d8382e0bd0
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -27,6 +27,8 @@ import org.springframework.integration.file.splitter.FileSplitter;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 4.2
|
||||
*
|
||||
*/
|
||||
@@ -42,8 +44,8 @@ public class FileSplitterParser extends AbstractConsumerEndpointParser {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "apply-sequence");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-timeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "first-line-as-header");
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 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.
|
||||
@@ -20,6 +20,7 @@ import java.nio.charset.Charset;
|
||||
|
||||
import org.springframework.integration.dsl.MessageHandlerSpec;
|
||||
import org.springframework.integration.file.splitter.FileSplitter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link MessageHandlerSpec} for the {@link FileSplitter}.
|
||||
@@ -27,6 +28,8 @@ import org.springframework.integration.file.splitter.FileSplitter;
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.0
|
||||
*
|
||||
* @see FileSplitter
|
||||
*/
|
||||
public class FileSplitterSpec extends MessageHandlerSpec<FileSplitterSpec, FileSplitter> {
|
||||
|
||||
@@ -40,6 +43,8 @@ public class FileSplitterSpec extends MessageHandlerSpec<FileSplitterSpec, FileS
|
||||
|
||||
private boolean applySequence;
|
||||
|
||||
private String firstLineHeaderName;
|
||||
|
||||
FileSplitterSpec() {
|
||||
this(true);
|
||||
}
|
||||
@@ -79,7 +84,6 @@ public class FileSplitterSpec extends MessageHandlerSpec<FileSplitterSpec, FileS
|
||||
* {@link org.springframework.integration.file.splitter.FileSplitter.FileMarker}s
|
||||
* Defaults to {@code false}.
|
||||
* @return the FileSplitterSpec
|
||||
* @see FileSplitter
|
||||
*/
|
||||
public FileSplitterSpec markers() {
|
||||
return markers(false);
|
||||
@@ -92,7 +96,6 @@ public class FileSplitterSpec extends MessageHandlerSpec<FileSplitterSpec, FileS
|
||||
* Defaults to {@code false} for markers and {@code false} for markersJson.
|
||||
* @param asJson the asJson flag to use.
|
||||
* @return the FileSplitterSpec
|
||||
* @see FileSplitter
|
||||
*/
|
||||
public FileSplitterSpec markers(boolean asJson) {
|
||||
this.markers = true;
|
||||
@@ -113,12 +116,25 @@ public class FileSplitterSpec extends MessageHandlerSpec<FileSplitterSpec, FileS
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the header name for the first line to be carried as a header in the
|
||||
* messages emitted for the remaining lines.
|
||||
* @param firstLineHeaderName the header name to carry first line.
|
||||
* @return the FileSplitterSpec
|
||||
*/
|
||||
public FileSplitterSpec firstLineAsHeader(String firstLineHeaderName) {
|
||||
this.firstLineHeaderName = firstLineHeaderName;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FileSplitter doGet() {
|
||||
FileSplitter fileSplitter = new FileSplitter(this.iterator, this.markers, this.markersJson);
|
||||
fileSplitter.setApplySequence(this.applySequence);
|
||||
fileSplitter.setCharset(this.charset);
|
||||
if (StringUtils.hasText(this.firstLineHeaderName)) {
|
||||
fileSplitter.setFirstLineAsHeader(this.firstLineHeaderName);
|
||||
}
|
||||
return fileSplitter;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 2015-2017 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.
|
||||
@@ -47,20 +47,28 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link AbstractMessageSplitter} implementation to split the {@link File}
|
||||
* Message payload to lines.
|
||||
* The {@link AbstractMessageSplitter} implementation to split the {@link File} Message
|
||||
* payload to lines.
|
||||
* <p>
|
||||
* With {@code iterator = true} (defaults to {@code true}) this class produces an {@link Iterator}
|
||||
* to process file lines on demand from {@link Iterator#next}.
|
||||
* Otherwise a {@link List} of all lines is returned to the to further
|
||||
* With {@code iterator = true} (defaults to {@code true}) this class produces an
|
||||
* {@link Iterator} to process file lines on demand from {@link Iterator#next}. Otherwise
|
||||
* a {@link List} of all lines is returned to the to further
|
||||
* {@link AbstractMessageSplitter#handleRequestMessage} process.
|
||||
* <p>
|
||||
* Can accept {@link String} as file path, {@link File}, {@link Reader} or {@link InputStream}
|
||||
* as payload type.
|
||||
* All other types are ignored and returned to the {@link AbstractMessageSplitter} as is.
|
||||
* Can accept {@link String} as file path, {@link File}, {@link Reader} or
|
||||
* {@link InputStream} as payload type. All other types are ignored and returned to the
|
||||
* {@link AbstractMessageSplitter} as is.
|
||||
* <p>
|
||||
* If {@link #setFirstLineAsHeader(String)} is specified, the first line of the content is
|
||||
* treated as a header and carried as a header with the provided name in the messages
|
||||
* emitted for the remaining lines. In this case, if markers are enabled, the line count
|
||||
* in the END marker does not include the header line and, if
|
||||
* {@link #setApplySequence(boolean) applySequence} is true, the header is not included in
|
||||
* the sequence.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 4.1.2
|
||||
*/
|
||||
public class FileSplitter extends AbstractMessageSplitter {
|
||||
@@ -76,6 +84,8 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
|
||||
private Charset charset;
|
||||
|
||||
private String firstLineHeaderName;
|
||||
|
||||
/**
|
||||
* Construct a splitter where the {@link #splitMessage(Message)} method returns
|
||||
* an iterator and the file is read line-by-line during iteration.
|
||||
@@ -143,6 +153,17 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the header name for the first line to be carried as a header in the
|
||||
* messages emitted for the remaining lines.
|
||||
* @param firstLineHeaderName the header name to carry first line.
|
||||
* @since 5.0
|
||||
*/
|
||||
public void setFirstLineAsHeader(String firstLineHeaderName) {
|
||||
Assert.hasText(firstLineHeaderName, "'firstLineHeaderName' must not be empty");
|
||||
this.firstLineHeaderName = firstLineHeaderName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object splitMessage(final Message<?> message) {
|
||||
Object payload = message.getPayload();
|
||||
@@ -199,7 +220,8 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
super.close();
|
||||
}
|
||||
finally {
|
||||
Closeable closeableResource = new IntegrationMessageHeaderAccessor(message).getCloseableResource();
|
||||
Closeable closeableResource = new IntegrationMessageHeaderAccessor(message)
|
||||
.getCloseableResource();
|
||||
if (closeableResource != null) {
|
||||
closeableResource.close();
|
||||
}
|
||||
@@ -208,6 +230,20 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
|
||||
};
|
||||
|
||||
String firstLineAsHeader;
|
||||
|
||||
if (this.firstLineHeaderName != null) {
|
||||
try {
|
||||
firstLineAsHeader = bufferedReader.readLine();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new MessageHandlingException(message, "IOException while reading first line", e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
firstLineAsHeader = null;
|
||||
}
|
||||
|
||||
Iterator<Object> iterator = new Iterator<Object>() {
|
||||
|
||||
boolean markers = FileSplitter.this.markers;
|
||||
@@ -275,7 +311,16 @@ public class FileSplitter extends AbstractMessageSplitter {
|
||||
String line = this.line;
|
||||
this.line = null;
|
||||
this.lineCount++;
|
||||
return line;
|
||||
|
||||
AbstractIntegrationMessageBuilder<String> messageBuilder =
|
||||
getMessageBuilderFactory()
|
||||
.withPayload(line);
|
||||
|
||||
if (firstLineAsHeader != null) {
|
||||
messageBuilder.setHeader(FileSplitter.this.firstLineHeaderName, firstLineAsHeader);
|
||||
}
|
||||
|
||||
return messageBuilder;
|
||||
}
|
||||
else {
|
||||
this.done = true;
|
||||
|
||||
@@ -712,6 +712,14 @@ Only files matching this regular expression will be picked up by this adapter.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="first-line-as-header" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
The header name for the first line to be carried as a header in the messages emitted for the
|
||||
remaining lines.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" use="optional" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
Reference in New Issue
Block a user