DirectoryPoller.java

  1. /*
  2.  * DirectoryPoller
  3.  *
  4.  * $Id$
  5.  * $HeadURL$
  6.  */
  7. package gov.usgs.util;

  8. import java.io.File;
  9. import java.util.Date;
  10. import java.util.Iterator;
  11. import java.util.List;
  12. import java.util.LinkedList;
  13. import java.util.Timer;
  14. import java.util.TimerTask;

  15. /**
  16.  * Monitor a directory for files, notifying FileListenerInterfaces.
  17.  *
  18.  * Implementers of the FileListenerInterface should process files before
  19.  * returning, because these files may move or disappear.
  20.  */
  21. public class DirectoryPoller {

  22.     /** Timer schedules polling frequency. */
  23.     private Timer timer;

  24.     /** Directory to watch. */
  25.     private final File pollDirectory;

  26.     /** Directory to store files in. */
  27.     private final File storageDirectory;

  28.     /** Notification of files. */
  29.     private List<FileListenerInterface> listeners = new LinkedList<FileListenerInterface>();

  30.     /**
  31.      * Create a DirectoryPoller.
  32.      *
  33.      * @param pollDirectory
  34.      *            directory that is polled for new files.
  35.      * @param storageDirectory
  36.      *            directory where polled files are moved. When null, polled
  37.      *            files are deleted after calling listeners.
  38.      */
  39.     public DirectoryPoller(final File pollDirectory, final File storageDirectory) {
  40.         if (!pollDirectory.exists()) {
  41.             pollDirectory.mkdirs();
  42.         }
  43.         this.pollDirectory = pollDirectory;

  44.         if (storageDirectory != null && !storageDirectory.exists()) {
  45.             storageDirectory.mkdirs();
  46.         }
  47.         this.storageDirectory = storageDirectory;
  48.     }

  49.     /** @return pollDirectory file */
  50.     public File getPollDirectory() {
  51.         return this.pollDirectory;
  52.     }

  53.     /** @return storageDirectory file */
  54.     public File getStorageDirectory() {
  55.         return this.storageDirectory;
  56.     }

  57.     /** @param listener FileListenerInterface to add */
  58.     public void addFileListener(final FileListenerInterface listener) {
  59.         listeners.add(listener);
  60.     }

  61.     /** @param listener FileListenerInterface to remove */
  62.     public void removeFileListener(final FileListenerInterface listener) {
  63.         listeners.remove(listener);
  64.     }

  65.     /**
  66.      * Start polling in a background thread.
  67.      *
  68.      * Any previously scheduled polling is stopped before starting at this
  69.      * frequency. This schedules using fixed-delay (time between complete polls)
  70.      * as opposed to fixed-rate (how often to start polling).
  71.      *
  72.      * @param frequencyInMilliseconds
  73.      *            how often to poll.
  74.      */
  75.     public void start(final long frequencyInMilliseconds) {
  76.         if (timer != null) {
  77.             // already started
  78.             stop();
  79.         }

  80.         timer = new Timer();
  81.         timer.schedule(new PollTask(), 0L, frequencyInMilliseconds);
  82.     }

  83.     /**
  84.      * Stop any currently scheduled polling.
  85.      */
  86.     public void stop() {
  87.         if (timer != null) {
  88.             timer.cancel();
  89.             timer = null;
  90.         }
  91.     }

  92.     /**
  93.      * The Polling Task. Notifies all listeners then either deletes or moves the
  94.      * file to storage.
  95.      *
  96.      * @author jmfee
  97.      *
  98.      */
  99.     protected class PollTask extends TimerTask {
  100.         public void run() {
  101.             // get files from poll directory
  102.             File[] files = pollDirectory.listFiles();
  103.             for (File file : files) {
  104.                 // send file to listeners
  105.                 notifyListeners(file);
  106.                 // move file to storage
  107.                 moveToStorage(file);
  108.             }
  109.         }
  110.     }

  111.     /**
  112.      * Notify all listeners that files exist and need to be processed.
  113.      *
  114.      * @param file that needs to be processed
  115.      */
  116.     public void notifyListeners(final File file) {
  117.         Iterator<FileListenerInterface> iter = new LinkedList<FileListenerInterface>(
  118.                 listeners).iterator();
  119.         while (iter.hasNext()) {
  120.             try {
  121.                 iter.next().onFile(file);
  122.             } catch (Exception e) {
  123.                 // keep notifying other listeners
  124.             }
  125.         }
  126.     }

  127.     /**
  128.      * Move a file from polldir to storage directory. Attempts to move file into
  129.      * storage directory. The file is not moved if no storage directory was
  130.      * specified, or if the file no longer exists.
  131.      *
  132.      * @param file
  133.      *            file to move.
  134.      */
  135.     private void moveToStorage(final File file) {
  136.         if (storageDirectory == null) {
  137.             // nowhere to move, just delete
  138.             file.delete();
  139.             return;
  140.         }

  141.         if (!file.exists()) {
  142.             // was already removed, done
  143.             return;
  144.         }

  145.         // build a filename that doesn't exist
  146.         String fileName = file.getName();
  147.         File storageFile = new File(storageDirectory, fileName);
  148.         if (storageFile.exists()) {
  149.             fileName = new Date().getTime() + "_" + fileName;
  150.             storageFile = new File(storageDirectory, fileName);
  151.         }
  152.         // rename file
  153.         file.renameTo(storageFile);
  154.     }

  155. }