INT-3494: Resolve dir for writing as a Resource (#3109)

* INT-3494: Resolve dir for writing as a Resource

JIRA: https://jira.spring.io/browse/INT-3494

The expression for local directory can be resolved into a `Resource`
or resource location.
* Fix `ExpressionUtils.expressionToFile()` to support `Resource` and
also use `ResourceUtils.getFile(path)` when expression result is a string
* Modify tests to ensure that resource is resolved properly
* Upgrade affected tests to JUnit 5
* Mention an new functionality in docs

* * Improve Java doc for `ExpressionUtils.expressionToFile()`
* Finish the sentence in the `file.adoc`
This commit is contained in:
Artem Bilan
2019-11-14 16:27:59 -05:00
committed by Gary Russell
parent 069d8730e0
commit 0f5bd4a40a
7 changed files with 164 additions and 211 deletions

View File

@@ -18,7 +18,7 @@
<si:header-enricher>
<si:header name="#{T(org.springframework.integration.file.FileHeaders).FILENAME}" value="${test.file}"/>
</si:header-enricher>
<file:outbound-channel-adapter id="file-outbound-channel-adapter-within-chain" directory="${work.dir}"/>
<file:outbound-channel-adapter id="file-outbound-channel-adapter-within-chain" directory-expression="${work.dir}"/>
</si:chain>
<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">

View File

@@ -22,69 +22,47 @@ import java.io.File;
import java.io.IOException;
import java.util.Properties;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.util.FileCopyUtils;
/**
* //INT-2275
*
* @author Artem Bilan
* @author Gary Russell
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringJUnitConfig
public class FileOutboundChannelAdapterInsideChainTests {
public static final String TEST_FILE_NAME = FileOutboundChannelAdapterInsideChainTests.class.getSimpleName();
static final String TEST_FILE_NAME = FileOutboundChannelAdapterInsideChainTests.class.getSimpleName();
public static final String WORK_DIR_NAME = System.getProperty("java.io.tmpdir") + "/" + FileOutboundChannelAdapterInsideChainTests.class.getSimpleName() + "Dir";
static final String SAMPLE_CONTENT = "test";
public static final String SAMPLE_CONTENT = "test";
@TempDir
static File WORK_DIR;
public static Properties placeholderProperties = new Properties();
static {
placeholderProperties.put("test.file", TEST_FILE_NAME);
placeholderProperties.put("work.dir", WORK_DIR_NAME);
}
@Autowired
private MessageChannel outboundChainChannel;
private static File workDir;
@BeforeClass
public static void setupClass() {
workDir = new File(WORK_DIR_NAME);
workDir.mkdir();
workDir.deleteOnExit();
@BeforeAll
static void setupClass() {
placeholderProperties.put("test.file", TEST_FILE_NAME);
placeholderProperties.put("work.dir", "'file://" + WORK_DIR.getAbsolutePath() + '\'');
}
@AfterClass
public static void cleanUp() {
if (workDir != null && workDir.exists()) {
for (File file : workDir.listFiles()) {
file.delete();
}
}
workDir.delete();
}
@Test //INT-2275
public void testFileOutboundChannelAdapterWithinChain() throws IOException {
@Test
void testFileOutboundChannelAdapterWithinChain() throws IOException {
Message<String> message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
outboundChainChannel.send(message);
File testFile = new File(workDir, TEST_FILE_NAME);
File testFile = new File(WORK_DIR, TEST_FILE_NAME);
assertThat(testFile.exists()).isTrue();
byte[] testFileContent = FileCopyUtils.copyToByteArray(testFile);
assertThat(SAMPLE_CONTENT).isEqualTo(new String(testFileContent));

View File

@@ -17,15 +17,14 @@
package org.springframework.integration.file;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import java.io.File;
import java.io.FileOutputStream;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.support.MessageBuilder;
@@ -33,8 +32,7 @@ import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.util.FileCopyUtils;
/**
@@ -42,9 +40,8 @@ import org.springframework.util.FileCopyUtils;
* @author Artem Bilan
* @author Gary Russell
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class FileOutboundChannelAdapterIntegrationTests {
@SpringJUnitConfig
class FileOutboundChannelAdapterIntegrationTests {
static final String DEFAULT_ENCODING = "UTF-8";
@@ -78,103 +75,71 @@ public class FileOutboundChannelAdapterIntegrationTests {
File sourceFile;
@Before
public void setUp() throws Exception {
sourceFile = File.createTempFile("anyFile", ".txt");
sourceFile.deleteOnExit();
@BeforeEach
void setUp(@TempDir File tmpDir) throws Exception {
sourceFile = new File(tmpDir, "anyFile.txt");
FileCopyUtils.copy(SAMPLE_CONTENT.getBytes(DEFAULT_ENCODING),
new FileOutputStream(sourceFile, false));
message = MessageBuilder.withPayload(sourceFile).build();
}
@After
public void tearDown() {
sourceFile.delete();
}
@Test
public void saveToBaseDir() throws Exception {
this.inputChannelSaveToBaseDir.send(message);
void saveToBaseDir() {
this.inputChannelSaveToBaseDir.send(this.message);
assertThat(new File("target/base-directory/foo.txt").exists()).isTrue();
}
@Test
public void saveToBaseDirDeleteSourceFile() throws Exception {
void saveToBaseDirDeleteSourceFile() {
assertThat(sourceFile.exists()).isTrue();
this.inputChannelSaveToBaseDirDeleteSource.send(message);
this.inputChannelSaveToBaseDirDeleteSource.send(this.message);
assertThat(new File("target/base-directory/foo.txt").exists()).isTrue();
assertThat(sourceFile.exists()).isFalse();
}
@Test
public void saveToSubDir() throws Exception {
this.inputChannelSaveToSubDir.send(message);
void saveToSubDir() {
this.inputChannelSaveToSubDir.send(this.message);
assertThat(new File("target/base-directory/sub-directory/foo.txt").exists()).isTrue();
}
@Test
public void saveToSubDirWithWrongExpression() throws Exception {
try {
this.inputChannelSaveToSubDirWrongExpression.send(message);
}
catch (MessageHandlingException e) {
assertThat(e.getCause().getMessage()).isEqualTo(TestUtils
.applySystemFileSeparator("Destination path [target/base-directory/sub-directory/foo.txt] does not" +
" point to a directory."));
return;
}
fail("Was expecting a MessageHandlingException to be thrown");
void saveToSubDirWithWrongExpression() {
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.inputChannelSaveToSubDirWrongExpression.send(this.message))
.withStackTraceContaining(TestUtils.applySystemFileSeparator(
"Destination path [target/base-directory/sub-directory/foo.txt] does " +
"not point to a directory."));
}
@Test
public void saveToSubDirWithEmptyStringExpression() throws Exception {
try {
this.inputChannelSaveToSubDirEmptyStringExpression.send(message);
}
catch (MessageHandlingException e) {
assertThat(e.getCause().getMessage())
.isEqualTo("Unable to resolve Destination Directory for the provided Expression '' ''.");
return;
}
fail("Was expecting a MessageHandlingException to be thrown");
void saveToSubDirWithEmptyStringExpression() {
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.inputChannelSaveToSubDirEmptyStringExpression.send(this.message))
.withStackTraceContaining("Unable to resolve Destination Directory for " +
"the provided Expression '' ''.");
}
@Test
public void saveToSubDir2() throws Exception {
final Message<File> message2 = MessageBuilder.fromMessage(message)
.setHeader("myFileLocation", "target/base-directory/headerdir")
.build();
void saveToSubDir2() {
Message<File> message2 = MessageBuilder.fromMessage(message)
.setHeader("myFileLocation", "target/base-directory/headerdir")
.build();
this.inputChannelSaveToSubDirWithHeader.send(message2);
assertThat(new File("target/base-directory/headerdir/foo.txt").exists()).isTrue();
}
@Test
public void saveToSubDirAutoCreateOff() throws Exception {
try {
this.inputChannelSaveToSubDirAutoCreateOff.send(message);
}
catch (MessageHandlingException e) {
assertThat(e.getCause().getMessage()).isEqualTo(TestUtils
.applySystemFileSeparator("Destination directory [target/base-directory2/sub-directory2] does not " +
"exist."));
return;
}
fail("Was expecting a MessageHandlingException to be thrown");
void saveToSubDirAutoCreateOff() {
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.inputChannelSaveToSubDirAutoCreateOff.send(this.message))
.withStackTraceContaining(TestUtils.applySystemFileSeparator("Destination directory " +
"[target/base-directory2/sub-directory2] does not exist."));
}
@Test
public void saveToSubWithFileExpression() throws Exception {
void saveToSubWithFileExpression() {
final File directory = new File("target/base-directory/sub-directory");
final Message<File> messageWithFileHeader = MessageBuilder.fromMessage(message)
.setHeader("subDirectory", directory)
@@ -184,46 +149,30 @@ public class FileOutboundChannelAdapterIntegrationTests {
}
@Test
public void saveToSubWithFileExpressionNull() throws Exception {
void saveToSubWithFileExpressionNull() {
final File directory = null;
final Message<File> messageWithFileHeader = MessageBuilder.fromMessage(message)
.setHeader("subDirectory", directory)
.build();
try {
this.inputChannelSaveToSubDirWithFile.send(messageWithFileHeader);
}
catch (MessageHandlingException e) {
assertThat(e.getCause().getMessage()).isEqualTo("The provided Destination Directory expression " +
"(headers['subDirectory']) must not evaluate to null.");
return;
}
fail("Was expecting a MessageHandlingException to be thrown");
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.inputChannelSaveToSubDirWithFile.send(messageWithFileHeader))
.withStackTraceContaining("The provided Destination Directory expression " +
"(headers['subDirectory']) must not evaluate to null.");
}
@Test
public void saveToSubWithFileExpressionUnsupportedObjectType() throws Exception {
final Integer unsupportedObject = Integer.valueOf(1234);
void saveToSubWithFileExpressionUnsupportedObjectType() {
final Integer unsupportedObject = 1234;
final Message<File> messageWithFileHeader = MessageBuilder.fromMessage(message)
.setHeader("subDirectory", unsupportedObject)
.build();
try {
this.inputChannelSaveToSubDirWithFile.send(messageWithFileHeader);
}
catch (MessageHandlingException e) {
assertThat(e.getCause().getMessage()).isEqualTo("The provided Destination Directory expression" +
" (headers['subDirectory']) must evaluate to type " +
"java.io.File or String, not java.lang.Integer.");
return;
}
fail("Was expecting a MessageHandlingException to be thrown");
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.inputChannelSaveToSubDirWithFile.send(messageWithFileHeader))
.withStackTraceContaining("The provided Destination Directory expression" +
" (headers['subDirectory']) must evaluate to type " +
"java.io.File, String or org.springframework.core.io.Resource, not java.lang.Integer.");
}
}

View File

@@ -17,6 +17,8 @@
package org.springframework.integration.file;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -39,19 +41,21 @@ import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.expression.Expression;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.QueueChannel;
@@ -79,36 +83,36 @@ public class FileWritingMessageHandlerTests {
static final String DEFAULT_ENCODING = "UTF-8";
static final String SAMPLE_CONTENT = "HelloWorld\n????";
static final String SAMPLE_CONTENT = "HelloWorld\näöüß";
private File sourceFile;
@Rule
public TemporaryFolder temp = new TemporaryFolder() {
@Override
public void create() throws IOException {
super.create();
outputDirectory = temp.newFolder("outputDirectory");
handler = new FileWritingMessageHandler(outputDirectory);
handler.setBeanFactory(mock(BeanFactory.class));
handler.afterPropertiesSet();
sourceFile = temp.newFile("sourceFile");
FileCopyUtils.copy(SAMPLE_CONTENT.getBytes(DEFAULT_ENCODING),
new FileOutputStream(sourceFile, false));
}
};
@TempDir
File tempDir;
private File outputDirectory;
private FileWritingMessageHandler handler;
@Test(expected = MessageHandlingException.class)
@BeforeEach
void setup() throws IOException {
outputDirectory = new File(tempDir, "outputDirectory");
sourceFile = new File(tempDir, "sourceFile");
FileCopyUtils.copy(SAMPLE_CONTENT.getBytes(DEFAULT_ENCODING),
new FileOutputStream(sourceFile, false));
this.handler = new FileWritingMessageHandler(this.outputDirectory);
this.handler.setBeanFactory(mock(BeanFactory.class));
this.handler.setApplicationContext(new GenericApplicationContext());
this.handler.afterPropertiesSet();
}
@Test
public void unsupportedType() {
this.handler.handleMessage(new GenericMessage<>(99));
assertThat(this.outputDirectory.listFiles()[0]).isNull();
assertThatExceptionOfType(MessageHandlingException.class)
.isThrownBy(() -> this.handler.handleMessage(new GenericMessage<>(99)));
}
@Test
@@ -138,7 +142,7 @@ public class FileWritingMessageHandlerTests {
handler.setChmod(0777);
}
handler.setOutputChannel(new NullChannel());
handler.handleMessage(new GenericMessage<String>("test"));
handler.handleMessage(new GenericMessage<>("test"));
File[] output = outputDirectory.listFiles();
assertThat(output.length).isEqualTo(1);
assertThat(output[0]).isNotNull();
@@ -265,18 +269,14 @@ public class FileWritingMessageHandlerTests {
}
@Test
@Ignore("INT-3289: doesn't fail on all OS")
@Disabled("INT-3289: doesn't fail on all OS")
public void testCreateDirFail() {
File dir = new File("/foo");
FileWritingMessageHandler handler = new FileWritingMessageHandler(dir);
handler.setBeanFactory(mock(BeanFactory.class));
try {
handler.afterPropertiesSet();
fail("Expected exception");
}
catch (IllegalArgumentException e) {
assertThat(e.getMessage()).contains("[/foo] could not be created");
}
assertThatIllegalArgumentException()
.isThrownBy(handler::afterPropertiesSet)
.withMessageContaining("[/foo] could not be created");
}
@Test
@@ -369,7 +369,7 @@ public class FileWritingMessageHandlerTests {
}
@Test
public void deleteSourceFileWithInputstreamPayloadAndFileInstanceHeader() throws Exception {
public void deleteSourceFileWithInputStreamPayloadAndFileInstanceHeader() throws Exception {
QueueChannel output = new QueueChannel();
handler.setCharset(DEFAULT_ENCODING);
handler.setDeleteSourceFiles(true);
@@ -388,7 +388,7 @@ public class FileWritingMessageHandlerTests {
}
@Test
public void deleteSourceFileWithInputstreamPayloadAndFilePathHeader() throws Exception {
public void deleteSourceFileWithInputStreamPayloadAndFilePathHeader() throws Exception {
QueueChannel output = new QueueChannel();
handler.setCharset(DEFAULT_ENCODING);
handler.setDeleteSourceFiles(true);
@@ -407,7 +407,7 @@ public class FileWritingMessageHandlerTests {
}
@Test
public void customFileNameGenerator() throws Exception {
public void customFileNameGenerator() {
final String anyFilename = "fooBar.test";
QueueChannel output = new QueueChannel();
handler.setOutputChannel(output);
@@ -422,7 +422,7 @@ public class FileWritingMessageHandlerTests {
public void existingFileIgnored() throws Exception {
Message<?> message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
QueueChannel output = new QueueChannel();
File outFile = temp.newFile("/outputDirectory/" + message.getHeaders().getId().toString() + ".msg");
File outFile = new File(tempDir, "/outputDirectory/" + message.getHeaders().getId().toString() + ".msg");
FileCopyUtils.copy("foo".getBytes(), new FileOutputStream(outFile));
handler.setCharset(DEFAULT_ENCODING);
handler.setOutputChannel(output);
@@ -436,7 +436,8 @@ public class FileWritingMessageHandlerTests {
public void existingWritingFileIgnored() throws Exception {
Message<?> message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
QueueChannel output = new QueueChannel();
File outFile = temp.newFile("/outputDirectory/" + message.getHeaders().getId().toString() + ".msg.writing");
File outFile =
new File(tempDir, "/outputDirectory/" + message.getHeaders().getId().toString() + ".msg.writing");
FileCopyUtils.copy("foo".getBytes(), new FileOutputStream(outFile));
handler.setCharset(DEFAULT_ENCODING);
handler.setOutputChannel(output);
@@ -453,7 +454,8 @@ public class FileWritingMessageHandlerTests {
public void existingWritingFileNotIgnoredIfEmptySuffix() throws Exception {
Message<?> message = MessageBuilder.withPayload(SAMPLE_CONTENT).build();
QueueChannel output = new QueueChannel();
File outFile = temp.newFile("/outputDirectory/" + message.getHeaders().getId().toString() + ".msg.writing");
File outFile =
new File(tempDir, "/outputDirectory/" + message.getHeaders().getId().toString() + ".msg.writing");
FileCopyUtils.copy("foo".getBytes(), new FileOutputStream(outFile));
handler.setCharset(DEFAULT_ENCODING);
handler.setOutputChannel(output);
@@ -470,7 +472,7 @@ public class FileWritingMessageHandlerTests {
@Test
public void noFlushAppend() throws Exception {
File tempFolder = this.temp.newFolder();
File tempFolder = new File(tempDir, UUID.randomUUID().toString());
FileWritingMessageHandler handler = new FileWritingMessageHandler(tempFolder);
handler.setFileExistsMode(FileExistsMode.APPEND_NO_FLUSH);
handler.setFileNameGenerator(message -> "foo.txt");
@@ -483,10 +485,10 @@ public class FileWritingMessageHandlerTests {
handler.afterPropertiesSet();
handler.start();
File file = new File(tempFolder, "foo.txt");
handler.handleMessage(new GenericMessage<String>("foo"));
handler.handleMessage(new GenericMessage<String>("bar"));
handler.handleMessage(new GenericMessage<String>("baz"));
handler.handleMessage(new GenericMessage<byte[]>("qux".getBytes())); // change of payload type forces flush
handler.handleMessage(new GenericMessage<>("foo"));
handler.handleMessage(new GenericMessage<>("bar"));
handler.handleMessage(new GenericMessage<>("baz"));
handler.handleMessage(new GenericMessage<>("qux".getBytes())); // change of payload type forces flush
assertThat(file.length()).isGreaterThanOrEqualTo(9L);
handler.stop(); // forces flush
assertThat(file.length()).isEqualTo(12L);
@@ -499,7 +501,7 @@ public class FileWritingMessageHandlerTests {
}
assertThat(file.length()).isEqualTo(15L);
handler.handleMessage(new GenericMessage<InputStream>(new ByteArrayInputStream("buz".getBytes())));
handler.trigger(new GenericMessage<String>(Matcher.quoteReplacement(file.getAbsolutePath())));
handler.trigger(new GenericMessage<>(Matcher.quoteReplacement(file.getAbsolutePath())));
assertThat(file.length()).isEqualTo(18L);
assertThat(TestUtils.getPropertyValue(handler, "fileStates", Map.class).size()).isEqualTo(0);
@@ -510,7 +512,7 @@ public class FileWritingMessageHandlerTests {
return true;
});
handler.handleMessage(new GenericMessage<InputStream>(new ByteArrayInputStream("box".getBytes())));
handler.trigger(new GenericMessage<String>("foo"));
handler.trigger(new GenericMessage<>("foo"));
assertThat(file.length()).isEqualTo(21L);
assertThat(called.get()).isTrue();
@@ -536,7 +538,7 @@ public class FileWritingMessageHandlerTests {
handler.setFlushWhenIdle(false);
handler.start();
for (int i = 0; i < 40; i++) {
handler.handleMessage(new GenericMessage<String>("foo"));
handler.handleMessage(new GenericMessage<>("foo"));
Thread.sleep(5);
}
assertThat(flushes.get()).isGreaterThanOrEqualTo(2);
@@ -545,7 +547,7 @@ public class FileWritingMessageHandlerTests {
@Test
public void lockForFlush() throws Exception {
File tempFolder = this.temp.newFolder();
File tempFolder = new File(tempDir, UUID.randomUUID().toString());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final BufferedOutputStream out = spy(new BufferedOutputStream(baos));
FileWritingMessageHandler handler = new FileWritingMessageHandler(tempFolder) {
@@ -617,7 +619,7 @@ public class FileWritingMessageHandlerTests {
@Test
public void replaceIfDifferentFile() throws IOException {
File file = new File(this.temp.newFolder(), "foo.txt");
File file = new File(this.tempDir, "foo.txt");
FileCopyUtils.copy("foo".getBytes(), new FileOutputStream(file));
file.setLastModified(42_000_000);
QueueChannel output = new QueueChannel();
@@ -691,8 +693,7 @@ public class FileWritingMessageHandlerTests {
protected File messageToFile(Message<?> result) {
assertThat(result).isNotNull();
assertThat(result.getPayload()).isInstanceOf(File.class);
File destFile = (File) result.getPayload();
return destFile;
return (File) result.getPayload();
}
}

View File

@@ -333,7 +333,7 @@ public class FileTests {
@Bean
public IntegrationFlow fileFlow1() {
return IntegrationFlows.from("fileFlow1Input")
.handle(Files.outboundAdapter(tmpDir.getRoot())
.handle(Files.outboundAdapter("'file://" + tmpDir.getRoot().getAbsolutePath() + '\'')
.fileNameGenerator(message -> null)
.fileExistsMode(FileExistsMode.APPEND_NO_FLUSH)
.flushInterval(60000)