INT-356: Changed namespace parsing to resolve incompatible MessageCreator problem. type attribute on ftpsource no longer supported.

This commit is contained in:
Iwein Fuld
2008-09-01 17:41:19 +00:00
parent 12a0142d7b
commit a27ae5726e
12 changed files with 80 additions and 210 deletions

View File

@@ -16,15 +16,10 @@
package org.springframework.integration.adapter.file.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.integration.ConfigurationException;
import org.springframework.integration.adapter.file.ByteArrayFileMessageCreator;
import org.springframework.integration.adapter.file.FileMessageCreator;
import org.springframework.integration.adapter.file.TextFileMessageCreator;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Base class for directory-based sources.
@@ -35,46 +30,16 @@ public abstract class AbstractDirectorySourceParser extends AbstractSimpleBeanDe
public static final String MESSAGE_CREATOR_REFERENCE_ATTRIBUTE = "message-creator";
public static final String TYPE_ATTRIBUTE = "type";
private final boolean deleteFileAfterMessageCreation;
public AbstractDirectorySourceParser(boolean deleteFileAfterMessageCreation){
this.deleteFileAfterMessageCreation = deleteFileAfterMessageCreation;
}
@Override
protected boolean isEligibleAttribute(String attributeName) {
return !MESSAGE_CREATOR_REFERENCE_ATTRIBUTE.equals(attributeName)
&& !TYPE_ATTRIBUTE.equals(attributeName)
&& super.isEligibleAttribute(attributeName);
return !MESSAGE_CREATOR_REFERENCE_ATTRIBUTE.equals(attributeName) && super.isEligibleAttribute(attributeName);
}
@Override
protected void postProcess(BeanDefinitionBuilder beanDefinition, Element element) {
String messageCreatorReference = element.getAttribute(MESSAGE_CREATOR_REFERENCE_ATTRIBUTE);
String type = element.getAttribute(TYPE_ATTRIBUTE);
if (StringUtils.hasText(type) && StringUtils.hasText(messageCreatorReference)) {
throw new ConfigurationException(
"Either the 'type' or the 'message-creator' attributes are allowed, but not both.");
}
if (StringUtils.hasText(messageCreatorReference)) {
beanDefinition.addConstructorArgReference(messageCreatorReference);
}
else {
if ("text".equals(type)) {
beanDefinition.addConstructorArgValue(new TextFileMessageCreator(deleteFileAfterMessageCreation));
}
else if ("binary".equals(type)) {
beanDefinition.addConstructorArgValue(new ByteArrayFileMessageCreator(deleteFileAfterMessageCreation));
}
else {
beanDefinition.addConstructorArgValue(new FileMessageCreator());
}
}
}
}

View File

