Package net.suberic.pooka.thread

Source Code of net.suberic.pooka.thread.FolderTracker

package net.suberic.pooka.thread;
import net.suberic.pooka.FolderInfo;
import net.suberic.pooka.OperationCancelledException;
import net.suberic.pooka.Pooka;
import net.suberic.util.thread.*;
import javax.mail.*;
import java.util.*;
import java.util.logging.*;
import java.awt.event.ActionEvent;

/**
* This class polls the underlying Folder of a FolderInfo in order to make
* sure that the UnreadMessageCount is current and to make sure that the
* Folder stays open.
*/
public class FolderTracker extends Thread {
  private Vector mUpdateInfos = new Vector();
  private CheckFolderAction mAction = new CheckFolderAction();
  private long mTrackerNextUpdateTime = -1;
  private boolean mStopped = false;
  private Logger mLogger = null;

  /**
   * Stores the information about the Folder to be updated.
   */
  private class UpdateInfo {
    // the Folder for this UpdateInfo
    FolderInfo folder;
    // milliseconds between checks
    long updateCheckMilliseconds;
    // next time to update.
    long nextFolderUpdate;
    // whether or not we're waiting on this to complete.
    boolean updateRunning = false;

    /**
     * Creates a new UpdateInfo for FolderInfo <code>info</code>, with
     * <code>updateCheck</code> milliseconds between checks.
     */
    public UpdateInfo(FolderInfo info, long updateCheck) {
      folder = info;
      updateCheckMilliseconds = updateCheck;
      nextFolderUpdate = Calendar.getInstance().getTime().getTime() + updateCheckMilliseconds;
    }

    /**
     * Updates the Folder.
     */
    public void update() {
      getLogger().fine("creating update action for folder " + folder.getFolderID());
      updateRunning = true;
      folder.getFolderThread().addToQueue(getAction(), new ActionEvent(this, 1, "folder-check - " + folder.getFolderID()), ActionThread.PRIORITY_LOW);
    }

    /**
     * Calculates the new next update time.
     */
    public void newUpdateTime() {
      updateRunning = false;
      nextFolderUpdate = Calendar.getInstance().getTime().getTime() + updateCheckMilliseconds;
      getLogger().finer("calculating new update time for " + folder.getFolderID() + ":  " + nextFolderUpdate);
      updateTrackerNextTime(nextFolderUpdate);
    }

    /**
     * Checks to see if we should run an update now.
     */
    public boolean shouldUpdate(long currentTime) {
      return (! updateRunning && nextFolderUpdate <= currentTime) ;
    }

    /**
     * Returns the nextFolderUpdate time for this Info.
     */
    public long getNextFolderUpdate() { return nextFolderUpdate; }

    /**
     * Returns the FolderInfo for this Info.
     */
    public FolderInfo getFolderInfo() { return folder; }

    /**
     * Returns whether or not this is waiting on an outstaning update
     * action.
     */
    public boolean isUpdateRunning() { return updateRunning; }

  } // end UpdateInfo.


  /**
   * This creates a new FolderTracker from a FolderInfo object.
   */
  public FolderTracker() {
    super("Folder Tracker thread");
    this.setPriority(1);
  }

  // list management.

  /**
   * This adds a FolderInfo to the FolderTracker.
   */
  public void addFolder(FolderInfo newFolder) {
    if (newFolder == null)
      return ;

    getLogger().fine("adding folder " + newFolder.getFolderID());
    long updateCheckMilliseconds;
    String updateString = Pooka.getProperty("Pooka.updateCheckMilliseconds", "60000");

    if (newFolder.getParentStore() != null) {
      updateString = Pooka.getProperty(newFolder.getFolderProperty() + ".updateCheckSeconds", Pooka.getProperty(newFolder.getParentStore().getStoreProperty() + ".updateCheckSeconds", Pooka.getProperty("Pooka.updateCheckSeconds", "300")));
    }
    try {
      updateCheckMilliseconds = Long.parseLong(updateString) *1000;
    } catch (Exception e) {
      updateCheckMilliseconds = 60000;
    }

    UpdateInfo info = new UpdateInfo(newFolder, updateCheckMilliseconds);
    mUpdateInfos.add(info);
    updateTrackerNextTime(info.getNextFolderUpdate());
  }

  /**
   * This removes a FolderInfo from the FolderTracker.
   */
  public void removeFolder(FolderInfo folder) {
    if (folder == null)
      return;

    getLogger().fine("removing folder " + folder.getFolderID() + " from tracker.");

    for (int i = 0 ; i < mUpdateInfos.size() ; i++)
      if (((UpdateInfo) mUpdateInfos.elementAt(i)).folder == folder)
        mUpdateInfos.removeElementAt(i);
  }

