Migrating adapters to spring-integration-adapters (INT-83).

This commit is contained in:
Mark Fisher
2008-02-21 22:55:19 +00:00
parent a04842a3fb
commit 553b67ee2f
10 changed files with 581 additions and 0 deletions

View File

@@ -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.message.AbstractMessageMapper;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageHandlingException;
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<T> extends AbstractMessageMapper<T, File> {
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<T> 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<T> toMessage(File file) {
try {
T payload = this.readMessagePayload(file);
if (payload == null) {
return null;
}
Message<T> message = new GenericMessage<T>(this.getIdGenerator().generateId(), 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;
}

View File

@@ -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<byte[]> {
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);
}
}

View File

@@ -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.adapter.file;
import org.springframework.integration.message.Message;
import org.springframework.util.StringUtils;
/**
* 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) {
String filenameProperty = message.getHeader().getProperty(FILENAME_PROPERTY_KEY);
return StringUtils.hasText(filenameProperty) ?
filenameProperty : message.getId() + "-" + System.currentTimeMillis() + ".msg";
}
}

View File

@@ -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;
/**
* Strategy interface for generating a file name from a message.
*
* @author Mark Fisher
*/
public interface FileNameGenerator {
String FILENAME_PROPERTY_KEY = "filename";
String generateFileName(Message<?> message);
}

View File

@@ -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.adapter.PollableSource;
import org.springframework.integration.message.MessageHandlingException;
import org.springframework.util.Assert;
/**
* A messaging source that polls a directory to retrieve files.
*
* @author Mark Fisher
*/
public class FileSource implements PollableSource<File> {
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<File> 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<File> results = new ArrayList<File>(size);
for (int i = 0; i < size; i++) {
results.add(files[i]);
}
return results;
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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<File> {
public FileSourceAdapter(File directory, MessageChannel channel, int period) {
this(directory, channel, period, true);
}
public FileSourceAdapter(File directory, MessageChannel channel, int period, boolean isTextBased) {
super(new FileSource(directory));
this.setChannel(channel);
this.setPeriod(period);
if (isTextBased) {
this.setMessageMapper(new TextFileMapper(directory));
}
else {
this.setMessageMapper(new ByteArrayFileMapper(directory));
}
}
public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
Assert.notNull(fileNameGenerator, "'fileNameGenerator' must not be null");
MessageMapper<?,?> mapper = this.getMessageMapper();
if (mapper instanceof AbstractFileMapper<?>) {
((AbstractFileMapper<?>) mapper).setFileNameGenerator(fileNameGenerator);
}
}
public void setBackupDirectory(File backupDirectory) {
Assert.notNull(backupDirectory, "'backupDirectory' must not be null");
MessageMapper<?, File> mapper = this.getMessageMapper();
if (mapper != null && (mapper instanceof AbstractFileMapper<?>)) {
((AbstractFileMapper<?>) mapper).setBackupDirectory(backupDirectory);
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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.AbstractTargetAdapter;
import org.springframework.integration.message.MessageMapper;
import org.springframework.util.Assert;
/**
* A convenience adapter for writing files. The actual file writing occurs in
* the message mapper ({@link TextFileMapper} or {@link ByteArrayFileMapper}).
*
* @author Mark Fisher
*/
public class FileTargetAdapter extends AbstractTargetAdapter<File> {
public FileTargetAdapter(File directory) {
this(directory, true);
}
public FileTargetAdapter(File directory, boolean isTextBased) {
if (isTextBased) {
this.setMessageMapper(new TextFileMapper(directory));
}
else {
this.setMessageMapper(new ByteArrayFileMapper(directory));
}
}
public void setFileNameGenerator(FileNameGenerator fileNameGenerator) {
Assert.notNull(fileNameGenerator, "'fileNameGenerator' must not be null");
MessageMapper<?,?> mapper = this.getMessageMapper();
if (mapper instanceof AbstractFileMapper<?>) {
((AbstractFileMapper<?>) mapper).setFileNameGenerator(fileNameGenerator);
}
}
@Override
protected boolean sendToTarget(File file) {
return file.exists();
}
}

View File

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

View File

@@ -0,0 +1,53 @@
/*
* 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.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.integration.adapter.file.FileSourceAdapter;
/**
* Parser for the &lt;file-source/&gt; element.
*
* @author Mark Fisher
*/
public class FileSourceAdapterParser extends AbstractSingleBeanDefinitionParser {
protected Class<?> getBeanClass(Element element) {
return FileSourceAdapter.class;
}
protected boolean shouldGenerateId() {
return false;
}
protected boolean shouldGenerateIdAsFallback() {
return true;
}
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String directory = element.getAttribute("directory");
String channel = element.getAttribute("channel");
String pollPeriod = element.getAttribute("poll-period");
builder.addConstructorArg(directory);
builder.addConstructorArgReference(channel);
builder.addConstructorArg(pollPeriod);
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.adapter.file.FileTargetAdapter;
import org.springframework.integration.endpoint.DefaultMessageEndpoint;
import org.springframework.integration.scheduling.Subscription;
/**
* Parser for the &lt;file-target/&gt; element.
*
* @author Mark Fisher
*/
public class FileTargetAdapterParser extends AbstractSingleBeanDefinitionParser {
protected Class<?> getBeanClass(Element element) {
return DefaultMessageEndpoint.class;
}
protected boolean shouldGenerateId() {
return false;
}
protected boolean shouldGenerateIdAsFallback() {
return true;
}
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
RootBeanDefinition adapterDef = new RootBeanDefinition(FileTargetAdapter.class);
adapterDef.getConstructorArgumentValues().addGenericArgumentValue(element.getAttribute("directory"));
String adapterBeanName = parserContext.getReaderContext().generateBeanName(adapterDef);
parserContext.registerBeanComponent(new BeanComponentDefinition(adapterDef, adapterBeanName));
builder.addPropertyReference("handler", adapterBeanName);
String channel = element.getAttribute("channel");
Subscription subscription = new Subscription(channel);
builder.addPropertyValue("subscription", subscription);
}
}