DirectoryPoller.java
/*
* DirectoryPoller
*
* $Id$
* $HeadURL$
*/
package gov.usgs.util;
import java.io.File;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;
/**
* Monitor a directory for files, notifying FileListenerInterfaces.
*
* Implementers of the FileListenerInterface should process files before
* returning, because these files may move or disappear.
*/
public class DirectoryPoller {
/** Timer schedules polling frequency. */
private Timer timer;
/** Directory to watch. */
private final File pollDirectory;
/** Directory to store files in. */
private final File storageDirectory;
/** Notification of files. */
private List<FileListenerInterface> listeners = new LinkedList<FileListenerInterface>();
/**
* Create a DirectoryPoller.
*
* @param pollDirectory
* directory that is polled for new files.
* @param storageDirectory
* directory where polled files are moved. When null, polled
* files are deleted after calling listeners.
*/
public DirectoryPoller(final File pollDirectory, final File storageDirectory) {
if (!pollDirectory.exists()) {
pollDirectory.mkdirs();
}
this.pollDirectory = pollDirectory;
if (storageDirectory != null && !storageDirectory.exists()) {
storageDirectory.mkdirs();
}
this.storageDirectory = storageDirectory;
}
/** @return pollDirectory file */
public File getPollDirectory() {
return this.pollDirectory;
}
/** @return storageDirectory file */
public File getStorageDirectory() {
return this.storageDirectory;
}
/** @param listener FileListenerInterface to add */
public void addFileListener(final FileListenerInterface listener) {
listeners.add(listener);
}
/** @param listener FileListenerInterface to remove */
public void removeFileListener(final FileListenerInterface listener) {
listeners.remove(listener);
}
/**
* Start polling in a background thread.
*
* Any previously scheduled polling is stopped before starting at this
* frequency. This schedules using fixed-delay (time between complete polls)
* as opposed to fixed-rate (how often to start polling).
*
* @param frequencyInMilliseconds
* how often to poll.
*/
public void start(final long frequencyInMilliseconds) {
if (timer != null) {
// already started
stop();
}
timer = new Timer();
timer.schedule(new PollTask(), 0L, frequencyInMilliseconds);
}
/**
* Stop any currently scheduled polling.
*/
public void stop() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
/**
* The Polling Task. Notifies all listeners then either deletes or moves the
* file to storage.
*
* @author jmfee
*
*/
protected class PollTask extends TimerTask {
public void run() {
// get files from poll directory
File[] files = pollDirectory.listFiles();
for (File file : files) {
// send file to listeners
notifyListeners(file);
// move file to storage
moveToStorage(file);
}
}
}
/**
* Notify all listeners that files exist and need to be processed.
*
* @param file that needs to be processed
*/
public void notifyListeners(final File file) {
Iterator<FileListenerInterface> iter = new LinkedList<FileListenerInterface>(
listeners).iterator();
while (iter.hasNext()) {
try {
iter.next().onFile(file);
} catch (Exception e) {
// keep notifying other listeners
}
}
}
/**
* Move a file from polldir to storage directory. Attempts to move file into
* storage directory. The file is not moved if no storage directory was
* specified, or if the file no longer exists.
*
* @param file
* file to move.
*/
private void moveToStorage(final File file) {
if (storageDirectory == null) {
// nowhere to move, just delete
file.delete();
return;
}
if (!file.exists()) {
// was already removed, done
return;
}
// build a filename that doesn't exist
String fileName = file.getName();
File storageFile = new File(storageDirectory, fileName);
if (storageFile.exists()) {
fileName = new Date().getTime() + "_" + fileName;
storageFile = new File(storageDirectory, fileName);
}
// rename file
file.renameTo(storageFile);
}
}