  // end folder administration

  // next update time administration

  /**
   * Adds a new update time.  This assumes that there's already a
   * valid update time, and that we're just making sure that the
   * new time isn't sooner than that.
   */
  public synchronized void updateTrackerNextTime(long pTime) {
    getLogger().finer("updating tracker next time with new value " + pTime + ", old value " + mTrackerNextUpdateTime);
    if (pTime < mTrackerNextUpdateTime) {
      mTrackerNextUpdateTime = pTime;
      getLogger().finer("new time is newer than old time; interrupting thread.");
      interrupt();
    }
  }

  /**
   * This returns the next update time.  This assumes that the old
   * update time is no longer valid, and that we should recalculate
   * a new update time.
   */
  public synchronized long calculateNextUpdateTime(long currentTime) {
    getLogger().finer("calculating next update time.");

    long nextTime = -1;
    Iterator iter = mUpdateInfos.iterator();
    while (iter.hasNext()) {
      UpdateInfo current = (UpdateInfo) iter.next();
      if (! current.isUpdateRunning()) {
        if (nextTime == -1)
          nextTime = current.getNextFolderUpdate();
        else
          nextTime = Math.min(nextTime, current.getNextFolderUpdate());
      }
    }

    if (nextTime == -1)
      nextTime = currentTime + 120000;

    mTrackerNextUpdateTime = nextTime;
    getLogger().finer("new next update time:  " + mTrackerNextUpdateTime);

    return mTrackerNextUpdateTime;
  }

  // end update time admin

  // main method(s)

  /**
   * This runs the thread, running checkFolder() every
   * updateCheckMilliseconds until the thread is interrupted.
   */
  public void run() {
    while (true && ! mStopped) {
      try {
        getLogger().fine("running folder tracker update.");

        long currentTime = Calendar.getInstance().getTime().getTime();
        updateFolders(currentTime);
        long sleepTime = calculateNextUpdateTime(currentTime) - currentTime;
        if (sleepTime > 0) {
          getLogger().finer("sleeping for " + sleepTime + " milliseconds.");

          sleep(sleepTime);
        } else {
          getLogger().finer("sleep time is negative; not sleeping.");
        }
      } catch (InterruptedException ie) {
        // on interrupt, just continue.
        getLogger().finer("caught InterruptedException.");
      }
    }

    getLogger().fine("Stopped.  Shutting down Folder Tracker.");
  }

  /**
   * Goes through the list of folders and updates the ones that are
   * due for an update.
   */
  public void updateFolders(long currentTime) {
    for (int i = 0; i < mUpdateInfos.size(); i++) {
      UpdateInfo info = (UpdateInfo)mUpdateInfos.elementAt(i);
      if (info.shouldUpdate(currentTime))
        info.update();
    }
  }

  // end main methods

  // thread control

  /**
   * Singals that the tracker thread should stop.
   */
  public void setStopped(boolean pStopped) {
    mStopped = pStopped;
    getLogger().fine("setting FolderTracker stopped to " + mStopped);
    if (mStopped == true)
      interrupt();
  }

  // end thread control

  // action section

  /**
   * This returns the action to run when it's time to update the folder.
   */
  public javax.swing.Action getAction() {
    return mAction;
  }

  /**
   * The Action that's put in the queue for checking the folder
   * status.
   */
  public class CheckFolderAction extends javax.swing.AbstractAction {
    public CheckFolderAction() {
      super("folder-check");
    }

    public void actionPerformed(java.awt.event.ActionEvent e) {
      UpdateInfo info = (UpdateInfo) e.getSource();
      try {
        getLogger().fine("running checkFolder on " + info.getFolderInfo().getFolderID());
        info.getFolderInfo().checkFolder();
      } catch (OperationCancelledException oce) {
      } catch (MessagingException me) {
        // ignore; only show if we're debugging.
        if (getLogger().isLoggable(Level.FINE)) {
          getLogger().fine("caught exception checking folder " + info.getFolderInfo().getFolderID() + ":  " + me);
          me.printStackTrace();
        }
      } finally {
        info.newUpdateTime();
      }
    }
  }

  // end action section

  // logging

  /**
   * Gets the Logger for this class.
   */
  public Logger getLogger() {
    if (mLogger == null) {
      mLogger = java.util.logging.Logger.getLogger("Pooka.debug.folderTracker");
    }

    return mLogger;
  }
}
TOP

Related Classes of net.suberic.pooka.thread.FolderTracker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.