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:
committed by
Gary Russell
parent
069d8730e0
commit
0f5bd4a40a
@@ -17,6 +17,8 @@
|
||||
package org.springframework.integration.expression;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -25,6 +27,7 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
@@ -39,6 +42,7 @@ import org.springframework.integration.support.utils.IntegrationUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
/**
|
||||
* Utility class with static methods for helping with evaluation of SpEL expressions.
|
||||
@@ -53,7 +57,7 @@ public final class ExpressionUtils {
|
||||
|
||||
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ExpressionUtils.class);
|
||||
private static final Log LOGGER = LogFactory.getLog(ExpressionUtils.class);
|
||||
|
||||
private ExpressionUtils() {
|
||||
super();
|
||||
@@ -84,7 +88,7 @@ public final class ExpressionUtils {
|
||||
*/
|
||||
public static StandardEvaluationContext createStandardEvaluationContext(@Nullable BeanFactory beanFactory) {
|
||||
if (beanFactory == null) {
|
||||
logger.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
|
||||
LOGGER.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
|
||||
}
|
||||
return (StandardEvaluationContext) doCreateContext(beanFactory, false);
|
||||
}
|
||||
@@ -98,7 +102,7 @@ public final class ExpressionUtils {
|
||||
*/
|
||||
public static SimpleEvaluationContext createSimpleEvaluationContext(@Nullable BeanFactory beanFactory) {
|
||||
if (beanFactory == null) {
|
||||
logger.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
|
||||
LOGGER.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanFactory"));
|
||||
}
|
||||
return (SimpleEvaluationContext) doCreateContext(beanFactory, true);
|
||||
}
|
||||
@@ -161,36 +165,56 @@ public final class ExpressionUtils {
|
||||
* @param expression the expression.
|
||||
* @param evaluationContext the evaluation context.
|
||||
* @param message the message (if available).
|
||||
* @param name the name of the result of the evaluation.
|
||||
* @param propertyName the property name the expression is evaluated for.
|
||||
* @return the File.
|
||||
* @since 5.0
|
||||
*/
|
||||
public static File expressionToFile(Expression expression, EvaluationContext evaluationContext,
|
||||
@Nullable Message<?> message, String name) {
|
||||
@Nullable Message<?> message, String propertyName) {
|
||||
|
||||
File file;
|
||||
Object value = message == null
|
||||
? expression.getValue(evaluationContext)
|
||||
: expression.getValue(evaluationContext, message);
|
||||
if (value == null) {
|
||||
throw new IllegalStateException(String.format("The provided %s expression (%s) must not evaluate to null.",
|
||||
name, expression.getExpressionString()));
|
||||
}
|
||||
else if (value instanceof File) {
|
||||
file = (File) value;
|
||||
Object value =
|
||||
message == null
|
||||
? expression.getValue(evaluationContext)
|
||||
: expression.getValue(evaluationContext, message);
|
||||
|
||||
Assert.state(value != null, () ->
|
||||
String.format("The provided %s expression (%s) must not evaluate to null.",
|
||||
propertyName, expression.getExpressionString()));
|
||||
|
||||
if (value instanceof File) {
|
||||
return (File) value;
|
||||
}
|
||||
else if (value instanceof String) {
|
||||
String path = (String) value;
|
||||
Assert.hasText(path, String.format("Unable to resolve %s for the provided Expression '%s'.", name,
|
||||
Assert.hasText(path, String.format("Unable to resolve %s for the provided Expression '%s'.", propertyName,
|
||||
expression.getExpressionString()));
|
||||
file = new File(path);
|
||||
try {
|
||||
return ResourceUtils.getFile(path);
|
||||
}
|
||||
catch (FileNotFoundException ex) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Unable to resolve %s for the provided Expression '%s'.",
|
||||
propertyName, expression.getExpressionString()),
|
||||
ex);
|
||||
}
|
||||
}
|
||||
else if (value instanceof Resource) {
|
||||
try {
|
||||
return ((Resource) value).getFile();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Unable to resolve %s for the provided Expression '%s'.",
|
||||
propertyName, expression.getExpressionString()),
|
||||
ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(String.format(
|
||||
"The provided %s expression (%s) must evaluate to type java.io.File or String, not %s.", name,
|
||||
"The provided %s expression (%s) must evaluate to type java.io.File, String " +
|
||||
"or org.springframework.core.io.Resource, not %s.", propertyName,
|
||||
expression.getExpressionString(), value.getClass().getName()));
|
||||
}
|
||||
return 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">
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -688,7 +688,8 @@ If you want to have full SpEL support, you can use the `directory-expression` at
|
||||
This attribute accepts a SpEL expression that is evaluated for each message being processed.
|
||||
Thus, you have full access to a message's payload and its headers when you dynamically specify the output file directory.
|
||||
|
||||
The SpEL expression must resolve to either a `String` or to `java.io.File`.
|
||||
The SpEL expression must resolve to either a `String`, `java.io.File` or `org.springframework.core.io.Resource`.
|
||||
(The later is evaluated into a `File` anyway.)
|
||||
Furthermore, the resulting `String` or `File` must point to a directory.
|
||||
If you do not specify the `directory-expression` attribute, then you must set the `directory` attribute.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user