@@ -23,8 +23,10 @@ import java.util.regex.Pattern;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.core.io.ResourceLoader;
import org.springframework.integration.ConfigurationException;
import org.springframework.integration.adapter.file.ByteArrayFileMessageCreator;
import org.springframework.integration.adapter.file.FileSource;
import org.springframework.integration.adapter.file.RegexPatternFilenameFilter;
import org.springframework.integration.adapter.file.TextFileMessageCreator;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -36,6 +38,8 @@ import org.w3c.dom.Element;
*/
public class FileSourceParser extends AbstractDirectorySourceParser {
public static final String TYPE_ATTRIBUTE = "type";
public static final String DIRECTORY_ATTRIBUTE = "directory";
public static final String FILE_FILTER_ATTRIBUTE = "file-filter";
@@ -44,12 +48,6 @@ public class FileSourceParser extends AbstractDirectorySourceParser {
public static final String FILENAME_PATTERN_ATTRIBUTE = "filename-pattern";
public FileSourceParser() {
super(false);
}
@Override
protected Class<?> getBeanClass(Element element) {
return FileSource.class;
@@ -57,18 +55,16 @@ public class FileSourceParser extends AbstractDirectorySourceParser {
@Override
protected boolean isEligibleAttribute(String attributeName) {
return !DIRECTORY_ATTRIBUTE.equals(attributeName)
&& !FILE_FILTER_ATTRIBUTE.equals(attributeName)
return !DIRECTORY_ATTRIBUTE.equals(attributeName) && !FILE_FILTER_ATTRIBUTE.equals(attributeName)
&& !FILENAME_FILTER_ATTRIBUTE.equals(attributeName)
&& !FILENAME_PATTERN_ATTRIBUTE.equals(attributeName)
&& !FILENAME_PATTERN_ATTRIBUTE.equals(attributeName) && !TYPE_ATTRIBUTE.equals(attributeName)
&& super.isEligibleAttribute(attributeName);
}
@Override
protected void postProcess(BeanDefinitionBuilder beanDefinition, Element element) {
String directoryLocation = element.getAttribute(DIRECTORY_ATTRIBUTE);
if (!directoryLocation.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX)
&& !isUrl(directoryLocation)) {
if (!directoryLocation.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX) && !isUrl(directoryLocation)) {
directoryLocation = "file:" + directoryLocation;
}
beanDefinition.addConstructorArgValue(directoryLocation);
@@ -88,6 +84,22 @@ public class FileSourceParser extends AbstractDirectorySourceParser {
beanDefinition.addPropertyValue("filenameFilter", regexFilter);
}
super.postProcess(beanDefinition, element);
processTypeAttribute(beanDefinition, element);
}
private void processTypeAttribute(BeanDefinitionBuilder beanDefinition, Element element) {
if (beanDefinition.getRawBeanDefinition().getConstructorArgumentValues().getArgumentCount() == 2) {
// message-creator already defined, ignore type property
}
else {
String type = element.getAttribute(TYPE_ATTRIBUTE);
if ("text".equals(type)) {
beanDefinition.addConstructorArgValue(new TextFileMessageCreator(false));
}
else if ("binary".equals(type)) {
beanDefinition.addConstructorArgValue(new ByteArrayFileMessageCreator(false));
}
}
}
private boolean isUrl(String directoryLocation) {
@@ -100,14 +112,13 @@ public class FileSourceParser extends AbstractDirectorySourceParser {
}
}
private void verifyAtMostOneAttributeSpecified(String ... attributes) {
private void verifyAtMostOneAttributeSpecified(String... attributes) {
boolean attributeSpecified = false;
for (String attribute : attributes) {
if (StringUtils.hasText(attribute)) {
if (attributeSpecified) {
throw new ConfigurationException("FileSource supports at most one of '"
+ FILE_FILTER_ATTRIBUTE + "', '" + FILENAME_FILTER_ATTRIBUTE
+ "', and '" + FILENAME_PATTERN_ATTRIBUTE + "'.");
throw new ConfigurationException("FileSource supports at most one of '" + FILE_FILTER_ATTRIBUTE
+ "', '" + FILENAME_FILTER_ATTRIBUTE + "', and '" + FILENAME_PATTERN_ATTRIBUTE + "'.");
}
attributeSpecified = true;
}

View File

@@ -27,6 +27,7 @@ import org.apache.commons.net.ftp.FTPFile;
import org.springframework.integration.adapter.file.AbstractDirectorySource;
import org.springframework.integration.adapter.file.Backlog;
import org.springframework.integration.adapter.file.FileSnapshot;
import org.springframework.integration.message.DefaultMessageCreator;
import org.springframework.integration.message.MessageCreator;
import org.springframework.util.Assert;
@@ -45,6 +46,10 @@ public class FtpSource extends AbstractDirectorySource<List<File>> {
private final FTPClientPool clientPool;
public FtpSource(FTPClientPool clientPool) {
this(new DefaultMessageCreator<List<File>>(), clientPool);
}
public FtpSource(MessageCreator<List<File>, List<File>> messageCreator, FTPClientPool clientPool) {
super(messageCreator);
this.clientPool = clientPool;
@@ -63,11 +68,9 @@ public class FtpSource extends AbstractDirectorySource<List<File>> {
@Override
protected void refreshSnapshotAndMarkProcessing(Backlog<FileSnapshot> directoryContentManager) throws IOException {
List<FileSnapshot> snapshot = new ArrayList<FileSnapshot>();
synchronized (directoryContentManager) {
populateSnapshot(snapshot);
directoryContentManager.processSnapshot(snapshot);
directoryContentManager.prepareForProcessing(maxFilesPerMessage);
}
populateSnapshot(snapshot);
directoryContentManager.processSnapshot(snapshot);
directoryContentManager.prepareForProcessing(maxFilesPerMessage);
}
@Override
@@ -98,7 +101,8 @@ public class FtpSource extends AbstractDirectorySource<List<File>> {
List<File> files = new ArrayList<File>();
List<FileSnapshot> toDo = this.getBacklog().getProcessingBuffer();
for (FileSnapshot fileSnapshot : toDo) {
//some awkwardness here because the local path may be different from the remote path
// some awkwardness here because the local path may be different
// from the remote path
File file = new File(this.localWorkingDirectory, fileSnapshot.getFileName());
if (file.exists()) {
file.delete();

View File

@@ -40,10 +40,6 @@ public class FtpSourceParser extends AbstractDirectorySourceParser {
private static final String POOL_ATTRIBUTE_REMOTEDIR = "remote-working-directory";
public FtpSourceParser() {
super(true);
}
@Override
protected Class<?> getBeanClass(Element element) {
return FtpSource.class;

View File

@@ -51,7 +51,7 @@ public class FileSourceParserTests {
FileSource fileSource = (FileSource) context.getBean("fileSourceDefault");
DirectFieldAccessor sourceAccessor = new DirectFieldAccessor(fileSource);
File directory = (File) sourceAccessor.getPropertyValue("directory");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertEquals(System.getProperty("java.io.tmpdir"), directory.getAbsolutePath());
assertTrue(messageCreator instanceof FileMessageCreator);
}
@@ -62,7 +62,7 @@ public class FileSourceParserTests {
FileSource fileSource = (FileSource) context.getBean("fileSourceText");
DirectFieldAccessor sourceAccessor = new DirectFieldAccessor(fileSource);
File directory = (File) sourceAccessor.getPropertyValue("directory");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertEquals(System.getProperty("java.io.tmpdir"), directory.getAbsolutePath());
assertTrue(messageCreator instanceof TextFileMessageCreator);
}
@@ -73,7 +73,7 @@ public class FileSourceParserTests {
FileSource fileSource = (FileSource) context.getBean("fileSourceBinary");
DirectFieldAccessor sourceAccessor = new DirectFieldAccessor(fileSource);
File directory = (File) sourceAccessor.getPropertyValue("directory");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertEquals(System.getProperty("java.io.tmpdir"), directory.getAbsolutePath());
assertTrue(messageCreator instanceof ByteArrayFileMessageCreator);
}
@@ -84,28 +84,29 @@ public class FileSourceParserTests {
FileSource fileSource = (FileSource) context.getBean("fileSourceFile");
DirectFieldAccessor sourceAccessor = new DirectFieldAccessor(fileSource);
File directory = (File) sourceAccessor.getPropertyValue("directory");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertEquals(System.getProperty("java.io.tmpdir"), directory.getAbsolutePath());
assertTrue(messageCreator instanceof FileMessageCreator);
}
@Test(expected=ConfigurationException.class)
public void testInvalidFileSource() throws Throwable {
try {
new ClassPathXmlApplicationContext("invalidFileSourceTests.xml", this.getClass());
fail();
} catch (BeanDefinitionStoreException e) {
throw e.getCause();
}
}
@Test
public void testFileSourceWithCustomMessageCreator() {
ApplicationContext context = new ClassPathXmlApplicationContext("fileSourceParserTests.xml", this.getClass());
FileSource fileSource = (FileSource) context.getBean("fileSourceWithCustomMessageCreator");
DirectFieldAccessor sourceAccessor = new DirectFieldAccessor(fileSource);
File directory = (File) sourceAccessor.getPropertyValue("directory");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertEquals(System.getProperty("java.io.tmpdir"), directory.getAbsolutePath());
assertTrue(messageCreator instanceof CustomMessageCreator);
}
@Test
public void testFileSourceWithTypeAndCustomMessageCreator() {
ApplicationContext context = new ClassPathXmlApplicationContext("fileSourceParserTests.xml", this.getClass());
FileSource fileSource = (FileSource) context.getBean("fileSourceTypeAndCustom");
DirectFieldAccessor sourceAccessor = new DirectFieldAccessor(fileSource);
File directory = (File) sourceAccessor.getPropertyValue("directory");
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertEquals(System.getProperty("java.io.tmpdir"), directory.getAbsolutePath());
assertTrue(messageCreator instanceof CustomMessageCreator);
}
@@ -138,12 +139,13 @@ public class FileSourceParserTests {
assertTrue(filter.accept(null, "foo.txt"));
}
@Test(expected=ConfigurationException.class)
@Test(expected = ConfigurationException.class)
public void testFileSourceWithFileFilterAndFilenameFilterNotAllowed() throws Throwable {
try {
new ClassPathXmlApplicationContext("fileSourceWithTooManyFilters.xml", this.getClass());
fail();
} catch (BeanDefinitionStoreException e) {
}
catch (BeanDefinitionStoreException e) {
throw e.getCause();
}
}
@@ -152,8 +154,9 @@ public class FileSourceParserTests {
public void testFileSourceWithFileAndNotDirectory() {
try {
new ClassPathXmlApplicationContext("fileSourceWithFileDirectory.xml", this.getClass());
fail();
} catch (BeanCreationException ex) {
fail();
}
catch (BeanCreationException ex) {
assertTrue(ex.getCause().getCause().getMessage().indexOf("is not a directory") > 0);
}
}

View File

@@ -25,6 +25,8 @@
<si:file-source id="fileSourceWithCustomFilenameFilter" filename-filter="customFilenameFilter" directory="${java.io.tmpdir}"/>
<si:file-source id="fileSourceWithRegexFilter" filename-pattern="fo+\.[tx]{3}" directory="${java.io.tmpdir}"/>
<si:file-source id="fileSourceTypeAndCustom" type="text" message-creator="customMessageCreator" directory="${java.io.tmpdir}"/>
<bean id="customMessageCreator" class="org.springframework.integration.adapter.file.config.CustomMessageCreator"/>

View File

@@ -1,21 +0,0 @@
<?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"
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/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd">
<si:file-source id="fileSourceCustom" type="text"
message-creator="customMessageCreator" directory="${java.io.tmpdir}"/>
<bean id="customMessageCreator"
class="org.springframework.integration.adapter.file.config.CustomMessageCreator"/>
<context:property-placeholder/>
</beans>

View File

@@ -234,7 +234,7 @@ public class FtpSourceTests {
recorded.await();
recievedFiles = ftpSource.receive();
receivesDone.countDown();
//make sure onSend happens after all receives
// make sure onSend happens after all receives
receivesDone.await();
}
catch (InterruptedException e) {
@@ -245,7 +245,12 @@ public class FtpSourceTests {
}
}).start();
}
receivesDone.await();
try {
receivesDone.await();
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
verify(globalMocks);
}

View File

@@ -23,7 +23,6 @@ import static org.junit.Assert.fail;
import java.io.File;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.context.ApplicationContext;
@@ -34,6 +33,7 @@ import org.springframework.integration.adapter.file.FileMessageCreator;
import org.springframework.integration.adapter.file.TextFileMessageCreator;
import org.springframework.integration.adapter.file.config.CustomMessageCreator;
import org.springframework.integration.adapter.ftp.FtpSource;
import org.springframework.integration.message.DefaultMessageCreator;
/**
* @author Mark Fisher
@@ -55,63 +55,7 @@ public class FtpSourceParserTests {
assertEquals("testUser", accessor.getPropertyValue("username"));
assertEquals("testPassword", accessor.getPropertyValue("password"));
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertTrue(messageCreator instanceof FileMessageCreator);
DirectFieldAccessor messageCreatorAccessor = new DirectFieldAccessor(messageCreator);
assertEquals(messageCreatorAccessor.getPropertyValue("deleteFileAfterCreation"), false);
}
@Test
public void testFtpSourceTextType() {
ApplicationContext context = new ClassPathXmlApplicationContext("ftpSourceParserTests.xml", this.getClass());
FtpSource ftpSource = (FtpSource) context.getBean("ftpSourceText");
DirectFieldAccessor sourceAccessor = new DirectFieldAccessor(ftpSource);
DirectFieldAccessor accessor = new DirectFieldAccessor(sourceAccessor.getPropertyValue("clientPool"));
assertEquals("testHost", accessor.getPropertyValue("host"));
assertEquals(2121, accessor.getPropertyValue("port"));
assertEquals(new File("/local"), sourceAccessor.getPropertyValue("localWorkingDirectory"));
assertEquals("/remote", accessor.getPropertyValue("remoteWorkingDirectory"));
assertEquals("testUser", accessor.getPropertyValue("username"));
assertEquals("testPassword", accessor.getPropertyValue("password"));
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertTrue(messageCreator instanceof TextFileMessageCreator);
DirectFieldAccessor messageCreatorAccessor = new DirectFieldAccessor(messageCreator);
assertEquals(messageCreatorAccessor.getPropertyValue("deleteFileAfterCreation"), true);
}
@Test
public void testFtpSourceBinaryType() {
ApplicationContext context = new ClassPathXmlApplicationContext("ftpSourceParserTests.xml", this.getClass());
FtpSource ftpSource = (FtpSource) context.getBean("ftpSourceBinary");
DirectFieldAccessor sourceAccessor = new DirectFieldAccessor(ftpSource);
DirectFieldAccessor accessor = new DirectFieldAccessor(sourceAccessor.getPropertyValue("clientPool"));
assertEquals("testHost", accessor.getPropertyValue("host"));
assertEquals(2121, accessor.getPropertyValue("port"));
assertEquals(new File("/local"), sourceAccessor.getPropertyValue("localWorkingDirectory"));
assertEquals("/remote", accessor.getPropertyValue("remoteWorkingDirectory"));
assertEquals("testUser", accessor.getPropertyValue("username"));
assertEquals("testPassword", accessor.getPropertyValue("password"));
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertTrue(messageCreator instanceof ByteArrayFileMessageCreator);
DirectFieldAccessor messageCreatorAccessor = new DirectFieldAccessor(messageCreator);
assertEquals(messageCreatorAccessor.getPropertyValue("deleteFileAfterCreation"), true);
}
@Test
public void testFtpSourceFileType() {
ApplicationContext context = new ClassPathXmlApplicationContext("ftpSourceParserTests.xml", this.getClass());
FtpSource ftpSource = (FtpSource) context.getBean("ftpSourceFile");
DirectFieldAccessor sourceAccessor = new DirectFieldAccessor(ftpSource);
DirectFieldAccessor accessor = new DirectFieldAccessor(sourceAccessor.getPropertyValue("clientPool"));
assertEquals("testHost", accessor.getPropertyValue("host"));
assertEquals(2121, accessor.getPropertyValue("port"));
assertEquals(new File("/local"), sourceAccessor.getPropertyValue("localWorkingDirectory"));
assertEquals("/remote", accessor.getPropertyValue("remoteWorkingDirectory"));
assertEquals("testUser", accessor.getPropertyValue("username"));
assertEquals("testPassword", accessor.getPropertyValue("password"));
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertTrue(messageCreator instanceof FileMessageCreator);
DirectFieldAccessor messageCreatorAccessor = new DirectFieldAccessor(messageCreator);
assertEquals(messageCreatorAccessor.getPropertyValue("deleteFileAfterCreation"), false);
assertTrue(messageCreator instanceof DefaultMessageCreator);
}
@Test
@@ -128,19 +72,6 @@ public class FtpSourceParserTests {
assertEquals("testPassword", accessor.getPropertyValue("password"));
Object messageCreator = sourceAccessor.getPropertyValue("messageCreator");
assertTrue(messageCreator instanceof CustomMessageCreator);
// not testing for deleteFileAfterCreation - this is completely left up
// to the implementation
}
@Test
public void testInvalidFtpSource() {
try {
new ClassPathXmlApplicationContext("invalidFtpSourceTests.xml", this.getClass());
fail();
}
catch (BeanDefinitionStoreException e) {
assertTrue(e.getCause() instanceof ConfigurationException);
}
}
}

View File

@@ -22,7 +22,7 @@
remote-working-directory="/remote"
username="testUser"
password="testPassword"
type="text"/>
/>
<si:ftp-source id="ftpSourceBinary"
host="testHost"
@@ -31,7 +31,7 @@
remote-working-directory="/remote"
username="testUser"
password="testPassword"
type="binary"/>
/>
<si:ftp-source id="ftpSourceFile"
host="testHost"
@@ -40,7 +40,7 @@
remote-working-directory="/remote"
username="testUser"
password="testPassword"
type="file"/>
/>
<si:ftp-source id="ftpSourceCustom"
host="testHost"

View File

@@ -1,28 +0,0 @@
<?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"
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/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd">
<si:ftp-source id="ftpSourceCustom"
host="testHost"
port="2121"
local-working-directory="/local"
remote-working-directory="/remote"
username="testUser"
password="testPassword"
message-creator="customMessageCreator"
type="text"/>
<bean id="customMessageCreator"
class="org.springframework.integration.adapter.file.config.CustomMessageCreator"/>
<context:property-placeholder/>
</beans>