From 49b636109578c25bba5630348e69d1e59f8d0052 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 28 Dec 2007 02:01:42 +0000 Subject: [PATCH] Added file source adapter and supporting classes. --- .../adapter/file/AbstractFileMapper.java | 101 ++++++++++++++++++ .../adapter/file/ByteArrayFileMapper.java | 46 ++++++++ .../file/DefaultFileNameGenerator.java | 33 ++++++ .../adapter/file/FileNameGenerator.java | 30 ++++++ .../integration/adapter/file/FileSource.java | 80 ++++++++++++++ .../adapter/file/FileSourceAdapter.java | 55 ++++++++++ .../adapter/file/TextFileMapper.java | 48 +++++++++ 7 files changed, 393 insertions(+) create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/adapter/file/AbstractFileMapper.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/adapter/file/ByteArrayFileMapper.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/adapter/file/DefaultFileNameGenerator.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileNameGenerator.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileSource.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileSourceAdapter.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/adapter/file/TextFileMapper.java diff --git a/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/AbstractFileMapper.java b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/AbstractFileMapper.java new file mode 100644 index 0000000000..8bb5326fee --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/AbstractFileMapper.java @@ -0,0 +1,101 @@ +/* + * 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 java.io.FileReader; +import java.io.FileWriter; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.integration.MessageHandlingException; +import org.springframework.integration.message.AbstractMessageMapper; +import org.springframework.integration.message.GenericMessage; +import org.springframework.integration.message.Message; +import org.springframework.util.Assert; +import org.springframework.util.FileCopyUtils; + +/** + * Base class providing common behavior for file-based message mappers. + * + * @author Mark Fisher + */ +public abstract class AbstractFileMapper extends AbstractMessageMapper { + + 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 fromMessage(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("failure occurred mapping file to message", e); + } + } + + public Message toMessage(File file) { + try { + T payload = this.readMessagePayload(file); + if (payload == null) { + return null; + } + Message message = new GenericMessage(this.getUidGenerator().generateUid(), payload); + 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) { + String errorMessage = "failure occurred mapping file to message"; + if (logger.isWarnEnabled()) { + logger.warn(errorMessage, e); + } + throw new MessageHandlingException(errorMessage, e); + } + } + + protected abstract T readMessagePayload(File file) throws Exception; + + protected abstract void writeToFile(File file, T payload) throws Exception; + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/ByteArrayFileMapper.java b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/ByteArrayFileMapper.java new file mode 100644 index 0000000000..a8aef0b75b --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/ByteArrayFileMapper.java @@ -0,0 +1,46 @@ +/* + * 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.util.FileCopyUtils; + +/** + * A {@link org.springframework.integration.message.MessageMapper} + * implementation for messages with a byte array payload. + * + * @author Mark Fisher + */ +public class ByteArrayFileMapper extends AbstractFileMapper { + + public ByteArrayFileMapper(File parentDirectory) { + super(parentDirectory); + } + + + @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/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/DefaultFileNameGenerator.java b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/DefaultFileNameGenerator.java new file mode 100644 index 0000000000..61b1dde2f3 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/DefaultFileNameGenerator.java @@ -0,0 +1,33 @@ +/* + * 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 org.springframework.integration.message.Message; + +/** + * Default implementation of the filename generator strategy. Concatenates the + * message id and the current timestamp. + * + * @author Mark Fisher + */ +public class DefaultFileNameGenerator implements FileNameGenerator { + + public String generateFileName(Message message) { + return message.getId() + "-" + System.currentTimeMillis() + ".msg"; + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileNameGenerator.java b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileNameGenerator.java new file mode 100644 index 0000000000..09802dbd26 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileNameGenerator.java @@ -0,0 +1,30 @@ +/* + * 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 org.springframework.integration.message.Message; + +/** + * Strategy interface for generating a file name from a message. + * + * @author Mark Fisher + */ +public interface FileNameGenerator { + + String generateFileName(Message message); + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileSource.java b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileSource.java new file mode 100644 index 0000000000..4c65794dea --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileSource.java @@ -0,0 +1,80 @@ +/* + * 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 java.io.FileFilter; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.integration.MessageHandlingException; +import org.springframework.integration.adapter.PollableSource; +import org.springframework.util.Assert; + +/** + * A messaging source that polls a directory to retrieve files. + * + * @author Mark Fisher + */ +public class FileSource implements PollableSource { + + private File directory; + + private FileFilter fileFilter; + + private FilenameFilter filenameFilter; + + + public FileSource(File directory) { + Assert.notNull("directory must not be null"); + this.directory = directory; + } + + public void setFileFilter(FileFilter fileFilter) { + this.fileFilter = fileFilter; + } + + public void setFilenameFilter(FilenameFilter filenameFilter) { + this.filenameFilter = filenameFilter; + } + + public Collection poll(int limit) { + File[] files = null; + if (this.fileFilter != null) { + files = this.directory.listFiles(fileFilter); + } + else if (this.filenameFilter != null) { + files = this.directory.listFiles(filenameFilter); + } + else { + files = this.directory.listFiles(); + } + if (files == null) { + throw new MessageHandlingException("Problem occurred while polling for files. " + + "Is '" + directory.getAbsolutePath() + "' a directory?"); + } + int size = Math.min(limit, files.length); + List results = new ArrayList(size); + for (int i = 0; i < size; i++) { + results.add(files[i]); + } + return results; + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileSourceAdapter.java b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileSourceAdapter.java new file mode 100644 index 0000000000..b0f0bc8562 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/FileSourceAdapter.java @@ -0,0 +1,55 @@ +/* + * 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.adapter.PollingSourceAdapter; +import org.springframework.integration.channel.MessageChannel; +import org.springframework.integration.message.MessageMapper; +import org.springframework.util.Assert; + +/** + * Channel adapter for polling a directory and creating messages from its files. + * + * @author Mark Fisher + */ +public class FileSourceAdapter extends PollingSourceAdapter { + + public FileSourceAdapter(File directory, MessageChannel channel, int pollInterval) { + this(directory, channel, pollInterval, true); + } + + public FileSourceAdapter(File directory, MessageChannel channel, int pollInterval, boolean isTextBased) { + super(new FileSource(directory), channel, pollInterval); + if (isTextBased) { + this.setMessageMapper(new TextFileMapper(directory)); + } + else { + this.setMessageMapper(new ByteArrayFileMapper(directory)); + } + } + + public void setBackupDirectory(File backupDirectory) { + Assert.notNull(backupDirectory, "'backupDirectory' must not be null"); + MessageMapper mapper = this.getMessageMapper(); + if (mapper != null && (mapper instanceof AbstractFileMapper)) { + ((AbstractFileMapper) mapper).setBackupDirectory(backupDirectory); + } + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/TextFileMapper.java b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/TextFileMapper.java new file mode 100644 index 0000000000..d1661f21f5 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/adapter/file/TextFileMapper.java @@ -0,0 +1,48 @@ +/* + * 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 java.io.FileReader; +import java.io.FileWriter; + +import org.springframework.util.FileCopyUtils; + +/** + * A {@link org.springframework.integration.message.MessageMapper} + * implementation for messages with a String payload. + * + * @author Mark Fisher + */ +public class TextFileMapper extends AbstractFileMapper { + + public TextFileMapper(File parentDirectory) { + super(parentDirectory); + } + + + @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)); + } + +}