diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/config/spring-integration-adapters-1.0.xsd b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/config/spring-integration-adapters-1.0.xsd index e85c59531b..97cb80aec5 100644 --- a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/config/spring-integration-adapters-1.0.xsd +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/config/spring-integration-adapters-1.0.xsd @@ -25,6 +25,8 @@ + + @@ -37,6 +39,7 @@ + @@ -259,5 +262,13 @@ + + + + + + + + \ No newline at end of file diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/AbstractFileMapper.java b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/AbstractFileMessageCreator.java similarity index 51% rename from org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/AbstractFileMapper.java rename to org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/AbstractFileMessageCreator.java index cec4654cd4..477ec22a10 100644 --- a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/AbstractFileMapper.java +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/AbstractFileMessageCreator.java @@ -17,61 +17,24 @@ package org.springframework.integration.adapter.file; import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.integration.message.GenericMessage; import org.springframework.integration.message.Message; import org.springframework.integration.message.MessageCreator; -import org.springframework.integration.message.MessageHandlingException; -import org.springframework.integration.message.MessageMapper; import org.springframework.integration.message.MessagingException; -import org.springframework.util.Assert; -import org.springframework.util.FileCopyUtils; /** - * Base class providing common behavior for file-based message mappers. + * Base class providing common behavior for file-based message creators. * * @author Mark Fisher + * @author Marius Bogoevici */ -public abstract class AbstractFileMapper implements MessageCreator, MessageMapper { +public abstract class AbstractFileMessageCreator implements MessageCreator { protected Log logger = LogFactory.getLog(this.getClass()); - private File parentDirectory; - - private File backupDirectory; - - private FileNameGenerator fileNameGenerator = new DefaultFileNameGenerator(); - - - public AbstractFileMapper(File parentDirectory) { - this.parentDirectory = parentDirectory; - } - - public void setBackupDirectory(File backupDirectory) { - this.backupDirectory = backupDirectory; - } - - public void setFileNameGenerator(FileNameGenerator fileNameGenerator) { - Assert.notNull(fileNameGenerator, "'fileNameGenerator' must not be null"); - this.fileNameGenerator = fileNameGenerator; - } - - public File mapMessage(Message message) { - try { - File file = new File(parentDirectory, this.fileNameGenerator.generateFileName(message)); - this.writeToFile(file, message.getPayload()); - return file; - } - catch (Exception e) { - throw new MessageHandlingException(message, "failure occurred mapping file to message", e); - } - } - public Message createMessage(File file) { try { T payload = this.readMessagePayload(file); @@ -80,12 +43,6 @@ public abstract class AbstractFileMapper implements MessageCreator, } Message message = new GenericMessage(payload); message.getHeader().setProperty(FileNameGenerator.FILENAME_PROPERTY_KEY, file.getName()); - if (this.backupDirectory != null) { - FileWriter writer = new FileWriter(this.backupDirectory.getAbsolutePath() + - File.separator + file.getName()); - FileCopyUtils.copy(new FileReader(file), writer); - } - file.delete(); return message; } catch (Exception e) { @@ -99,6 +56,4 @@ public abstract class AbstractFileMapper implements MessageCreator, protected abstract T readMessagePayload(File file) throws Exception; - protected abstract void writeToFile(File file, T payload) throws Exception; - } diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/ByteArrayFileMapper.java b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/ByteArrayFileMessageCreator.java similarity index 73% rename from org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/ByteArrayFileMapper.java rename to org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/ByteArrayFileMessageCreator.java index a8aef0b75b..85593fafbf 100644 --- a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/ByteArrayFileMapper.java +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/ByteArrayFileMessageCreator.java @@ -21,26 +21,17 @@ import java.io.File; import org.springframework.util.FileCopyUtils; /** - * A {@link org.springframework.integration.message.MessageMapper} + * A {@link org.springframework.integration.message.MessageCreator} * implementation for messages with a byte array payload. * * @author Mark Fisher + * @author Marius Bogoevici */ -public class ByteArrayFileMapper extends AbstractFileMapper { - - public ByteArrayFileMapper(File parentDirectory) { - super(parentDirectory); - } - +public class ByteArrayFileMessageCreator extends AbstractFileMessageCreator { @Override protected byte[] readMessagePayload(File file) throws Exception { return FileCopyUtils.copyToByteArray(file); } - @Override - protected void writeToFile(File file, byte[] payload) throws Exception { - FileCopyUtils.copy(payload, file); - } - } diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileMessageCreator.java b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileMessageCreator.java new file mode 100755 index 0000000000..5a31753952 --- /dev/null +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileMessageCreator.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2007 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.adapter.file; + +import java.io.File; + +import org.springframework.integration.message.Message; +import org.springframework.integration.message.MessageCreator; + +/** + * A {@link MessageCreator} that creates {@link Message} instances with the + * absolute path to the {@link File} as payload. + * + * @author Marius Bogoevici + */ +public class FileMessageCreator extends AbstractFileMessageCreator { + + @Override + protected File readMessagePayload(File file) throws Exception { + return file; + } + +} diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileSource.java b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileSource.java index c1dcf6a565..9414027eb5 100644 --- a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileSource.java +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileSource.java @@ -18,46 +18,61 @@ package org.springframework.integration.adapter.file; import java.io.File; import java.io.FileFilter; +import java.io.FileOutputStream; import java.io.FilenameFilter; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.net.ftp.FTPFile; import org.springframework.beans.factory.InitializingBean; +import org.springframework.integration.adapter.ftp.DirectoryContentManager; +import org.springframework.integration.adapter.ftp.FileInfo; import org.springframework.integration.message.Message; +import org.springframework.integration.message.MessageCreator; +import org.springframework.integration.message.MessageDeliveryAware; import org.springframework.integration.message.MessagingException; import org.springframework.integration.message.Source; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * A messaging source that polls a directory to retrieve files. * * @author Mark Fisher + * @author Marius Bogoevici */ -public class FileSource implements Source, InitializingBean { +public class FileSource implements Source, InitializingBean, MessageDeliveryAware { + + private final Log logger = LogFactory.getLog(this.getClass()); private final File directory; - private volatile boolean textBased = true; - - private volatile AbstractFileMapper mapper; - - private volatile FileNameGenerator fileNameGenerator; - + private volatile MessageCreator messageCreator; + private volatile FileFilter fileFilter; private volatile FilenameFilter filenameFilter; - + private final DirectoryContentManager directoryContentManager = new DirectoryContentManager(); + + public FileSource(File directory) { + this(directory, new FileMessageCreator()); + } + + public FileSource(File directory, MessageCreator messageCreator) { Assert.notNull(directory, "directory must not be null"); this.directory = directory; + Assert.notNull(messageCreator, "MessageCreator must not be null"); + this.messageCreator = messageCreator; } - - public boolean isTextBased() { - return this.textBased; - } - - public void setTextBased(boolean textBased) { - this.textBased = textBased; + + public void setMessageCreator(MessageCreator messageCreator) { + this.messageCreator = messageCreator; } public void setFileFilter(FileFilter fileFilter) { @@ -68,19 +83,9 @@ public class FileSource implements Source, InitializingBean { this.filenameFilter = filenameFilter; } - public void setFileNameGenerator(FileNameGenerator fileNameGenerator) { - this.fileNameGenerator = fileNameGenerator; - } - public void afterPropertiesSet() { - if (this.isTextBased()) { - this.mapper = new TextFileMapper(this.directory); - } - else { - this.mapper = new ByteArrayFileMapper(this.directory); - } - if (this.fileNameGenerator != null) { - this.mapper.setFileNameGenerator(this.fileNameGenerator); + if (null == messageCreator) { + messageCreator = new FileMessageCreator(); } } @@ -99,12 +104,34 @@ public class FileSource implements Source, InitializingBean { throw new MessagingException("Problem occurred while polling for files. " + "Is '" + directory.getAbsolutePath() + "' a directory?"); } + HashMap snapshot = new HashMap(); for (int i = 0; i < files.length; i++) { - if (files[i].isFile()) { - return this.mapper.createMessage(files[i]); - } + FileInfo fileInfo = new FileInfo(files[i].getName(), files[i].lastModified(), files[i].length()); + snapshot.put(files[i].getName(), fileInfo); + } + this.directoryContentManager.processSnapshot(snapshot); + if (!this.directoryContentManager.getBacklog().isEmpty()) { + String fileName = this.directoryContentManager.getBacklog().keySet().iterator().next(); + File file = new File(directory, fileName); + return this.messageCreator.createMessage(file); } return null; } + public void onSend(Message message) { + String filename = message.getHeader().getProperty(FileNameGenerator.FILENAME_PROPERTY_KEY); + if (StringUtils.hasText(filename)) { + this.directoryContentManager.fileProcessed(filename); + } + else if (this.logger.isWarnEnabled()) { + logger.warn("No filename in Message header, cannot send notification of processing."); + } + } + + public void onFailure(MessagingException exception) { + if (this.logger.isWarnEnabled()) { + logger.warn("FtpSource received failure notifcation", exception); + } + } + } diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileTarget.java b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileTarget.java index ba0c14cdc7..afb508b91d 100644 --- a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileTarget.java +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/FileTarget.java @@ -19,42 +19,28 @@ package org.springframework.integration.adapter.file; import java.io.File; import org.springframework.integration.message.Message; +import org.springframework.integration.message.MessageMapper; import org.springframework.integration.message.Target; -import org.springframework.util.Assert; /** - * A message target for writing files. The actual file writing occurs in - * the message mapper ({@link TextFileMapper} or {@link ByteArrayFileMapper}). + * A message target for writing files. The actual file writing occurs in the + * message mapper ({@link TextFileMessageCreator} or {@link ByteArrayFileMessageCreator}). * * @author Mark Fisher + * @author Marius Bogoevici */ public class FileTarget implements Target { - private AbstractFileMapper mapper; + private MessageMapper messageMapper; - - public FileTarget(File directory) { - this(directory, true); + + public FileTarget(MessageMapper messageMapper) { + this.messageMapper = messageMapper; } - - public FileTarget(File directory, boolean isTextBased) { - if (isTextBased) { - this.mapper = new TextFileMapper(directory); - } - else { - this.mapper = new ByteArrayFileMapper(directory); - } - } - - public void setFileNameGenerator(FileNameGenerator fileNameGenerator) { - Assert.notNull(fileNameGenerator, "'fileNameGenerator' must not be null"); - if (mapper instanceof AbstractFileMapper) { - ((AbstractFileMapper) mapper).setFileNameGenerator(fileNameGenerator); - } - } - + + public boolean send(Message message) { - File file = this.mapper.mapMessage(message); + File file = this.messageMapper.mapMessage(message); return file.exists(); } diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/SimpleFileMessageMapper.java b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/SimpleFileMessageMapper.java new file mode 100644 index 0000000000..e74c6f92bd --- /dev/null +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/SimpleFileMessageMapper.java @@ -0,0 +1,79 @@ +/* + * Copyright 2002-2008 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.adapter.file; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import org.springframework.integration.message.Message; +import org.springframework.integration.message.MessageHandlingException; +import org.springframework.integration.message.MessageMapper; +import org.springframework.util.FileCopyUtils; + +/** + * A default {@link MessageMapper} for {@link FileTarget}, converting payloads of the + * {@link File}, {@code byte[]} and {@link String} types to files. The name of the newly + * created is defined by the {@link FileNameGenerator} instance configured with it. + * By default, it uses a {@link DefaultFileNameGenerator}. + * + * @author Marius Bogoevici + */ +public class SimpleFileMessageMapper implements MessageMapper { + + private volatile FileNameGenerator fileNameGenerator = new DefaultFileNameGenerator(); + + private final File parentDirectory; + + + public SimpleFileMessageMapper(String parentDirectoryPath) { + this(new File(parentDirectoryPath)); + } + + + public SimpleFileMessageMapper(File parentDirectory) { + this.parentDirectory = parentDirectory; + } + + + public void setFileNameGenerator(FileNameGenerator fileNameGenerator) { + this.fileNameGenerator = fileNameGenerator; + } + + public File mapMessage(Message message) { + try { + File file = new File(parentDirectory, this.fileNameGenerator.generateFileName(message)); + this.writeToFile(file, message.getPayload()); + return file; + } + catch (Exception e) { + throw new MessageHandlingException(message, "failure occurred mapping file to message", e); + } + } + + public void writeToFile(File file, Object payload) throws IOException { + if (payload instanceof byte[]) { + FileCopyUtils.copy((byte[]) payload, file); + } + else if (payload instanceof String) { + FileCopyUtils.copy((String) payload, new FileWriter(file)); + } + else if (payload instanceof File) { + FileCopyUtils.copy((File) payload, file); + } + } + +} diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/TextFileMapper.java b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/TextFileMessageCreator.java similarity index 77% rename from org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/TextFileMapper.java rename to org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/TextFileMessageCreator.java index 31e95e05cc..57f79bfb95 100644 --- a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/TextFileMapper.java +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/TextFileMessageCreator.java @@ -18,7 +18,6 @@ package org.springframework.integration.adapter.file; import java.io.File; import java.io.FileReader; -import java.io.FileWriter; import org.springframework.util.FileCopyUtils; @@ -27,22 +26,13 @@ import org.springframework.util.FileCopyUtils; * implementation for messages with a String payload. * * @author Mark Fisher + * @author Marius Bogoevici */ -public class TextFileMapper extends AbstractFileMapper { - - public TextFileMapper(File parentDirectory) { - super(parentDirectory); - } - +public class TextFileMessageCreator extends AbstractFileMessageCreator { @Override protected String readMessagePayload(File file) throws Exception { return FileCopyUtils.copyToString(new FileReader(file)); } - @Override - protected void writeToFile(File file, String payload) throws Exception { - FileCopyUtils.copy(payload, new FileWriter(file)); - } - } diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/config/FileSourceParser.java b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/config/FileSourceParser.java index 5d1463e08a..6221785f50 100644 --- a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/config/FileSourceParser.java +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/config/FileSourceParser.java @@ -16,19 +16,37 @@ 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.FileSource; +import org.springframework.integration.adapter.file.TextFileMessageCreator; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; /** * Parser for the <file-source/> element. * * @author Mark Fisher + * @author Marius Bogoevici */ public class FileSourceParser extends AbstractSimpleBeanDefinitionParser { + private static final String FILE_SOURCE_TYPE_ATTRIBUTE = "file"; + + private static final String TEXT_SOURCE_TYPE_ATTRIBUTE = "text"; + + private static final String BINARY_SOURCE_TYPE_ATTRIBUTE = "binary"; + + public static final String DIRECTORY_ATTRIBUTE = "directory"; + + public static final String MESSAGE_CREATOR_REFERENCE_ATTRIBUTE = "message-creator"; + + public static final String TYPE_ATTRIBUTE = "type"; + + @Override protected Class getBeanClass(Element element) { return FileSource.class; @@ -36,12 +54,34 @@ public class FileSourceParser extends AbstractSimpleBeanDefinitionParser { @Override protected boolean isEligibleAttribute(String attributeName) { - return (!"directory".equals(attributeName)) && super.isEligibleAttribute(attributeName); + return !(DIRECTORY_ATTRIBUTE.equals(attributeName) || MESSAGE_CREATOR_REFERENCE_ATTRIBUTE.equals(attributeName) || TYPE_ATTRIBUTE + .equals(attributeName)) + && super.isEligibleAttribute(attributeName); } @Override protected void postProcess(BeanDefinitionBuilder beanDefinition, Element element) { - beanDefinition.addConstructorArgValue(element.getAttribute("directory")); + beanDefinition.addConstructorArgValue(element.getAttribute(DIRECTORY_ATTRIBUTE)); + 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 (!StringUtils.hasText(type) || FILE_SOURCE_TYPE_ATTRIBUTE.equals(type)) { + beanDefinition.addConstructorArgValue(new FileMessageCreator()); + } + else if (TEXT_SOURCE_TYPE_ATTRIBUTE.equals(type)) { + beanDefinition.addConstructorArgValue(new TextFileMessageCreator()); + } + else if (BINARY_SOURCE_TYPE_ATTRIBUTE.equals(type)) { + beanDefinition.addConstructorArgValue(new ByteArrayFileMessageCreator()); + } + } } } diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/config/FileTargetParser.java b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/config/FileTargetParser.java index 7ac778b54c..31dd299b7c 100644 --- a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/config/FileTargetParser.java +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/file/config/FileTargetParser.java @@ -16,34 +16,57 @@ package org.springframework.integration.adapter.file.config; -import org.w3c.dom.Element; - +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.adapter.file.FileTarget; +import org.springframework.integration.adapter.file.SimpleFileMessageMapper; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; /** - * Parser for the <file-target/> element. + * Parser for the <file-target/> element. * * @author Mark Fisher + * @author Marius Bogoevici */ -public class FileTargetParser extends AbstractSingleBeanDefinitionParser { +public class FileTargetParser extends AbstractSimpleBeanDefinitionParser { + private static final String NAME_GENERATOR_PROPERTY = "fileNameGenerator"; + + public static final String DIRECTORY_ATTRIBUTE = "directory"; + + public static final String FILE_NAME_GENERATOR_ATTRIBUTE = "name-generator"; + + + @Override protected Class getBeanClass(Element element) { return FileTarget.class; } - protected boolean shouldGenerateId() { - return false; - } - - protected boolean shouldGenerateIdAsFallback() { - return true; + @Override + protected boolean isEligibleAttribute(String attributeName) { + return !(DIRECTORY_ATTRIBUTE.equals(attributeName) || FILE_NAME_GENERATOR_ATTRIBUTE.equals(attributeName)) + && super.isEligibleAttribute(attributeName); } + @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { - builder.addConstructorArgValue(element.getAttribute("directory")); + super.doParse(element, parserContext, builder); + BeanDefinition messageMapperDefinition = new RootBeanDefinition(SimpleFileMessageMapper.class); + messageMapperDefinition.getConstructorArgumentValues().addGenericArgumentValue( + element.getAttribute(DIRECTORY_ATTRIBUTE)); + if (StringUtils.hasText(element.getAttribute(FILE_NAME_GENERATOR_ATTRIBUTE))) { + messageMapperDefinition.getPropertyValues().addPropertyValue(NAME_GENERATOR_PROPERTY, + new RuntimeBeanReference(element.getAttribute(FILE_NAME_GENERATOR_ATTRIBUTE))); + } + String mapperBeanName = parserContext.getReaderContext().generateBeanName(messageMapperDefinition); + parserContext.getRegistry().registerBeanDefinition( + mapperBeanName, messageMapperDefinition); + builder.addConstructorArgReference(mapperBeanName); } } diff --git a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/ftp/FtpSource.java b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/ftp/FtpSource.java index f6aff0eef2..bb3e9e1c7a 100644 --- a/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/ftp/FtpSource.java +++ b/org.springframework.integration.adapter/src/main/java/org/springframework/integration/adapter/ftp/FtpSource.java @@ -28,9 +28,9 @@ import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; -import org.springframework.integration.adapter.file.ByteArrayFileMapper; +import org.springframework.integration.adapter.file.ByteArrayFileMessageCreator; import org.springframework.integration.adapter.file.FileNameGenerator; -import org.springframework.integration.adapter.file.TextFileMapper; +import org.springframework.integration.adapter.file.TextFileMessageCreator; import org.springframework.integration.message.Message; import org.springframework.integration.message.MessageCreator; import org.springframework.integration.message.MessageDeliveryAware; @@ -113,10 +113,10 @@ public class FtpSource implements Source, MessageDeliveryAware { public void afterPropertiesSet() { if (this.isTextBased()) { - this.messageCreator = new TextFileMapper(this.localWorkingDirectory); + this.messageCreator = new TextFileMessageCreator(); } else { - this.messageCreator = new ByteArrayFileMapper(this.localWorkingDirectory); + this.messageCreator = new ByteArrayFileMessageCreator(); } } diff --git a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/CustomMessageCreator.java b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/CustomMessageCreator.java new file mode 100644 index 0000000000..773d2f42a6 --- /dev/null +++ b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/CustomMessageCreator.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2008 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.adapter.file.config; + +import java.io.File; + +import org.springframework.integration.message.GenericMessage; +import org.springframework.integration.message.Message; +import org.springframework.integration.message.MessageCreator; + +/** + * @author Marius Bogoevici + */ +public class CustomMessageCreator implements MessageCreator{ + + public Message createMessage(File object) { + return new GenericMessage (object.getAbsolutePath()); + } + +} diff --git a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/CustomNameGenerator.java b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/CustomNameGenerator.java new file mode 100644 index 0000000000..bc16b93d19 --- /dev/null +++ b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/CustomNameGenerator.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2008 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.adapter.file.config; + +import java.util.Date; + +import org.springframework.integration.adapter.file.FileNameGenerator; +import org.springframework.integration.message.Message; + +/** + * @author Marius Bogoevici + */ +public class CustomNameGenerator implements FileNameGenerator{ + + public String generateFileName(Message message) { + return "file" + new Date().getTime(); + } + +} diff --git a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/FileSourceParserTests.java b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/FileSourceParserTests.java index 893f887b1c..332914ca46 100644 --- a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/FileSourceParserTests.java +++ b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/FileSourceParserTests.java @@ -17,28 +17,91 @@ package org.springframework.integration.adapter.file.config; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +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; import org.springframework.context.support.ClassPathXmlApplicationContext; +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.FileSource; +import org.springframework.integration.adapter.file.TextFileMessageCreator; /** * @author Mark Fisher + * @author Marius Bogoevici */ public class FileSourceParserTests { @Test - public void testFileSource() { + public void testFileSourceDefaultType() { ApplicationContext context = new ClassPathXmlApplicationContext("fileSourceParserTests.xml", this.getClass()); - FileSource fileSource = (FileSource) context.getBean("fileSource"); + FileSource fileSource = (FileSource) context.getBean("fileSourceDefault"); 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 FileMessageCreator); } - + + @Test + public void testFileSourceTextType() { + ApplicationContext context = new ClassPathXmlApplicationContext("fileSourceParserTests.xml", this.getClass()); + FileSource fileSource = (FileSource) context.getBean("fileSourceText"); + 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 TextFileMessageCreator); + } + + @Test + public void testFileSourceBinaryType() { + ApplicationContext context = new ClassPathXmlApplicationContext("fileSourceParserTests.xml", this.getClass()); + FileSource fileSource = (FileSource) context.getBean("fileSourceBinary"); + 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 ByteArrayFileMessageCreator); + } + + @Test + public void testFileSourceFileType() { + ApplicationContext context = new ClassPathXmlApplicationContext("fileSourceParserTests.xml", this.getClass()); + FileSource fileSource = (FileSource) context.getBean("fileSourceFile"); + 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 FileMessageCreator); + } + + @Test + public void testFileSourceCustomType() { + ApplicationContext context = new ClassPathXmlApplicationContext("fileSourceParserTests.xml", this.getClass()); + FileSource fileSource = (FileSource) context.getBean("fileSourceCustom"); + 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); + } + + @Test + public void testInvalidFileSource() { + try { + ApplicationContext context = new ClassPathXmlApplicationContext("invalidFileSourceTests.xml", this.getClass()); + fail(); + } catch (BeanDefinitionStoreException e) { + assertTrue(e.getCause() instanceof ConfigurationException); + } + } + } diff --git a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/FileTargetParserTests.java b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/FileTargetParserTests.java index dccf4248b5..e4198cfbf5 100644 --- a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/FileTargetParserTests.java +++ b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/FileTargetParserTests.java @@ -17,24 +17,44 @@ package org.springframework.integration.adapter.file.config; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; import org.junit.Test; - +import org.springframework.beans.DirectFieldAccessor; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.integration.adapter.file.DefaultFileNameGenerator; import org.springframework.integration.adapter.file.FileTarget; -import org.springframework.integration.message.Target; +import org.springframework.integration.adapter.file.SimpleFileMessageMapper; /** * @author Mark Fisher + * @author Marius Bogoevici */ public class FileTargetParserTests { @Test public void testFileTarget() { ApplicationContext context = new ClassPathXmlApplicationContext("fileTargetParserTests.xml", this.getClass()); - Target target = (Target) context.getBean("target"); - assertEquals(FileTarget.class, target.getClass()); + FileTarget target = (FileTarget) context.getBean("target"); + DirectFieldAccessor targetFieldAccessor = new DirectFieldAccessor(target); + SimpleFileMessageMapper messageMapper = (SimpleFileMessageMapper) targetFieldAccessor.getPropertyValue("messageMapper"); + DirectFieldAccessor mapperAccessor = new DirectFieldAccessor(messageMapper); + assertEquals(System.getProperty("java.io.tmpdir"), ((File) mapperAccessor.getPropertyValue("parentDirectory")).getAbsolutePath()); + assertTrue(mapperAccessor.getPropertyValue("fileNameGenerator") instanceof DefaultFileNameGenerator); } + @Test + public void testFileTargetWithCustomFilenameGenerator() { + ApplicationContext context = new ClassPathXmlApplicationContext("fileTargetParserTests.xml", this.getClass()); + FileTarget target = (FileTarget) context.getBean("targetWithCustomNameGenerator"); + DirectFieldAccessor targetFieldAccessor = new DirectFieldAccessor(target); + SimpleFileMessageMapper messageMapper = (SimpleFileMessageMapper) targetFieldAccessor.getPropertyValue("messageMapper"); + DirectFieldAccessor mapperAccessor = new DirectFieldAccessor(messageMapper); + assertEquals(System.getProperty("java.io.tmpdir"), ((File) mapperAccessor.getPropertyValue("parentDirectory")).getAbsolutePath()); + assertTrue(mapperAccessor.getPropertyValue("fileNameGenerator") instanceof CustomNameGenerator); + + } } diff --git a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/fileSourceParserTests.xml b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/fileSourceParserTests.xml index aff5d2137c..375fe37934 100644 --- a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/fileSourceParserTests.xml +++ b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/fileSourceParserTests.xml @@ -10,7 +10,17 @@ http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd"> - + + + + + + + + + + + diff --git a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/fileTargetParserTests.xml b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/fileTargetParserTests.xml index 46b6197d2e..59ab012d15 100644 --- a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/fileTargetParserTests.xml +++ b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/fileTargetParserTests.xml @@ -15,6 +15,10 @@ + + + + diff --git a/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/invalidFileSourceTests.xml b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/invalidFileSourceTests.xml new file mode 100644 index 0000000000..9236043e61 --- /dev/null +++ b/org.springframework.integration.adapter/src/test/java/org/springframework/integration/adapter/file/config/invalidFileSourceTests.xml @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/BinaryFileCopyDemo.java b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/BinaryFileCopyDemo.java new file mode 100644 index 0000000000..61c1806615 --- /dev/null +++ b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/BinaryFileCopyDemo.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2008 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.samples.filecopy; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Demonstrating the file copy scenario using binary file source and target. + * + * @author Marius Bogoevici + */ +public class BinaryFileCopyDemo { + + public static void main(String[] args) { + FileCopyDemoCommon.setupDirectories(); + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("fileCopyDemo-binary.xml", + BinaryFileCopyDemo.class); + context.start(); + } + +} + diff --git a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/Exclaimer.java b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/Exclaimer.java index b56b1e4db2..0515e84731 100644 --- a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/Exclaimer.java +++ b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/Exclaimer.java @@ -16,13 +16,29 @@ package org.springframework.integration.samples.filecopy; +import java.io.File; + /** + * A class providing several handling methods for different types of payloads. + * * @author Mark Fisher + * @author Marius Bogoevici */ public class Exclaimer { public String exclaim(String input) { - return input.toUpperCase() + "!!!"; + System.out.println("Copying text: " + input); + return input.toUpperCase(); + } + + public File exclaim(File input) { + System.out.println("Copying file: " + input.getAbsolutePath()); + return input; + } + + public byte[] exclaim(byte[] input) { + System.out.println("Copying " + input.length + " bytes ..."); + return new String(input).toUpperCase().getBytes(); } } diff --git a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/FileBasedFileCopyDemo.java b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/FileBasedFileCopyDemo.java new file mode 100644 index 0000000000..8f6232fbea --- /dev/null +++ b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/FileBasedFileCopyDemo.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2007 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.samples.filecopy; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Demonstrating the file copy scenario using file-based source and target. + * + * @author Marius Bogoevici + */ +public class FileBasedFileCopyDemo { + + public static void main(String[] args) { + FileCopyDemoCommon.setupDirectories(); + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("fileCopyDemo-file.xml", + FileBasedFileCopyDemo.class); + context.start(); + } + +} + diff --git a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/FileCopyDemo.java b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/FileCopyDemoCommon.java similarity index 75% rename from org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/FileCopyDemo.java rename to org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/FileCopyDemoCommon.java index a5954548ea..8ac47809f1 100644 --- a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/FileCopyDemo.java +++ b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/FileCopyDemoCommon.java @@ -18,22 +18,14 @@ package org.springframework.integration.samples.filecopy; import java.io.File; -import org.springframework.context.support.ClassPathXmlApplicationContext; - /** - * Demo of file source and target adapters. + * Common functionality for the file demo. * - * @author Mark Fisher + * @author Marius Bogoevici */ -public class FileCopyDemo { +public class FileCopyDemoCommon { - public static void main(String[] args) { - setupDirectories(); - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("fileCopyDemo.xml", FileCopyDemo.class); - context.start(); - } - - private static void setupDirectories() { + public static void setupDirectories() { String tmpDirPath = System.getProperty("java.io.tmpdir"); File parentDir = new File(tmpDirPath + File.separator + "spring-integration-samples"); File inDir = new File(parentDir, "input"); @@ -47,5 +39,5 @@ public class FileCopyDemo { System.exit(0); } } - + } diff --git a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/TextFileCopyDemo.java b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/TextFileCopyDemo.java new file mode 100644 index 0000000000..682f83af41 --- /dev/null +++ b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/TextFileCopyDemo.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2007 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.samples.filecopy; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Demo of file source and target adapters. + * + * @author Mark Fisher + * @author Marius Bogoevici + */ +public class TextFileCopyDemo { + + public static void main(String[] args) { + FileCopyDemoCommon.setupDirectories(); + ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("fileCopyDemo-text.xml", + TextFileCopyDemo.class); + context.start(); + } + +} + diff --git a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-binary.xml b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-binary.xml new file mode 100644 index 0000000000..9718cbe722 --- /dev/null +++ b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-binary.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo.xml b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-common.xml similarity index 92% rename from org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo.xml rename to org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-common.xml index ccc1998598..de95662586 100644 --- a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo.xml +++ b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-common.xml @@ -24,8 +24,6 @@ - - diff --git a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-file.xml b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-file.xml new file mode 100644 index 0000000000..78b3ad2616 --- /dev/null +++ b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-file.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-text.xml b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-text.xml new file mode 100644 index 0000000000..de0faec939 --- /dev/null +++ b/org.springframework.integration.samples/src/main/java/org/springframework/integration/samples/filecopy/fileCopyDemo-text.xml @@ -0,0 +1,14 @@ + + + + + + + +