PollableSource now returns a Message rather than an Object from poll(). Now PollableSource implementations may use a MessageMapper, but the "source adapter" no longer does.

This commit is contained in:
Mark Fisher
2008-04-10 21:40:41 +00:00
parent 63680cd570
commit 069e7672e3
24 changed files with 242 additions and 175 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* 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.
@@ -22,6 +22,7 @@ import java.util.List;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.integration.adapter.AbstractSourceAdapter;
import org.springframework.integration.message.GenericMessage;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -49,15 +50,19 @@ public class ApplicationEventSourceAdapter extends AbstractSourceAdapter<Applica
public void onApplicationEvent(ApplicationEvent event) {
if (CollectionUtils.isEmpty(this.eventTypes)) {
this.sendToChannel(event);
this.sendMessage(event);
return;
}
for (Class<? extends ApplicationEvent> eventType : this.eventTypes) {
if (eventType.isAssignableFrom(event.getClass())) {
this.sendToChannel(event);
this.sendMessage(event);
return;
}
}
}
private void sendMessage(ApplicationEvent event) {
this.sendToChannel(new GenericMessage<ApplicationEvent>(event));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* 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.
@@ -77,7 +77,8 @@ public abstract class AbstractFileMapper<T> extends AbstractMessageMapper<T, Fil
if (payload == null) {
return null;
}
Message<T> message = new GenericMessage<T>(this.getIdGenerator().generateId(), payload);
Message<T> message = new GenericMessage<T>(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());

View File

@@ -1,77 +0,0 @@
/*
* 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.FileFilter;
import java.io.FilenameFilter;
import org.springframework.integration.adapter.PollableSource;
import org.springframework.integration.message.MessagingException;
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 File poll() {
File[] files = null;
if (this.fileFilter != null) {
files = this.directory.listFiles(this.fileFilter);
}
else if (this.filenameFilter != null) {
files = this.directory.listFiles(this.filenameFilter);
}
else {
files = this.directory.listFiles();
}
if (files == null) {
throw new MessagingException("Problem occurred while polling for files. " +
"Is '" + directory.getAbsolutePath() + "' a directory?");
}
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
return files[i];
}
}
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* 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.
@@ -17,49 +17,96 @@
package org.springframework.integration.adapter.file;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import org.springframework.integration.adapter.PollableSource;
import org.springframework.integration.adapter.PollingSourceAdapter;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.MessageMapper;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessagingException;
import org.springframework.util.Assert;
/**
* Channel adapter for polling a directory and creating messages from its files.
* A messaging source that polls a directory to retrieve files.
*
* @author Mark Fisher
*/
public class FileSourceAdapter extends PollingSourceAdapter<File> {
public class FileSourceAdapter extends PollingSourceAdapter<Object> implements PollableSource<Object> {
public FileSourceAdapter(File directory, MessageChannel channel, int period) {
this(directory, channel, period, true);
private final File directory;
private volatile boolean textBased = true;
private volatile AbstractFileMapper mapper;
private volatile FileNameGenerator fileNameGenerator;
private volatile FileFilter fileFilter;
private volatile FilenameFilter filenameFilter;
public FileSourceAdapter(File directory) {
Assert.notNull(directory, "directory must not be null");
this.directory = directory;
}
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 boolean isTextBased() {
return this.textBased;
}
public void setTextBased(boolean textBased) {
this.textBased = textBased;
}
public void setFileFilter(FileFilter fileFilter) {
this.fileFilter = fileFilter;
}
public void setFilenameFilter(FilenameFilter filenameFilter) {
this.filenameFilter = filenameFilter;
}
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);
this.fileNameGenerator = fileNameGenerator;
}
@Override
protected void initialize() {
this.setSource(this);
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);
}
}
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);
public Message<Object> poll() {
File[] files = null;
if (this.fileFilter != null) {
files = this.directory.listFiles(this.fileFilter);
}
else if (this.filenameFilter != null) {
files = this.directory.listFiles(this.filenameFilter);
}
else {
files = this.directory.listFiles();
}
if (files == null) {
throw new MessagingException("Problem occurred while polling for files. " +
"Is '" + directory.getAbsolutePath() + "' a directory?");
}
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
return this.mapper.toMessage(files[i]);
}
}
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* 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.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* 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.
@@ -45,9 +45,9 @@ public class FileSourceAdapterParser extends AbstractSingleBeanDefinitionParser
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);
builder.addConstructorArgValue(directory);
builder.addPropertyReference("channel", channel);
builder.addPropertyValue("period", pollPeriod);
}
}

View File

