diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileReadingMessageSource.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileReadingMessageSource.java index 238aeaaf92..55c961457e 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileReadingMessageSource.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileReadingMessageSource.java @@ -28,6 +28,7 @@ import java.util.concurrent.PriorityBlockingQueue; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import org.springframework.integration.aggregator.Resequencer; import org.springframework.integration.core.Message; @@ -61,7 +62,7 @@ import org.springframework.util.Assert; * @author Iwein Fuld * @author Mark Fisher */ -public class FileReadingMessageSource implements MessageSource { +public class FileReadingMessageSource implements MessageSource, InitializingBean { private static final int INTERNAL_QUEUE_CAPACITY = 5; @@ -69,6 +70,8 @@ public class FileReadingMessageSource implements MessageSource { private volatile File inputDirectory; + private volatile boolean autoCreateDirectory = true; + /** * {@link PriorityBlockingQueue#iterator()} throws * {@link java.util.ConcurrentModificationException} in Java 5. @@ -99,16 +102,29 @@ public class FileReadingMessageSource implements MessageSource { toBeReceived = new PriorityBlockingQueue(INTERNAL_QUEUE_CAPACITY, receptionOrderComparator); } + /** + * Specify the input directory. + */ public void setInputDirectory(Resource inputDirectory) { Assert.notNull(inputDirectory, "inputDirectory cannot be null"); - Assert.isTrue(inputDirectory.exists(), inputDirectory + " doesn't exist."); try { this.inputDirectory = inputDirectory.getFile(); } catch (IOException e) { - throw new IllegalArgumentException("Unexpected IOException when looking for " + inputDirectory, e); + throw new IllegalArgumentException( + "Unexpected IOException when looking for source directory: " + inputDirectory, e); } - Assert.isTrue(this.inputDirectory.canRead(), "No read permissions on " + this.inputDirectory); + } + + /** + * Specify whether to create the source directory automatically if it does + * not yet exist upon initialization. By default, this value is + * true. If set to false and the + * source directory does not exist, an Exception will be thrown upon + * initialization. + */ + public void setAutoCreateDirectory(boolean autoCreateDirectory) { + this.autoCreateDirectory = autoCreateDirectory; } /** @@ -136,6 +152,18 @@ public class FileReadingMessageSource implements MessageSource { this.scanEachPoll = scanEachPoll; } + public final void afterPropertiesSet() { + if (!this.inputDirectory.exists() && this.autoCreateDirectory) { + this.inputDirectory.mkdirs(); + } + Assert.isTrue(this.inputDirectory.exists(), + "Source directory [" + inputDirectory + "] does not exist."); + Assert.isTrue(this.inputDirectory.isDirectory(), + "Source path [" + this.inputDirectory + "] does not point to a directory."); + Assert.isTrue(this.inputDirectory.canRead(), + "Source directory [" + this.inputDirectory + "] is not readable."); + } + public Message receive() throws MessagingException { Message message = null; // rescan only if needed or explicitly configured diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileWritingMessageHandler.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileWritingMessageHandler.java index 4012067d5b..e26c8e9c5f 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileWritingMessageHandler.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/FileWritingMessageHandler.java @@ -25,6 +25,7 @@ import java.nio.charset.Charset; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import org.springframework.integration.core.Message; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; @@ -57,7 +58,7 @@ import org.springframework.util.FileCopyUtils; * @author Iwein Fuld * @author Alex Peters */ -public class FileWritingMessageHandler extends AbstractReplyProducingMessageHandler { +public class FileWritingMessageHandler extends AbstractReplyProducingMessageHandler implements InitializingBean { private static final String TEMPORARY_FILE_SUFFIX =".writing"; @@ -68,6 +69,8 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand private final File destinationDirectory; + private volatile boolean autoCreateDirectory = true; + private volatile boolean deleteSourceFiles; private volatile Charset charset = Charset.defaultCharset(); @@ -75,20 +78,26 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand public FileWritingMessageHandler(Resource destinationDirectory) { try { - Assert.isTrue(destinationDirectory.exists(), - "Output directory [" + destinationDirectory + "] does not exist"); this.destinationDirectory = destinationDirectory.getFile(); - Assert.isTrue(this.destinationDirectory.isDirectory(), - "[" + this.destinationDirectory + "] is not a directory"); - Assert.isTrue(this.destinationDirectory.canWrite(), - "[" + this.destinationDirectory + "] is not writable"); } catch (IOException e) { - throw new IllegalArgumentException("Inaccessible output directory", e); + throw new IllegalArgumentException( + "Unexpected IOException when looking for destination directory: " + destinationDirectory, e); } } + /** + * Specify whether to create the destination directory automatically if it + * does not yet exist upon initialization. By default, this value is + * true. If set to false and the + * destination directory does not exist, an Exception will be thrown upon + * initialization. + */ + public void setAutoCreateDirectory(boolean autoCreateDirectory) { + this.autoCreateDirectory = autoCreateDirectory; + } + /** * Provide the {@link FileNameGenerator} strategy to use when generating * the destination file's name. @@ -119,6 +128,18 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand this.charset = Charset.forName(charset); } + public void afterPropertiesSet() { + if (!this.destinationDirectory.exists() && this.autoCreateDirectory) { + this.destinationDirectory.mkdirs(); + } + Assert.isTrue(destinationDirectory.exists(), + "Destination directory [" + destinationDirectory + "] does not exist."); + Assert.isTrue(this.destinationDirectory.isDirectory(), + "Destination path [" + this.destinationDirectory + "] does not point to a directory."); + Assert.isTrue(this.destinationDirectory.canWrite(), + "Destination directory [" + this.destinationDirectory + "] is not writable."); + } + @Override protected void handleRequestMessage(Message requestMessage, ReplyMessageHolder replyMessageHolder) { Assert.notNull(requestMessage, "message must not be null"); diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java index dbf63f4b62..eb8ec95484 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileInboundChannelAdapterParser.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser; +import org.springframework.integration.config.xml.IntegrationNamespaceUtils; import org.springframework.util.StringUtils; /** @@ -51,6 +52,7 @@ public class FileInboundChannelAdapterParser extends AbstractPollingInboundChann } builder.addPropertyValue("inputDirectory", directory); } + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-create-directory"); String filterBeanName = this.registerFileListFilter(element, parserContext); builder.addPropertyReference("filter", filterBeanName); return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry()); diff --git a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerBeanDefinitionBuilder.java b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerBeanDefinitionBuilder.java index 8c3c9d0683..117c03668e 100644 --- a/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerBeanDefinitionBuilder.java +++ b/org.springframework.integration.file/src/main/java/org/springframework/integration/file/config/FileWritingMessageHandlerBeanDefinitionBuilder.java @@ -51,6 +51,7 @@ abstract class FileWritingMessageHandlerBeanDefinitionBuilder { if (StringUtils.hasText(outputChannelBeanName)) { builder.addPropertyReference("outputChannel", outputChannelBeanName); } + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-create-directory"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "delete-source-files"); String fileNameGenerator = element.getAttribute("filename-generator"); if (StringUtils.hasText(fileNameGenerator)) { diff --git a/org.springframework.integration.file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-1.0.xsd b/org.springframework.integration.file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-1.0.xsd index 7a8baa5e5b..fef8f4a275 100644 --- a/org.springframework.integration.file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-1.0.xsd +++ b/org.springframework.integration.file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-1.0.xsd @@ -72,6 +72,15 @@ + + + + Specify whether to automatically create the source directory if it does not yet exist when this + adapter is being initialized. The default value is 'true'. If set to 'false' and the directory + does not exist upon initialization, an Exception will be thrown. + + + @@ -164,6 +173,15 @@ ]]> + + + + Specify whether to automatically create the destination directory if it does not yet exist + when this adapter is being initialized. The default value is 'true'. If set to 'false' and + the directory does not exist upon initialization, an Exception will be thrown. + + + diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/AutoCreateDirectoryTests.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/AutoCreateDirectoryTests.java new file mode 100644 index 0000000000..b8a46af571 --- /dev/null +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/AutoCreateDirectoryTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2002-2009 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 + * + * http://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; + +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.core.io.FileSystemResource; + +/** + * @author Mark Fisher + * @since 1.0.3 + */ +public class AutoCreateDirectoryTests { + + private static final String BASE_PATH = + System.getProperty("java.io.tmpdir") + File.separator + "AutoCreateDirectoryTests"; + + private static final String INBOUND_PATH = BASE_PATH + File.separator + "inbound"; + + private static final String OUTBOUND_PATH = BASE_PATH + File.separator + "outbound"; + + + @Before + @After + public void clearDirectories() { + File baseDir = new File(BASE_PATH); + File inboundDir = new File(INBOUND_PATH); + File outboundDir = new File(OUTBOUND_PATH); + if (inboundDir.exists()) { + inboundDir.delete(); + } + if (outboundDir.exists()) { + outboundDir.delete(); + } + if (baseDir.exists()) { + baseDir.delete(); + } + } + + @Test + public void autoCreateForInboundEnabledByDefault() { + FileReadingMessageSource source = new FileReadingMessageSource(); + source.setInputDirectory(new FileSystemResource(INBOUND_PATH)); + source.afterPropertiesSet(); + assertTrue(new File(INBOUND_PATH).exists()); + } + + @Test(expected = IllegalArgumentException.class) + public void autoCreateForInboundDisabled() { + FileReadingMessageSource source = new FileReadingMessageSource(); + source.setInputDirectory(new FileSystemResource(INBOUND_PATH)); + source.setAutoCreateDirectory(false); + source.afterPropertiesSet(); + } + + @Test + public void autoCreateForOutboundEnabledByDefault() { + FileWritingMessageHandler handler = new FileWritingMessageHandler( + new FileSystemResource(OUTBOUND_PATH)); + handler.afterPropertiesSet(); + assertTrue(new File(OUTBOUND_PATH).exists()); + } + + @Test(expected = IllegalArgumentException.class) + public void autoCreateForOutboundDisabled() { + FileWritingMessageHandler handler = new FileWritingMessageHandler( + new FileSystemResource(OUTBOUND_PATH)); + handler.setAutoCreateDirectory(false); + handler.afterPropertiesSet(); + } + +} diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/AutoCreateDirectoryIntegrationTests-context.xml b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/AutoCreateDirectoryIntegrationTests-context.xml new file mode 100644 index 0000000000..d14ff092bd --- /dev/null +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/AutoCreateDirectoryIntegrationTests-context.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/AutoCreateDirectoryIntegrationTests.java b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/AutoCreateDirectoryIntegrationTests.java new file mode 100644 index 0000000000..a7d9ac64d2 --- /dev/null +++ b/org.springframework.integration.file/src/test/java/org/springframework/integration/file/config/AutoCreateDirectoryIntegrationTests.java @@ -0,0 +1,132 @@ +/* + * Copyright 2002-2009 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 + * + * http://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.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.integration.file.FileReadingMessageSource; +import org.springframework.integration.file.FileWritingMessageHandler; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Mark Fisher + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class AutoCreateDirectoryIntegrationTests { + + private static final String BASE_PATH = + System.getProperty("java.io.tmpdir") + File.separator + AutoCreateDirectoryIntegrationTests.class.getSimpleName(); + + + @Autowired + private ApplicationContext context; + + + @BeforeClass + public static void setupNonAutoCreatedDirectories() { + new File(BASE_PATH).delete(); + new File(BASE_PATH + File.separator + "customInbound").mkdirs(); + new File(BASE_PATH + File.separator + "customOutbound").mkdirs(); + new File(BASE_PATH + File.separator + "customOutboundGateway").mkdirs(); + } + + @AfterClass + public static void deleteBaseDirectory() { + new File(BASE_PATH).delete(); + } + + + @Test + public void defaultInbound() throws Exception { + Object adapter = context.getBean("defaultInbound"); + DirectFieldAccessor adapterAccessor = new DirectFieldAccessor(adapter); + FileReadingMessageSource source = (FileReadingMessageSource) + adapterAccessor.getPropertyValue("source"); + assertEquals(Boolean.TRUE, + new DirectFieldAccessor(source).getPropertyValue("autoCreateDirectory")); + assertTrue(new File(BASE_PATH + File.separator + "defaultInbound").exists()); + } + + @Test + public void customInbound() throws Exception { + Object adapter = context.getBean("customInbound"); + DirectFieldAccessor adapterAccessor = new DirectFieldAccessor(adapter); + FileReadingMessageSource source = (FileReadingMessageSource) + adapterAccessor.getPropertyValue("source"); + assertTrue(new File(BASE_PATH + File.separator + "customInbound").exists()); + assertEquals(Boolean.FALSE, + new DirectFieldAccessor(source).getPropertyValue("autoCreateDirectory")); + } + + @Test + public void defaultOutbound() throws Exception { + Object adapter = context.getBean("defaultOutbound"); + DirectFieldAccessor adapterAccessor = new DirectFieldAccessor(adapter); + FileWritingMessageHandler handler = (FileWritingMessageHandler) + adapterAccessor.getPropertyValue("handler"); + assertEquals(Boolean.TRUE, + new DirectFieldAccessor(handler).getPropertyValue("autoCreateDirectory")); + assertTrue(new File(BASE_PATH + File.separator + "defaultOutbound").exists()); + } + + @Test + public void customOutbound() throws Exception { + Object adapter = context.getBean("customOutbound"); + DirectFieldAccessor adapterAccessor = new DirectFieldAccessor(adapter); + FileWritingMessageHandler handler = (FileWritingMessageHandler) + adapterAccessor.getPropertyValue("handler"); + assertTrue(new File(BASE_PATH + File.separator + "customOutbound").exists()); + assertEquals(Boolean.FALSE, + new DirectFieldAccessor(handler).getPropertyValue("autoCreateDirectory")); + } + + @Test + public void defaultOutboundGateway() throws Exception { + Object gateway = context.getBean("defaultOutboundGateway"); + DirectFieldAccessor gatewayAccessor = new DirectFieldAccessor(gateway); + FileWritingMessageHandler handler = (FileWritingMessageHandler) + gatewayAccessor.getPropertyValue("handler"); + assertEquals(Boolean.TRUE, + new DirectFieldAccessor(handler).getPropertyValue("autoCreateDirectory")); + assertTrue(new File(BASE_PATH + File.separator + "defaultOutboundGateway").exists()); + } + + @Test + public void customOutboundGateway() throws Exception { + Object gateway = context.getBean("customOutboundGateway"); + DirectFieldAccessor gatewayAccessor = new DirectFieldAccessor(gateway); + FileWritingMessageHandler handler = (FileWritingMessageHandler) + gatewayAccessor.getPropertyValue("handler"); + assertTrue(new File(BASE_PATH + File.separator + "customOutboundGateway").exists()); + assertEquals(Boolean.FALSE, + new DirectFieldAccessor(handler).getPropertyValue("autoCreateDirectory")); + } + +}