KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > suberic > pooka > thread > FolderTracker


1 package net.suberic.pooka.thread;
2 import net.suberic.pooka.FolderInfo;
3 import net.suberic.pooka.Pooka;
4 import net.suberic.util.thread.*;
5 import javax.mail.*;
6 import java.util.*;
7 import java.util.logging.*;
8 import java.awt.event.ActionEvent JavaDoc;
9
10 /**
11  * This class polls the underlying Folder of a FolderInfo in order to make
12  * sure that the UnreadMessageCount is current and to make sure that the
13  * Folder stays open.
14  */

15 public class FolderTracker extends Thread JavaDoc {
16   private Vector mUpdateInfos = new Vector();
17   private CheckFolderAction mAction = new CheckFolderAction();
18   private long mTrackerNextUpdateTime = -1;
19   private boolean mStopped = false;
20   private Logger mLogger = null;
21
22   /**
23    * Stores the information about the Folder to be updated.
24    */

25   private class UpdateInfo {
26     // the Folder for this UpdateInfo
27
FolderInfo folder;
28     // milliseconds between checks
29
long updateCheckMilliseconds;
30     // next time to update.
31
long nextFolderUpdate;
32     // whether or not we're waiting on this to complete.
33
boolean updateRunning = false;
34
35     /**
36      * Creates a new UpdateInfo for FolderInfo <code>info</code>, with
37      * <code>updateCheck</code> milliseconds between checks.
38      */

39     public UpdateInfo(FolderInfo info, long updateCheck) {
40       folder = info;
41       updateCheckMilliseconds = updateCheck;
42       nextFolderUpdate = Calendar.getInstance().getTime().getTime() + updateCheckMilliseconds;
43     }
44
45     /**
46      * Updates the Folder.
47      */

48     public void update() {
49       getLogger().fine("creating update action for folder " + folder.getFolderID());
50       updateRunning = true;
51       folder.getFolderThread().addToQueue(getAction(), new ActionEvent JavaDoc(this, 1, "folder-check - " + folder.getFolderID()), ActionThread.PRIORITY_LOW);
52     }
53
54     /**
55      * Calculates the new next update time.
56      */

57     public void newUpdateTime() {
58       updateRunning = false;
59       nextFolderUpdate = Calendar.getInstance().getTime().getTime() + updateCheckMilliseconds;
60       getLogger().finer("calculating new update time for " + folder.getFolderID() + ": " + nextFolderUpdate);
61       updateTrackerNextTime(nextFolderUpdate);
62     }
63
64     /**
65      * Checks to see if we should run an update now.
66      */

67     public boolean shouldUpdate(long currentTime) {
68       return (! updateRunning && nextFolderUpdate <= currentTime) ;
69     }
70
71     /**
72      * Returns the nextFolderUpdate time for this Info.
73      */

74     public long getNextFolderUpdate() { return nextFolderUpdate; }
75
76     /**
77      * Returns the FolderInfo for this Info.
78      */

79     public FolderInfo getFolderInfo() { return folder; }
80
81     /**
82      * Returns whether or not this is waiting on an outstaning update
83      * action.
84      */

85     public boolean isUpdateRunning() { return updateRunning; }
86
87   } // end UpdateInfo.
88

89
90   /**
91    * This creates a new FolderTracker from a FolderInfo object.
92    */

93   public FolderTracker() {
94     super("Folder Tracker thread");
95     this.setPriority(1);
96   }
97
98   // list management.
99

100   /**
101    * This adds a FolderInfo to the FolderTracker.
102    */

103   public void addFolder(FolderInfo newFolder) {
104     if (newFolder == null)
105       return ;
106
107     getLogger().fine("adding folder " + newFolder.getFolderID());
108     long updateCheckMilliseconds;
109     String JavaDoc updateString = Pooka.getProperty("Pooka.updateCheckMilliseconds", "60000");
110
111     if (newFolder.getParentStore() != null) {
112       updateString = Pooka.getProperty(newFolder.getFolderProperty() + ".updateCheckSeconds", Pooka.getProperty(newFolder.getParentStore().getStoreProperty() + ".updateCheckSeconds", Pooka.getProperty("Pooka.updateCheckSeconds", "300")));
113     }
114     try {
115       updateCheckMilliseconds = Long.parseLong(updateString) *1000;
116     } catch (Exception JavaDoc e) {
117       updateCheckMilliseconds = 60000;
118     }
119
120     UpdateInfo info = new UpdateInfo(newFolder, updateCheckMilliseconds);
121     mUpdateInfos.add(info);
122     updateTrackerNextTime(info.getNextFolderUpdate());
123   }
124
125   /**
126    * This removes a FolderInfo from the FolderTracker.
127    */

128   public void removeFolder(FolderInfo folder) {
129     if (folder == null)
130       return;
131
132     getLogger().fine("removing folder " + folder.getFolderID() + " from tracker.");
133
134     for (int i = 0 ; i < mUpdateInfos.size() ; i++)
135       if (((UpdateInfo) mUpdateInfos.elementAt(i)).folder == folder)
136   mUpdateInfos.removeElementAt(i);
137   }
138
139   // end folder administration
140

141   // next update time administration
142

143   /**
144    * Adds a new update time. This assumes that there's already a
145    * valid update time, and that we're just making sure that the
146    * new time isn't sooner than that.
147    */

148   public synchronized void updateTrackerNextTime(long pTime) {
149     getLogger().finer("updating tracker next time with new value " + pTime + ", old value " + mTrackerNextUpdateTime);
150     if (pTime < mTrackerNextUpdateTime) {
151       mTrackerNextUpdateTime = pTime;
152       getLogger().finer("new time is newer than old time; interrupting thread.");
153       interrupt();
154     }
155   }
156
157   /**
158    * This returns the next update time. This assumes that the old
159    * update time is no longer valid, and that we should recalculate
160    * a new update time.
161    */

162   public synchronized long calculateNextUpdateTime(long currentTime) {
163     getLogger().finer("calculating next update time.");
164
165     long nextTime = -1;
166     Iterator iter = mUpdateInfos.iterator();
167     while (iter.hasNext()) {
168       UpdateInfo current = (UpdateInfo) iter.next();
169       if (! current.isUpdateRunning()) {
170   if (nextTime == -1)
171     nextTime = current.getNextFolderUpdate();
172   else
173     nextTime = Math.min(nextTime, current.getNextFolderUpdate());
174       }
175     }
176
177     if (nextTime == -1)
178       nextTime = currentTime + 120000;
179
180     mTrackerNextUpdateTime = nextTime;
181     getLogger().finer("new next update time: " + mTrackerNextUpdateTime);
182
183     return mTrackerNextUpdateTime;
184   }
185
186   // end update time admin
187

188   // main method(s)
189

190   /**
191    * This runs the thread, running checkFolder() every
192    * updateCheckMilliseconds until the thread is interrupted.
193    */

194   public void run() {
195     while (true && ! mStopped) {
196       try {
197   getLogger().fine("running folder tracker update.");
198
199   long currentTime = Calendar.getInstance().getTime().getTime();
200   updateFolders(currentTime);
201   long sleepTime = calculateNextUpdateTime(currentTime) - currentTime;
202   if (sleepTime > 0) {
203     getLogger().finer("sleeping for " + sleepTime + " milliseconds.");
204
205     sleep(sleepTime);
206   } else {
207     getLogger().finer("sleep time is negative; not sleeping.");
208   }
209       } catch (InterruptedException JavaDoc ie) {
210   // on interrupt, just continue.
211
getLogger().finer("caught InterruptedException.");
212       }
213     }
214
215     getLogger().fine("Stopped. Shutting down Folder Tracker.");
216   }
217
218   /**
219    * Goes through the list of folders and updates the ones that are
220    * due for an update.
221    */

222   public void updateFolders(long currentTime) {
223     for (int i = 0; i < mUpdateInfos.size(); i++) {
224       UpdateInfo info = (UpdateInfo)mUpdateInfos.elementAt(i);
225       if (info.shouldUpdate(currentTime))
226   info.update();
227     }
228   }
229
230   // end main methods
231

232   // thread control
233

234   /**
235    * Singals that the tracker thread should stop.
236    */

237   public void setStopped(boolean pStopped) {
238     mStopped = pStopped;
239     getLogger().fine("setting FolderTracker stopped to " + mStopped);
240     if (mStopped == true)
241       interrupt();
242   }
243
244   // end thread control
245

246   // action section
247

248   /**
249    * This returns the action to run when it's time to update the folder.
250    */

251   public javax.swing.Action JavaDoc getAction() {
252     return mAction;
253   }
254
255   /**
256    * The Action that's put in the queue for checking the folder
257    * status.
258    */

259   public class CheckFolderAction extends javax.swing.AbstractAction JavaDoc {
260     public CheckFolderAction() {
261       super("folder-check");
262     }
263
264     public void actionPerformed(java.awt.event.ActionEvent JavaDoc e) {
265       UpdateInfo info = (UpdateInfo) e.getSource();
266       try {
267   getLogger().fine("running checkFolder on " + info.getFolderInfo().getFolderID());
268   info.getFolderInfo().checkFolder();
269       } catch (MessagingException me) {
270   // ignore; only show if we're debugging.
271
if (getLogger().isLoggable(Level.FINE)) {
272     getLogger().fine("caught exception checking folder " + info.getFolderInfo().getFolderID() + ": " + me);
273     me.printStackTrace();
274   }
275       } finally {
276   info.newUpdateTime();
277       }
278     }
279   }
280
281   // end action section
282

283   // logging
284

285   /**
286    * Gets the Logger for this class.
287    */

288   public Logger getLogger() {
289     if (mLogger == null) {
290       mLogger = java.util.logging.Logger.getLogger("Pooka.debug.folderTracker");
291     }
292
293     return mLogger;
294   }
295 }
296
Popular Tags