@@ -21,6 +21,9 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Tracks changes in a directory. This implementation is thread-safe as it
* allows to synchronously process a new directory structure.
@@ -30,6 +33,8 @@ import java.util.Map;
*/
public class DirectoryContentManager {
private final Log logger = LogFactory.getLog(this.getClass());
private Map<String, FileInfo> previousSnapshot = new HashMap<String, FileInfo>();
private final Map<String, FileInfo> backlog = new HashMap<String, FileInfo>();
@@ -40,12 +45,18 @@ public class DirectoryContentManager {
while (iter.hasNext()) {
String fileName = iter.next().getKey();
if (!currentSnapshot.containsKey(fileName)) {
if (logger.isDebugEnabled()) {
logger.debug("Removing file '" + fileName + "' from backlog. It no longer exists in remote directory.");
}
iter.remove();
}
}
for (String fileName : currentSnapshot.keySet()) {
if (!this.previousSnapshot.containsKey(fileName)
|| (!this.previousSnapshot.get(fileName).equals(currentSnapshot.get(fileName)))) {
if (logger.isDebugEnabled()) {
logger.debug("Adding new or modified file '" + fileName + "' to backlog.");
}
this.backlog.put(fileName, currentSnapshot.get(fileName));
}
}
@@ -53,7 +64,12 @@ public class DirectoryContentManager {
}
public synchronized void fileProcessed(String fileName) {
this.backlog.remove(fileName);
if (fileName != null) {
if (logger.isDebugEnabled()) {
logger.debug("Removing file '" + fileName + "' from the backlog. It has been processed.");
}
this.backlog.remove(fileName);
}
}
public Map<String, FileInfo> getBacklog() {

View File

@@ -31,7 +31,10 @@ import org.apache.commons.net.ftp.FTPFile;
import org.springframework.integration.adapter.PollableSource;
import org.springframework.integration.adapter.PollingSourceAdapter;
import org.springframework.integration.adapter.file.ByteArrayFileMapper;
import org.springframework.integration.adapter.file.FileNameGenerator;
import org.springframework.integration.adapter.file.TextFileMapper;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageMapper;
import org.springframework.integration.message.MessagingException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -42,7 +45,7 @@ import org.springframework.util.StringUtils;
* @author Marius Bogoevici
* @author Mark Fisher
*/
public class FtpSourceAdapter extends PollingSourceAdapter<File> implements PollableSource<File> {
public class FtpSourceAdapter extends PollingSourceAdapter<Object> implements PollableSource<Object> {
private final static String DEFAULT_HOST = "localhost";
@@ -67,6 +70,8 @@ public class FtpSourceAdapter extends PollingSourceAdapter<File> implements Poll
private volatile boolean textBased = true;
private volatile MessageMapper mapper;
private final DirectoryContentManager directoryContentManager = new DirectoryContentManager();
private final FTPClient client = new FTPClient();
@@ -110,20 +115,26 @@ public class FtpSourceAdapter extends PollingSourceAdapter<File> implements Poll
protected void initialize() {
this.setSource(this);
if (this.isTextBased()) {
this.setMessageMapper(new TextFileMapper(this.localWorkingDirectory));
this.mapper = new TextFileMapper(this.localWorkingDirectory);
}
else {
this.setMessageMapper(new ByteArrayFileMapper(this.localWorkingDirectory));
this.mapper = new ByteArrayFileMapper(this.localWorkingDirectory);
}
}
@Override
protected void onSend(File file) {
this.directoryContentManager.fileProcessed(file.getName());
protected void onSend(Message<Object> 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 final File poll() {
public final Message<Object> poll() {
try {
this.establishConnection();
FTPFile[] fileList = this.client.listFiles();
@@ -146,7 +157,7 @@ public class FtpSourceAdapter extends PollingSourceAdapter<File> implements Poll
FileOutputStream fileOutputStream = new FileOutputStream(file);
this.client.retrieveFile(fileName, fileOutputStream);
fileOutputStream.close();
return file;
return this.mapper.toMessage(file);
}
catch (Exception e) {
try {

View File

@@ -20,6 +20,8 @@ import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import org.springframework.integration.adapter.PollableSource;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.jms.core.JmsTemplate;
/**
@@ -49,8 +51,8 @@ public class JmsPollableSource extends AbstractJmsTemplateBasedAdapter implement
}
public Object poll() {
return this.getJmsTemplate().receiveAndConvert();
public Message<Object> poll() {
return new GenericMessage<Object>(this.getJmsTemplate().receiveAndConvert());
}
}

View File

@@ -21,6 +21,8 @@ import java.io.IOException;
import java.io.InputStream;
import org.springframework.integration.adapter.PollableSource;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessagingException;
/**
@@ -65,7 +67,7 @@ public class ByteStreamSource implements PollableSource<byte[]> {
this.shouldTruncate = shouldTruncate;
}
public byte[] poll() {
public Message<byte[]> poll() {
try {
byte[] bytes;
int bytesRead = 0;
@@ -80,12 +82,12 @@ public class ByteStreamSource implements PollableSource<byte[]> {
return null;
}
if (!this.shouldTruncate) {
return bytes;
return new GenericMessage<byte[]>(bytes);
}
else {
byte[] result = new byte[bytesRead];
System.arraycopy(bytes, 0, result, 0, result.length);
return result;
return new GenericMessage<byte[]>(result);
}
}
catch (IOException e) {

View File

@@ -22,6 +22,7 @@ import java.io.Reader;
import org.springframework.integration.adapter.PollableSource;
import org.springframework.integration.message.MessagingException;
import org.springframework.integration.message.StringMessage;
import org.springframework.util.Assert;
/**
@@ -55,13 +56,14 @@ public class CharacterStreamSource implements PollableSource<String> {
}
public String poll() {
public StringMessage poll() {
try {
synchronized (this.monitor) {
if (!this.reader.ready()) {
return null;
}
return this.reader.readLine();
String line = this.reader.readLine();
return (line != null) ? new StringMessage(line) : null;
}
}
catch (IOException e) {