INT-724, INT-725 Added an 'auto-create-directory' attribute to all File adapters with a default value of TRUE. Now, if the inbound or outbound directory does not yet exist, it may be created upon initialization.

This commit is contained in:
Mark Fisher
2009-07-16 00:35:23 +00:00
parent b9d90eff7a
commit 89b39de9bf
8 changed files with 371 additions and 12 deletions

View File

@@ -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<File> {
public class FileReadingMessageSource implements MessageSource<File>, InitializingBean {
private static final int INTERNAL_QUEUE_CAPACITY = 5;
@@ -69,6 +70,8 @@ public class FileReadingMessageSource implements MessageSource<File> {
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<File> {
toBeReceived = new PriorityBlockingQueue<File>(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
* <emphasis>true</emphasis>. If set to <emphasis>false</emphasis> 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<File> {
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<File> receive() throws MessagingException {
Message<File> message = null;
// rescan only if needed or explicitly configured

View File

@@ -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
* <emphasis>true</emphasis>. If set to <emphasis>false</emphasis> 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");

View File

@@ -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());

View File

@@ -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)) {

View File

@@ -72,6 +72,15 @@
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-startup" type="xsd:string" default="true"/>
<xsd:attribute name="auto-create-directory" type="xsd:string" default="true">
<xsd:annotation>
<xsd:documentation>
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.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
@@ -164,6 +173,15 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-create-directory" type="xsd:string" default="true">
<xsd:annotation>
<xsd:documentation>
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.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-startup" type="xsd:string"/>
</xsd:complexType>

View File

@@ -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();
}
}

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:si="http://www.springframework.org/schema/integration"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:file="http://www.springframework.org/schema/integration/file"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
http://www.springframework.org/schema/integration/file
http://www.springframework.org/schema/integration/file/spring-integration-file-1.0.xsd">
<si:channel id="channel1"/>
<si:channel id="channel2"/>
<si:channel id="channel3"/>
<si:channel id="channel4"/>
<si:channel id="channel5"/>
<si:channel id="channel6"/>
<file:inbound-channel-adapter id="defaultInbound"
channel="channel1"
directory="file:${java.io.tmpdir}${file.separator}AutoCreateDirectoryIntegrationTests${file.separator}defaultInbound"
auto-startup="false"/>
<file:inbound-channel-adapter id="customInbound"
channel="channel2"
directory="file:${java.io.tmpdir}${file.separator}AutoCreateDirectoryIntegrationTests${file.separator}customInbound"
auto-startup="false"
auto-create-directory="false"/>
<file:outbound-channel-adapter id="defaultOutbound"
channel="channel3"
directory="file:${java.io.tmpdir}${file.separator}AutoCreateDirectoryIntegrationTests${file.separator}defaultOutbound"
auto-startup="false"/>
<file:outbound-channel-adapter id="customOutbound"
channel="channel4"
directory="file:${java.io.tmpdir}${file.separator}AutoCreateDirectoryIntegrationTests${file.separator}customOutbound"
auto-startup="false"
auto-create-directory="false"/>
<file:outbound-gateway id="defaultOutboundGateway"
request-channel="channel5"
directory="file:${java.io.tmpdir}${file.separator}AutoCreateDirectoryIntegrationTests${file.separator}defaultOutboundGateway"
auto-startup="false"/>
<file:outbound-gateway id="customOutboundGateway"
request-channel="channel6"
directory="file:${java.io.tmpdir}${file.separator}AutoCreateDirectoryIntegrationTests${file.separator}customOutboundGateway"
auto-startup="false"
auto-create-directory="false"/>
<context:property-placeholder/>
<si:poller default="true">
<si:interval-trigger interval="10000"/>
</si:poller>
</beans>

View File

@@ -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"));
}
}