KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > mail > Folder


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21
22 /*
23  * @(#)Folder.java 1.57 05/08/29
24  *
25  * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package javax.mail;
29
30 import java.io.*;
31 import java.lang.*;
32 import java.util.Vector JavaDoc;
33 import java.util.StringTokenizer JavaDoc;
34 import javax.mail.search.SearchTerm JavaDoc;
35 import javax.mail.event.*;
36
37 /**
38  * Folder is an abstract class that represents a folder for mail
39  * messages. Subclasses implement protocol specific Folders.<p>
40  *
41  * Folders can contain Messages, other Folders or both, thus providing
42  * a tree-like hierarchy rooted at the Store's default folder. (Note
43  * that some Folder implementations may not allow both Messages and
44  * other Folders in the same Folder).<p>
45  *
46  * The interpretation of folder names is implementation dependent.
47  * The different levels of hierarchy in a folder's full name
48  * are separated from each other by the hierarchy delimiter
49  * character.<p>
50  *
51  * The case-insensitive full folder name (that is, the full name
52  * relative to the default folder for a Store) <strong>INBOX</strong>
53  * is reserved to mean the "primary folder for this user on this
54  * server". Not all Stores will provide an INBOX folder, and not
55  * all users will have an INBOX folder at all times. The name
56  * <strong>INBOX</strong> is reserved to refer to this folder,
57  * when it exists, in Stores that provide it. <p>
58  *
59  * A Folder object obtained from a Store need not actually exist
60  * in the backend store. The <code>exists</code> method tests whether
61  * the folder exists or not. The <code>create</code> method
62  * creates a Folder. <p>
63  *
64  * A Folder is initially in the closed state. Certain methods are valid
65  * in this state; the documentation for those methods note this. A
66  * Folder is opened by calling its 'open' method. All Folder methods,
67  * except <code>open</code>, <code>delete</code> and
68  * <code>renameTo</code>, are valid in this state. <p>
69  *
70  * The only way to get a Folder is by invoking the
71  * <code>getFolder</code> method on Store, Folder, or Session, or by invoking
72  * the <code>list</code> or <code>listSubscribed</code> methods
73  * on Folder. Folder objects returned by the above methods are not
74  * cached by the Store. Thus, invoking the <code>getFolder</code> method
75  * with the same folder name multiple times will return distinct Folder
76  * objects. Likewise for the <code>list</code> and <code>listSubscribed</code>
77  * methods. <p>
78  *
79  * The Message objects within the Folder are cached by the Folder.
80  * Thus, invoking <code>getMessage(msgno)</code> on the same message number
81  * multiple times will return the same Message object, until an
82  * expunge is done on this Folder. <p>
83  *
84  * Note that a Message's message number can change within a
85  * session if the containing Folder is expunged using the expunge
86  * method. Clients that use message numbers as references to messages
87  * should be aware of this and should be prepared to deal with
88  * situation (probably by flushing out existing message number references
89  * and reloading them). Because of this complexity, it is better for
90  * clients to use Message objects as references to messages, rather than
91  * message numbers. Expunged Message objects still have to be
92  * pruned, but other Message objects in that folder are not affected by the
93  * expunge.
94  *
95  * @author John Mani
96  * @author Bill Shannon
97  */

98
99 public abstract class Folder {
100
101     /**
102      * The parent store.
103      */

104     protected Store JavaDoc store;
105
106     /**
107      * The open mode of this folder. The open mode is
108      * <code>Folder.READ_ONLY</code>, <code>Folder.READ_WRITE</code>,
109      * or -1 if not known.
110      * @since JavaMail 1.1
111      */

112     protected int mode = -1;
113
114     /**
115      * Constructor that takes a Store object.
116      *
117      * @param store the Store that holds this folder
118      */

119     protected Folder(Store JavaDoc store) {
120     this.store = store;
121     }
122
123     /**
124      * Returns the name of this Folder. <p>
125      *
126      * This method can be invoked on a closed Folder.
127      *
128      * @return name of the Folder
129      */

130     public abstract String JavaDoc getName();
131
132     /**
133      * Returns the full name of this Folder. If the folder resides under
134      * the root hierarchy of this Store, the returned name is relative
135      * to the root. Otherwise an absolute name, starting with the
136      * hierarchy delimiter, is returned. <p>
137      *
138      * This method can be invoked on a closed Folder.
139      *
140      * @return full name of the Folder
141      */

142     public abstract String JavaDoc getFullName();
143
144     /**
145      * Return a URLName representing this folder. The returned URLName
146      * does <em>not</em> include the password used to access the store.
147      *
148      * @return the URLName representing this folder
149      * @see URLName
150      * @since JavaMail 1.1
151      */

152     public URLName JavaDoc getURLName() throws MessagingException JavaDoc {
153     URLName JavaDoc storeURL = getStore().getURLName();
154     String JavaDoc fullname = getFullName();
155     StringBuffer JavaDoc encodedName = new StringBuffer JavaDoc();
156     char separator = getSeparator();
157
158     if (fullname != null) {
159         /*
160         // We need to encode each of the folder's names.
161         StringTokenizer tok = new StringTokenizer(
162         fullname, new Character(separator).toString(), true);
163
164         while (tok.hasMoreTokens()) {
165         String s = tok.nextToken();
166         if (s.charAt(0) == separator)
167             encodedName.append(separator);
168         else
169             // XXX - should encode, but since there's no decoder...
170             //encodedName.append(java.net.URLEncoder.encode(s));
171             encodedName.append(s);
172         }
173         */

174         // append the whole thing, until we can encode
175
encodedName.append(fullname);
176     }
177
178     /*
179      * Sure would be convenient if URLName had a
180      * constructor that took a base URLName.
181      */

182     return new URLName JavaDoc(storeURL.getProtocol(), storeURL.getHost(),
183                 storeURL.getPort(), encodedName.toString(),
184                 storeURL.getUsername(),
185                 null /* no password */);
186     }
187
188     /**
189      * Returns the Store that owns this Folder object.
190      * This method can be invoked on a closed Folder.
191      * @return the Store
192      */

193     public Store JavaDoc getStore() {
194     return store;
195     }
196
197     /**
198      * Returns the parent folder of this folder.
199      * This method can be invoked on a closed Folder. If this folder
200      * is the top of a folder hierarchy, this method returns null. <p>
201      *
202      * Note that since Folder objects are not cached, invoking this method
203      * returns a new distinct Folder object.
204      *
205      * @return Parent folder
206      */

207     public abstract Folder JavaDoc getParent() throws MessagingException JavaDoc;
208
209     /**
210      * Tests if this folder physically exists on the Store.
211      * This method can be invoked on a closed Folder.
212      *
213      * @return true if the folder exists, otherwise false
214      * @see #create
215      * @exception MessagingException typically if the connection
216      * to the server is lost.
217      */

218     public abstract boolean exists() throws MessagingException JavaDoc;
219
220     /**
221      * Returns a list of Folders belonging to this Folder's namespace
222      * that match the specified pattern. Patterns may contain the wildcard
223      * characters <code>"%"</code>, which matches any character except hierarchy
224      * delimiters, and <code>"*"</code>, which matches any character. <p>
225      *
226      * As an example, given the folder hierarchy: <pre>
227      * Personal/
228      * Finance/
229      * Stocks
230      * Bonus
231      * StockOptions
232      * Jokes
233      * </pre>
234      * <code>list("*")</code> on "Personal" will return the whole
235      * hierarchy. <br>
236      * <code>list("%")</code> on "Personal" will return "Finance" and
237      * "Jokes". <br>
238      * <code>list("Jokes")</code> on "Personal" will return "Jokes".<br>
239      * <code>list("Stock*")</code> on "Finance" will return "Stocks"
240      * and "StockOptions". <p>
241      *
242      * Folder objects are not cached by the Store, so invoking this
243      * method on the same pattern multiple times will return that many
244      * distinct Folder objects. <p>
245      *
246      * This method can be invoked on a closed Folder.
247      *
248      * @param pattern the match pattern
249      * @return array of matching Folder objects. An empty
250      * array is returned if no matching Folders exist.
251      * @see #listSubscribed
252      * @exception FolderNotFoundException if this folder does
253      * not exist.
254      * @exception MessagingException
255      */

256     public abstract Folder JavaDoc[] list(String JavaDoc pattern) throws MessagingException JavaDoc;
257
258     /**
259      * Returns a list of subscribed Folders belonging to this Folder's
260      * namespace that match the specified pattern. If the folder does
261      * not support subscription, this method should resolve to
262      * <code>list</code>.
263      * (The default implementation provided here, does just this).
264      * The pattern can contain wildcards as for <code>list</code>. <p>
265      *
266      * Note that, at a given level of the folder hierarchy, a particular
267      * folder may not be subscribed, but folders underneath that folder
268      * in the folder hierarchy may be subscribed. In order to allow
269      * walking the folder hierarchy, such unsubscribed folders may be
270      * returned, indicating that a folder lower in the hierarchy is
271      * subscribed. The <code>isSubscribed</code> method on a folder will
272      * tell whether any particular folder is actually subscribed. <p>
273      *
274      * Folder objects are not cached by the Store, so invoking this
275      * method on the same pattern multiple times will return that many
276      * distinct Folder objects. <p>
277      *
278      * This method can be invoked on a closed Folder.
279      *
280      * @param pattern the match pattern
281      * @return array of matching subscribed Folder objects. An
282      * empty array is returned if no matching
283      * subscribed folders exist.
284      * @see #list
285      * @exception FolderNotFoundException if this folder does
286      * not exist.
287      * @exception MessagingException
288      */

289     public Folder JavaDoc[] listSubscribed(String JavaDoc pattern) throws MessagingException JavaDoc {
290     return list(pattern);
291     }
292
293     /**
294      * Convenience method that returns the list of folders under this
295      * Folder. This method just calls the <code>list(String pattern)</code>
296      * method with <code>"%"</code> as the match pattern. This method can
297      * be invoked on a closed Folder.
298      *
299      * @return array of Folder objects under this Folder. An
300      * empty array is returned if no subfolders exist.
301      * @see #list
302      * @exception FolderNotFoundException if this folder does
303      * not exist.
304      * @exception MessagingException
305      */

306
307     public Folder JavaDoc[] list() throws MessagingException JavaDoc {
308     return list("%");
309     }
310
311     /**
312      * Convenience method that returns the list of subscribed folders
313      * under this Folder. This method just calls the
314      * <code>listSubscribed(String pattern)</code> method with <code>"%"</code>
315      * as the match pattern. This method can be invoked on a closed Folder.
316      *
317      * @return array of subscribed Folder objects under this
318      * Folder. An empty array is returned if no subscribed
319      * subfolders exist.
320      * @see #listSubscribed
321      * @exception FolderNotFoundException if this folder does
322      * not exist.
323      * @exception MessagingException
324      */

325     public Folder JavaDoc[] listSubscribed() throws MessagingException JavaDoc {
326     return listSubscribed("%");
327     }
328
329     /**
330      * Return the delimiter character that separates this Folder's pathname
331      * from the names of immediate subfolders. This method can be invoked
332      * on a closed Folder.
333      *
334      * @exception FolderNotFoundException if the implementation
335      * requires the folder to exist, but it does not
336      * @return Hierarchy separator character
337      */

338     public abstract char getSeparator() throws MessagingException JavaDoc;
339
340     /**
341      * This folder can contain messages
342      */

343     public final static int HOLDS_MESSAGES = 0x01;
344
345     /**
346      * This folder can contain other folders
347      */

348     public final static int HOLDS_FOLDERS = 0x02;
349
350     /**
351      * Returns the type of this Folder, that is, whether this folder can hold
352      * messages or subfolders or both. The returned value is an integer
353      * bitfield with the appropriate bits set. This method can be invoked
354      * on a closed folder.
355      *
356      * @return integer with appropriate bits set
357      * @exception FolderNotFoundException if this folder does
358      * not exist.
359      * @see #HOLDS_FOLDERS
360      * @see #HOLDS_MESSAGES
361      */

362     public abstract int getType() throws MessagingException JavaDoc;
363
364     /**
365      * Create this folder on the Store. When this folder is created, any
366      * folders in its path that do not exist are also created. <p>
367      *
368      * If the creation is successful, a CREATED FolderEvent is delivered
369      * to any FolderListeners registered on this Folder and this Store.
370      *
371      * @param type The type of this folder.
372      *
373      * @return true if the creation succeeds, else false.
374      * @exception MessagingException
375      * @see #HOLDS_FOLDERS
376      * @see #HOLDS_MESSAGES
377      * @see javax.mail.event.FolderEvent
378      */

379     public abstract boolean create(int type) throws MessagingException JavaDoc;
380
381     /**
382      * Returns true if this Folder is subscribed. <p>
383      *
384      * This method can be invoked on a closed Folder. <p>
385      *
386      * The default implementation provided here just returns true.
387      *
388      * @return true if this Folder is subscribed
389      */

390     public boolean isSubscribed() {
391     return true;
392     }
393
394     /**
395      * Subscribe or unsubscribe this Folder. Not all Stores support
396      * subscription. <p>
397      *
398      * This method can be invoked on a closed Folder. <p>
399      *
400      * The implementation provided here just throws the
401      * MethodNotSupportedException.
402      *
403      * @param subscribe true to subscribe, false to unsubscribe
404      * @exception FolderNotFoundException if this folder does
405      * not exist.
406      * @exception MethodNotSupportedException if this store
407      * does not support subscription
408      * @exception MessagingException
409      */

410     public void setSubscribed(boolean subscribe)
411             throws MessagingException JavaDoc {
412     throw new MethodNotSupportedException JavaDoc();
413     }
414
415     /**
416      * Returns true if this Folder has new messages since the last time
417      * this indication was reset. When this indication is set or reset
418      * depends on the Folder implementation (and in the case of IMAP,
419      * depends on the server). This method can be used to implement
420      * a lightweight "check for new mail" operation on a Folder without
421      * opening it. (For example, a thread that monitors a mailbox and
422      * flags when it has new mail.) This method should indicate whether
423      * any messages in the Folder have the <code>RECENT</code> flag set. <p>
424      *
425      * Note that this is not an incremental check for new mail, i.e.,
426      * it cannot be used to determine whether any new messages have
427      * arrived since the last time this method was invoked. To
428      * implement incremental checks, the Folder needs to be opened. <p>
429      *
430      * This method can be invoked on a closed Folder that can contain
431      * Messages.
432      *
433      * @return true if the Store has new Messages
434      * @exception FolderNotFoundException if this folder does
435      * not exist.
436      * @exception MessagingException
437      */

438     public abstract boolean hasNewMessages() throws MessagingException JavaDoc;
439
440     /**
441      * Return the Folder object corresponding to the given name. Note that
442      * this folder does not physically have to exist in the Store. The
443      * <code>exists()</code> method on a Folder indicates whether it really
444      * exists on the Store. <p>
445      *
446      * In some Stores, name can be an absolute path if it starts with the
447      * hierarchy delimiter. Otherwise, it is interpreted relative to
448      * this Folder. <p>
449      *
450      * Folder objects are not cached by the Store, so invoking this
451      * method on the same name multiple times will return that many
452      * distinct Folder objects. <p>
453      *
454      * This method can be invoked on a closed Folder.
455      *
456      * @param name name of the Folder
457      * @return Folder object
458      * @exception MessagingException
459      */

460     public abstract Folder JavaDoc getFolder(String JavaDoc name)
461                 throws MessagingException JavaDoc;
462
463     /**
464      * Delete this Folder. This method will succeed only on a closed
465      * Folder. <p>
466      *
467      * The <code>recurse</code> flag controls whether the deletion affects
468      * subfolders or not. If true, all subfolders are deleted, then this
469      * folder itself is deleted. If false, the behaviour is dependent on
470      * the folder type and is elaborated below: <p>
471      *
472      * <ul>
473      * <li>
474      * The folder can contain only messages: (type == HOLDS_MESSAGES).
475      * <br>
476      * All messages within the folder are removed. The folder
477      * itself is then removed. An appropriate FolderEvent is generated by
478      * the Store and this folder. <p>
479      *
480      * <li>
481      * The folder can contain only subfolders: (type == HOLDS_FOLDERS).
482      * <br>
483      * If this folder is empty (does not contain any
484      * subfolders at all), it is removed. An appropriate FolderEvent is
485      * generated by the Store and this folder.<br>
486      * If this folder contains any subfolders, the delete fails
487      * and returns false. <p>
488      *
489      * <li>
490      * The folder can contain subfolders as well as messages: <br>
491      * If the folder is empty (no messages or subfolders), it
492      * is removed. If the folder contains no subfolders, but only messages,
493      * then all messages are removed. The folder itself is then removed.
494      * In both the above cases, an appropriate FolderEvent is
495      * generated by the Store and this folder. <p>
496      *
497      * If the folder contains subfolders there are 3 possible
498      * choices an implementation is free to do: <p>
499      *
500      * <ol>
501      * <li> The operation fails, irrespective of whether this folder
502      * contains messages or not. Some implementations might elect to go
503      * with this simple approach. The delete() method returns false.
504      *
505      * <li> Any messages within the folder are removed. Subfolders
506      * are not removed. The folder itself is not removed or affected
507      * in any manner. The delete() method returns true. And the
508      * exists() method on this folder will return true indicating that
509      * this folder still exists. <br>
510      * An appropriate FolderEvent is generated by the Store and this folder.
511      *
512      * <li> Any messages within the folder are removed. Subfolders are
513      * not removed. The folder itself changes its type from
514      * HOLDS_FOLDERS | HOLDS_MESSAGES to HOLDS_FOLDERS. Thus new
515      * messages cannot be added to this folder, but new subfolders can
516      * be created underneath. The delete() method returns true indicating
517      * success. The exists() method on this folder will return true
518      * indicating that this folder still exists. <br>
519      * An appropriate FolderEvent is generated by the Store and this folder.
520      * </ol>
521      * </ul>
522      *
523      * @return true if the Folder is deleted successfully
524      * @exception FolderNotFoundException if this folder does
525      * not exist
526      * @exception IllegalStateException if this folder is not in
527      * the closed state.
528      * @exception MessagingException
529      * @see javax.mail.event.FolderEvent
530      */

531     public abstract boolean delete(boolean recurse)
532                 throws MessagingException JavaDoc;
533
534     /**
535      * Rename this Folder. This method will succeed only on a closed
536      * Folder. <p>
537      *
538      * If the rename is successful, a RENAMED FolderEvent is delivered
539      * to FolderListeners registered on this folder and its containing
540      * Store.
541      *
542      * @param f a folder representing the new name for this Folder
543      * @return true if the Folder is renamed successfully
544      * @exception FolderNotFoundException if this folder does
545      * not exist
546      * @exception IllegalStateException if this folder is not in
547      * the closed state.
548      * @exception MessagingException
549      * @see javax.mail.event.FolderEvent
550      */

551     public abstract boolean renameTo(Folder JavaDoc f) throws MessagingException JavaDoc;
552
553     /**
554      * The Folder is read only. The state and contents of this
555      * folder cannot be modified.
556      */

557     public static final int READ_ONLY = 1;
558
559     /**
560      * The state and contents of this folder can be modified.
561      */

562     public static final int READ_WRITE = 2;
563
564     /**
565      * Open this Folder. This method is valid only on Folders that
566      * can contain Messages and that are closed. <p>
567      *
568      * If this folder is opened successfully, an OPENED ConnectionEvent
569      * is delivered to any ConnectionListeners registered on this
570      * Folder. <p>
571      *
572      * The effect of opening multiple connections to the same folder
573      * on a specifc Store is implementation dependent. Some implementations
574      * allow multiple readers, but only one writer. Others allow
575      * multiple writers as well as readers.
576      *
577      * @param mode open the Folder READ_ONLY or READ_WRITE
578      * @exception FolderNotFoundException if this folder does
579      * not exist.
580      * @exception IllegalStateException if this folder is not in
581      * the closed state.
582      * @exception MessagingException
583      * @see #READ_ONLY
584      * @see #READ_WRITE
585      * @see #getType()
586      * @see javax.mail.event.ConnectionEvent
587      */

588     public abstract void open(int mode) throws MessagingException JavaDoc;
589
590     /**
591      * Close this Folder. This method is valid only on open Folders. <p>
592      *
593      * A CLOSED ConnectionEvent is delivered to any ConnectionListeners
594      * registered on this Folder. Note that the folder is closed even
595      * if this method terminates abnormally by throwing a
596      * MessagingException.
597      *
598      * @param expunge expunges all deleted messages if this flag is true
599      * @exception IllegalStateException if this folder is not opened
600      * @exception MessagingException
601      * @see javax.mail.event.ConnectionEvent
602      */

603     public abstract void close(boolean expunge) throws MessagingException JavaDoc;
604
605     /**
606      * Indicates whether this Folder is in the 'open' state.
607      * @return true if this Folder is in the 'open' state.
608      */

609     public abstract boolean isOpen();
610
611     /**
612      * Return the open mode of this folder. Returns
613      * <code>Folder.READ_ONLY</code>, <code>Folder.READ_WRITE</code>,
614      * or -1 if the open mode is not known (usually only because an older
615      * <code>Folder</code> provider has not been updated to use this new
616      * method).
617      *
618      * @exception IllegalStateException if this folder is not opened
619      * @return the open mode of this folder
620      * @since JavaMail 1.1
621      */

622     public int getMode() {
623     if (!isOpen())
624         throw new IllegalStateException JavaDoc("Folder not open");
625     return mode;
626     }
627  
628     /**
629      * Get the permanent flags supported by this Folder. Returns a Flags
630      * object that contains all the flags supported. <p>
631      *
632      * The special flag <code>Flags.USER </code> indicates that this Folder
633      * supports arbitrary user-defined flags. <p>
634      *
635      * The supported permanent flags for a folder may not be available
636      * until the folder is opened.
637      *
638      * @return permanent flags, or null if not known
639      */

640     public abstract Flags JavaDoc getPermanentFlags();
641
642     /**
643      * Get total number of messages in this Folder. <p>
644      *
645      * This method can be invoked on a closed folder. However, note
646      * that for some folder implementations, getting the total message
647      * count can be an expensive operation involving actually opening
648      * the folder. In such cases, a provider can choose not to support
649      * this functionality in the closed state, in which case this method
650      * must return -1. <p>
651      *
652      * Clients invoking this method on a closed folder must be aware
653      * that this is a potentially expensive operation. Clients must
654      * also be prepared to handle a return value of -1 in this case.
655      *
656      * @return total number of messages. -1 may be returned
657      * by certain implementations if this method is
658      * invoked on a closed folder.
659      * @exception FolderNotFoundException if this folder does
660      * not exist.
661      * @exception MessagingException
662      */

663     public abstract int getMessageCount() throws MessagingException JavaDoc;
664
665     /**
666      * Get the number of new messages in this Folder. <p>
667      *
668      * This method can be invoked on a closed folder. However, note
669      * that for some folder implementations, getting the new message
670      * count can be an expensive operation involving actually opening
671      * the folder. In such cases, a provider can choose not to support
672      * this functionality in the closed state, in which case this method
673      * must return -1. <p>
674      *
675      * Clients invoking this method on a closed folder must be aware
676      * that this is a potentially expensive operation. Clients must
677      * also be prepared to handle a return value of -1 in this case. <p>
678      *
679      * This implementation returns -1 if this folder is closed. Else
680      * this implementation gets each Message in the folder using
681      * <code>getMessage(int)</code> and checks whether its
682      * <code>RECENT</code> flag is set. The total number of messages
683      * that have this flag set is returned.
684      *
685      * @return number of new messages. -1 may be returned
686      * by certain implementations if this method is
687      * invoked on a closed folder.
688      * @exception FolderNotFoundException if this folder does
689      * not exist.
690      * @exception MessagingException
691      */

692     public synchronized int getNewMessageCount()
693             throws MessagingException JavaDoc {
694     if (!isOpen())
695         return -1;
696
697     int newmsgs = 0;
698     int total = getMessageCount();
699     for (int i = 1; i <= total; i++) {
700         try {
701         if (getMessage(i).isSet(Flags.Flag.RECENT))
702             newmsgs++;
703         } catch (MessageRemovedException JavaDoc me) {
704         // This is an expunged message, ignore it.
705
continue;
706         }
707     }
708     return newmsgs;
709     }
710
711     /**
712      * Get the total number of unread messages in this Folder. <p>
713      *
714      * This method can be invoked on a closed folder. However, note
715      * that for some folder implementations, getting the unread message
716      * count can be an expensive operation involving actually opening
717      * the folder. In such cases, a provider can choose not to support
718      * this functionality in the closed state, in which case this method
719      * must return -1. <p>
720      *
721      * Clients invoking this method on a closed folder must be aware
722      * that this is a potentially expensive operation. Clients must
723      * also be prepared to handle a return value of -1 in this case. <p>
724      *
725      * This implementation returns -1 if this folder is closed. Else
726      * this implementation gets each Message in the folder using
727      * <code>getMessage(int)</code> and checks whether its
728      * <code>SEEN</code> flag is set. The total number of messages
729      * that do not have this flag set is returned.
730      *
731      * @return total number of unread messages. -1 may be returned
732      * by certain implementations if this method is
733      * invoked on a closed folder.
734      * @exception FolderNotFoundException if this folder does
735      * not exist.
736      * @exception MessagingException
737      */

738     public synchronized int getUnreadMessageCount()
739             throws MessagingException JavaDoc {
740     if (!isOpen())
741         return -1;
742
743     int unread = 0;
744     int total = getMessageCount();
745     for (int i = 1; i <= total; i++) {
746         try {
747         if (!getMessage(i).isSet(Flags.Flag.SEEN))
748             unread++;
749         } catch (MessageRemovedException JavaDoc me) {
750         // This is an expunged message, ignore it.
751
continue;
752         }
753     }
754     return unread;
755     }
756
757     /**
758      * Get the number of deleted messages in this Folder. <p>
759      *
760      * This method can be invoked on a closed folder. However, note
761      * that for some folder implementations, getting the deleted message
762      * count can be an expensive operation involving actually opening
763      * the folder. In such cases, a provider can choose not to support
764      * this functionality in the closed state, in which case this method
765      * must return -1. <p>
766      *
767      * Clients invoking this method on a closed folder must be aware
768      * that this is a potentially expensive operation. Clients must
769      * also be prepared to handle a return value of -1 in this case. <p>
770      *
771      * This implementation returns -1 if this folder is closed. Else
772      * this implementation gets each Message in the folder using
773      * <code>getMessage(int)</code> and checks whether its
774      * <code>DELETED</code> flag is set. The total number of messages
775      * that have this flag set is returned.
776      *
777      * @return number of deleted messages. -1 may be returned
778      * by certain implementations if this method is
779      * invoked on a closed folder.
780      * @exception FolderNotFoundException if this folder does
781      * not exist.
782      * @exception MessagingException
783      * @since JavaMail 1.3
784      */

785     public synchronized int getDeletedMessageCount() throws MessagingException JavaDoc {
786     if (!isOpen())
787         return -1;
788
789     int deleted = 0;
790     int total = getMessageCount();
791     for (int i = 1; i <= total; i++) {
792         try {
793         if (getMessage(i).isSet(Flags.Flag.DELETED))
794             deleted++;
795         } catch (MessageRemovedException JavaDoc me) {
796         // This is an expunged message, ignore it.
797
continue;
798         }
799     }
800     return deleted;
801     }
802
803     /**
804      * Get the Message object corresponding to the given message
805      * number. A Message object's message number is the relative
806      * position of this Message in its Folder. Messages are numbered
807      * starting at 1 through the total number of message in the folder.
808      * Note that the message number for a particular Message can change
809      * during a session if other messages in the Folder are deleted and
810      * the Folder is expunged. <p>
811      *
812      * Message objects are light-weight references to the actual message
813      * that get filled up on demand. Hence Folder implementations are
814      * expected to provide light-weight Message objects. <p>
815      *
816      * Unlike Folder objects, repeated calls to getMessage with the
817      * same message number will return the same Message object, as
818      * long as no messages in this folder have been expunged. <p>
819      *
820      * Since message numbers can change within a session if the folder
821      * is expunged , clients are advised not to use message numbers as
822      * references to messages. Use Message objects instead.
823      *
824      * @param msgnum the message number
825      * @return the Message object
826      * @see #getMessageCount
827      * @see #fetch
828      * @exception FolderNotFoundException if this folder does
829      * not exist.
830      * @exception IllegalStateException if this folder is not opened
831      * @exception IndexOutOfBoundsException if the message number
832      * is out of range.
833      * @exception MessagingException
834      */

835     public abstract Message JavaDoc getMessage(int msgnum)
836                 throws MessagingException JavaDoc;
837
838     /**
839      * Get the Message objects for message numbers ranging from start
840      * through end, both start and end inclusive. Note that message
841      * numbers start at 1, not 0. <p>
842      *
843      * Message objects are light-weight references to the actual message
844      * that get filled up on demand. Hence Folder implementations are
845      * expected to provide light-weight Message objects. <p>
846      *
847      * This implementation uses getMessage(index) to obtain the required
848      * Message objects. Note that the returned array must contain
849      * <code>(end-start+1)</code> Message objects.
850      *
851      * @param start the number of the first message
852      * @param end the number of the last message
853      * @return the Message objects
854      * @see #fetch
855      * @exception FolderNotFoundException if this folder does
856      * not exist.
857      * @exception IllegalStateException if this folder is not opened.
858      * @exception IndexOutOfBoundsException if the start or end
859      * message numbers are out of range.
860      * @exception MessagingException
861      */

862     public synchronized Message JavaDoc[] getMessages(int start, int end)
863             throws MessagingException JavaDoc {
864     Message JavaDoc[] msgs = new Message JavaDoc[end - start +1];
865     for (int i = start; i <= end; i++)
866         msgs[i - start] = getMessage(i);
867     return msgs;
868     }
869
870     /**
871      * Get the Message objects for message numbers specified in
872      * the array. <p>
873      *
874      * Message objects are light-weight references to the actual message
875      * that get filled up on demand. Hence Folder implementations are
876      * expected to provide light-weight Message objects. <p>
877      *
878      * This implementation uses getMessage(index) to obtain the required
879      * Message objects. Note that the returned array must contain
880      * <code>msgnums.length</code> Message objects
881      *
882      * @param msgnums the array of message numbers
883      * @return the array of Message objects.
884      * @see #fetch
885      * @exception FolderNotFoundException if this folder does
886      * not exist.
887      * @exception IllegalStateException if this folder is not opened.
888      * @exception IndexOutOfBoundsException if any message number
889      * in the given array is out of range.
890      * @exception MessagingException
891      */

892     public synchronized Message JavaDoc[] getMessages(int[] msgnums)
893             throws MessagingException JavaDoc {
894     int len = msgnums.length;
895     Message JavaDoc[] msgs = new Message JavaDoc[len];
896     for (int i = 0; i < len; i++)
897         msgs[i] = getMessage(msgnums[i]);
898     return msgs;
899     }
900
901     /**
902      * Get all Message objects from this Folder. Returns an empty array
903      * if the folder is empty.
904      *
905      * Clients can use Message objects (instead of sequence numbers)
906      * as references to the messages within a folder; this method supplies
907      * the Message objects to the client. Folder implementations are
908      * expected to provide light-weight Message objects, which get
909      * filled on demand. <p>
910      *
911      * This implementation invokes <code>getMessageCount()</code> to get
912      * the current message count and then uses <code>getMessage()</code>
913      * to get Message objects from 1 till the message count.
914      *
915      * @return array of Message objects, empty array if folder
916      * is empty.
917      * @see #fetch
918      * @exception FolderNotFoundException if this folder does
919      * not exist.
920      * @exception IllegalStateException if this folder is not opened.
921      * @exception MessagingException
922      */

923     public synchronized Message JavaDoc[] getMessages() throws MessagingException JavaDoc {
924     if (!isOpen()) // otherwise getMessageCount might return -1
925
throw new IllegalStateException JavaDoc("Folder not open");
926     int total = getMessageCount();
927     Message JavaDoc[] msgs = new Message JavaDoc[total];
928     for (int i = 1; i <= total; i++)
929         msgs[i-1] = getMessage(i);
930     return msgs;
931     }
932
933     /**
934      * Append given Messages to this folder. This method can be
935      * invoked on a closed Folder. An appropriate MessageCountEvent
936      * is delivered to any MessageCountListener registered on this
937      * folder when the messages arrive in the folder. <p>
938      *
939      * Folder implementations must not abort this operation if a
940      * Message in the given message array turns out to be an
941      * expunged Message.
942      *
943      * @param msgs array of Messages to be appended
944      * @exception FolderNotFoundException if this folder does
945      * not exist.
946      * @exception MessagingException if the append failed.
947      */

948     public abstract void appendMessages(Message JavaDoc[] msgs)
949                 throws MessagingException JavaDoc;
950
951     /**
952      * Prefetch the items specified in the FetchProfile for the
953      * given Messages. <p>
954      *
955      * Clients use this method to indicate that the specified items are
956      * needed en-masse for the given message range. Implementations are
957      * expected to retrieve these items for the given message range in
958      * a efficient manner. Note that this method is just a hint to the
959      * implementation to prefetch the desired items. <p>
960      *
961      * An example is a client filling its header-view window with
962      * the Subject, From and X-mailer headers for all messages in the
963      * folder.<p>
964      * <blockquote><pre>
965      *
966      * Message[] msgs = folder.getMessages();
967      *
968      * FetchProfile fp = new FetchProfile();
969      * fp.add(FetchProfile.Item.ENVELOPE);
970      * fp.add("X-mailer");
971      * folder.fetch(msgs, fp);
972      *
973      * for (int i = 0; i < folder.getMessageCount(); i++) {
974      * display(msg[i].getFrom());
975      * display(msg[i].getSubject());
976      * display(msg[i].getHeader("X-mailer"));
977      * }
978      *
979      * </pre></blockquote><p>
980      *
981      * The implementation provided here just returns without
982      * doing anything useful. Providers wanting to provide a real
983      * implementation for this method should override this method.
984      *
985      * @param msgs fetch items for these messages
986      * @param fp the FetchProfile
987      * @exception IllegalStateException if this folder is not opened
988      * @exception MessagingException.
989      */

990     public void fetch(Message JavaDoc[] msgs, FetchProfile JavaDoc fp)
991             throws MessagingException JavaDoc {
992     return;
993     }
994
995     /**
996      * Set the specified flags on the messages specified in the array.
997      * This will result in appropriate MessageChangedEvents being
998      * delivered to any MessageChangedListener registered on this
999      * Message's containing folder. <p>
1000     *
1001     * Note that the specified Message objects <strong>must</strong>
1002     * belong to this folder. Certain Folder implementations can
1003     * optimize the operation of setting Flags for a group of messages,
1004     * so clients might want to use this method, rather than invoking
1005     * <code>Message.setFlags</code> for each Message. <p>
1006     *
1007     * This implementation degenerates to invoking <code>setFlags()</code>
1008     * on each Message object. Specific Folder implementations that can
1009     * optimize this case should do so.
1010     * Also, an implementation must not abort the operation if a Message
1011     * in the array turns out to be an expunged Message.
1012     *
1013     * @param msgs the array of message objects
1014     * @param flag Flags object containing the flags to be set
1015     * @param value set the flags to this boolean value
1016     * @exception IllegalStateException if this folder is not opened
1017     * or if it has been opened READ_ONLY.
1018     * @exception MessagingException
1019     * @see Message#setFlags
1020     * @see javax.mail.event.MessageChangedEvent
1021     */

1022    public synchronized void setFlags(Message JavaDoc[] msgs,
1023            Flags JavaDoc flag, boolean value) throws MessagingException JavaDoc {
1024    for (int i = 0; i < msgs.length; i++) {
1025        try {
1026        msgs[i].setFlags(flag, value);
1027        } catch (MessageRemovedException JavaDoc me) {
1028        // This message is expunged, skip
1029
}
1030    }
1031    }
1032
1033    /**
1034     * Set the specified flags on the messages numbered from start
1035     * through end, both start and end inclusive. Note that message
1036     * numbers start at 1, not 0.
1037     * This will result in appropriate MessageChangedEvents being
1038     * delivered to any MessageChangedListener registered on this
1039     * Message's containing folder. <p>
1040     *
1041     * Certain Folder implementations can
1042     * optimize the operation of setting Flags for a group of messages,
1043     * so clients might want to use this method, rather than invoking
1044     * <code>Message.setFlags</code> for each Message. <p>
1045     *
1046     * The default implementation uses <code>getMessage(int)</code> to
1047     * get each <code>Message</code> object and then invokes
1048     * <code>setFlags</code> on that object to set the flags.
1049     * Specific Folder implementations that can optimize this case should do so.
1050     * Also, an implementation must not abort the operation if a message
1051     * number refers to an expunged message.
1052     *
1053     * @param start the number of the first message
1054     * @param end the number of the last message
1055     * @param flag Flags object containing the flags to be set
1056     * @param value set the flags to this boolean value
1057     * @exception IllegalStateException if this folder is not opened
1058     * or if it has been opened READ_ONLY.
1059     * @exception IndexOutOfBoundsException if the start or end
1060     * message numbers are out of range.
1061     * @exception MessagingException
1062     * @see Message#setFlags
1063     * @see javax.mail.event.MessageChangedEvent
1064     */

1065    public synchronized void setFlags(int start, int end,
1066            Flags JavaDoc flag, boolean value) throws MessagingException JavaDoc {
1067    for (int i = start; i <= end; i++) {
1068        try {
1069        Message JavaDoc msg = getMessage(i);
1070        msg.setFlags(flag, value);
1071        } catch (MessageRemovedException JavaDoc me) {
1072        // This message is expunged, skip
1073
}
1074    }
1075    }
1076
1077    /**
1078     * Set the specified flags on the messages whose message numbers
1079     * are in the array.
1080     * This will result in appropriate MessageChangedEvents being
1081     * delivered to any MessageChangedListener registered on this
1082     * Message's containing folder. <p>
1083     *
1084     * Certain Folder implementations can
1085     * optimize the operation of setting Flags for a group of messages,
1086     * so clients might want to use this method, rather than invoking
1087     * <code>Message.setFlags</code> for each Message. <p>
1088     *
1089     * The default implementation uses <code>getMessage(int)</code> to
1090     * get each <code>Message</code> object and then invokes
1091     * <code>setFlags</code> on that object to set the flags.
1092     * Specific Folder implementations that can optimize this case should do so.
1093     * Also, an implementation must not abort the operation if a message
1094     * number refers to an expunged message.
1095     *
1096     * @param msgnums the array of message numbers
1097     * @param flag Flags object containing the flags to be set
1098     * @param value set the flags to this boolean value
1099     * @exception IllegalStateException if this folder is not opened
1100     * or if it has been opened READ_ONLY.
1101     * @exception IndexOutOfBoundsException if any message number
1102     * in the given array is out of range.
1103     * @exception MessagingException
1104     * @see Message#setFlags
1105     * @see javax.mail.event.MessageChangedEvent
1106     */

1107    public synchronized void setFlags(int[] msgnums,
1108            Flags JavaDoc flag, boolean value) throws MessagingException JavaDoc {
1109    for (int i = 0; i < msgnums.length; i++) {
1110        try {
1111        Message JavaDoc msg = getMessage(msgnums[i]);
1112        msg.setFlags(flag, value);
1113        } catch (MessageRemovedException JavaDoc me) {
1114        // This message is expunged, skip
1115
}
1116    }
1117    }
1118
1119    /**
1120     * Copy the specified Messages from this Folder into another
1121     * Folder. This operation appends these Messages to the
1122     * destination Folder. The destination Folder does not have to
1123     * be opened. An appropriate MessageCountEvent
1124     * is delivered to any MessageCountListener registered on the
1125     * destination folder when the messages arrive in the folder. <p>
1126     *
1127     * Note that the specified Message objects <strong>must</strong>
1128     * belong to this folder. Folder implementations might be able
1129     * to optimize this method by doing server-side copies. <p>
1130     *
1131     * This implementation just invokes <code>appendMessages()</code>
1132     * on the destination folder to append the given Messages. Specific
1133     * folder implementations that support server-side copies should
1134     * do so, if the destination folder's Store is the same as this
1135     * folder's Store.
1136     * Also, an implementation must not abort the operation if a
1137     * Message in the array turns out to be an expunged Message.
1138     *
1139     * @param msgs the array of message objects
1140     * @param folder the folder to copy the messages to
1141     * @exception FolderNotFoundException if the destination
1142     * folder does not exist.
1143     * @exception IllegalStateException if this folder is not opened.
1144     * @exception MessagingException
1145     * @see #appendMessages
1146     */

1147    public void copyMessages(Message JavaDoc[] msgs, Folder JavaDoc folder)
1148                throws MessagingException JavaDoc {
1149    if (!folder.exists())
1150        throw new FolderNotFoundException JavaDoc(
1151            folder.getFullName() + " does not exist",
1152            folder);
1153
1154    folder.appendMessages(msgs);
1155    }
1156
1157    /**
1158     * Expunge (permanently remove) messages marked DELETED. Returns an
1159     * array containing the expunged message objects. The
1160     * <code>getMessageNumber</code> method
1161     * on each of these message objects returns that Message's original
1162     * (that is, prior to the expunge) sequence number. A MessageCountEvent
1163     * containing the expunged messages is delivered to any
1164     * MessageCountListeners registered on the folder. <p>
1165     *
1166     * Expunge causes the renumbering of Message objects subsequent to
1167     * the expunged messages. Clients that use message numbers as
1168     * references to messages should be aware of this and should be
1169     * prepared to deal with the situation (probably by flushing out
1170     * existing message number caches and reloading them). Because of
1171     * this complexity, it is better for clients to use Message objects
1172     * as references to messages, rather than message numbers. Any
1173     * expunged Messages objects still have to be pruned, but other
1174     * Messages in that folder are not affected by the expunge. <p>
1175     *
1176     * After a message is expunged, only the <code>isExpunged</code> and
1177     * <code>getMessageNumber</code> methods are still valid on the
1178     * corresponding Message object; other methods may throw
1179     * <code>MessageRemovedException</code>
1180     *
1181     * @return array of expunged Message objects
1182     * @exception FolderNotFoundException if this folder does not
1183     * exist
1184     * @exception IllegalStateException if this folder is not opened.
1185     * @exception MessagingException
1186     * @see Message#isExpunged
1187     * @see javax.mail.event.MessageCountEvent
1188     */

1189    public abstract Message JavaDoc[] expunge() throws MessagingException JavaDoc;
1190
1191    /**
1192     * Search this Folder for messages matching the specified
1193     * search criterion. Returns an array containing the matching
1194     * messages . Returns an empty array if no matches were found. <p>
1195     *
1196     * This implementation invokes
1197     * <code>search(term, getMessages())</code>, to apply the search
1198     * over all the messages in this folder. Providers that can implement
1199     * server-side searching might want to override this method to provide
1200     * a more efficient implementation.
1201     *
1202     * @param term the search criterion
1203     * @return array of matching messages
1204     * @exception javax.mail.search.SearchException if the search
1205     * term is too complex for the implementation to handle.
1206     * @exception FolderNotFoundException if this folder does
1207     * not exist.
1208     * @exception IllegalStateException if this folder is not opened.
1209     * @exception MessagingException
1210     * @see javax.mail.search.SearchTerm
1211     */

1212    public Message JavaDoc[] search(SearchTerm JavaDoc term) throws MessagingException JavaDoc {
1213    return search(term, getMessages());
1214    }
1215
1216    /**
1217     * Search the given array of messages for those that match the
1218     * specified search criterion. Returns an array containing the
1219     * matching messages. Returns an empty array if no matches were
1220     * found. <p>
1221     *
1222     * Note that the specified Message objects <strong>must</strong>
1223     * belong to this folder. <p>
1224     *
1225     * This implementation iterates through the given array of messages,
1226     * and applies the search criterion on each message by calling
1227     * its <code>match()</code> method with the given term. The
1228     * messages that succeed in the match are returned. Providers
1229     * that can implement server-side searching might want to override
1230     * this method to provide a more efficient implementation. If the
1231     * search term is too complex or contains user-defined terms that
1232     * cannot be executed on the server, providers may elect to either
1233     * throw a SearchException or degenerate to client-side searching by
1234     * calling <code>super.search()</code> to invoke this implementation.
1235     *
1236     * @param term the search criterion
1237     * @param msgs the messages to be searched
1238     * @return array of matching messages
1239     * @exception javax.mail.search.SearchException if the search
1240     * term is too complex for the implementation to handle.
1241     * @exception IllegalStateException if this folder is not opened
1242     * @exception MessagingException
1243     * @see javax.mail.search.SearchTerm
1244     */

1245    public Message JavaDoc[] search(SearchTerm JavaDoc term, Message JavaDoc[] msgs)
1246                throws MessagingException JavaDoc {
1247    Vector JavaDoc matchedMsgs = new Vector JavaDoc();
1248
1249    // Run thru the given messages
1250
for (int i = 0; i < msgs.length; i++) {
1251        try {
1252        if (msgs[i].match(term)) // matched
1253
matchedMsgs.addElement(msgs[i]); // add it
1254
} catch(MessageRemovedException JavaDoc mrex) { }
1255    }
1256
1257    Message JavaDoc[] m = new Message JavaDoc[matchedMsgs.size()];
1258    matchedMsgs.copyInto(m);
1259    return m;
1260    }
1261
1262    /*
1263     * The set of listeners are stored in Vectors appropriate to their
1264     * type. We mark all listener Vectors as "volatile" because, while
1265     * we initialize them inside this folder's synchronization lock,
1266     * they are accessed (checked for null) in the "notify" methods,
1267     * which can't be synchronized due to lock ordering constraints.
1268     * Since the listener fields (the handles on the Vector objects)
1269     * are only ever set, and are never cleared, we believe this is
1270     * safe. The code that dispatches the notifications will either
1271     * see the null and assume there are no listeners or will see the
1272     * Vector and will process the listeners. There's an inherent race
1273     * between adding a listener and notifying the listeners; the lack
1274     * of synchronization during notification does not make the race
1275     * condition significantly worse. If one thread is setting a
1276     * listener at the "same" time an event is being dispatched, the
1277     * dispatch code might not see the listener right away. The
1278     * dispatch code doesn't have to worry about the Vector handle
1279     * being set to null, and thus using an out-of-date set of
1280     * listeners, because we never set the field to null.
1281     */

1282
1283    // Vector of connection listeners.
1284
private volatile Vector JavaDoc connectionListeners = null;
1285
1286    /**
1287     * Add a listener for Connection events on this Folder. <p>
1288     *
1289     * The implementation provided here adds this listener
1290     * to an internal list of ConnectionListeners.
1291     *
1292     * @param l the Listener for Connection events
1293     * @see javax.mail.event.ConnectionEvent
1294     */

1295    public synchronized void
1296    addConnectionListener(ConnectionListener l) {
1297    if (connectionListeners == null)
1298        connectionListeners = new Vector JavaDoc();
1299    connectionListeners.addElement(l);
1300    }
1301
1302    /**
1303     * Remove a Connection event listener. <p>
1304     *
1305     * The implementation provided here removes this listener
1306     * from the internal list of ConnectionListeners.
1307     *
1308     * @param l the listener
1309     * @see #addConnectionListener
1310     */

1311    public synchronized void
1312    removeConnectionListener(ConnectionListener l) {
1313    if (connectionListeners != null)
1314        connectionListeners.removeElement(l);
1315    }
1316
1317    /**
1318     * Notify all ConnectionListeners. Folder implementations are
1319     * expected to use this method to broadcast connection events. <p>
1320     *
1321     * The provided implementation queues the event into
1322     * an internal event queue. An event dispatcher thread dequeues
1323     * events from the queue and dispatches them to the registered
1324     * ConnectionListeners. Note that the event dispatching occurs
1325     * in a separate thread, thus avoiding potential deadlock problems.
1326     *
1327     * @param type the ConnectionEvent type
1328     * @see javax.mail.event.ConnectionEvent
1329     */

1330    protected void notifyConnectionListeners(int type) {
1331    if (connectionListeners != null) {
1332        ConnectionEvent e = new ConnectionEvent(this, type);
1333        queueEvent(e, connectionListeners);
1334    }
1335
1336    /* Fix for broken JDK1.1.x Garbage collector :
1337     * The 'conservative' GC in JDK1.1.x occasionally fails to
1338     * garbage-collect Threads which are in the wait state.
1339     * This would result in thread (and consequently memory) leaks.
1340     *
1341     * We attempt to fix this by sending a 'terminator' event
1342     * to the queue, after we've sent the CLOSED event. The
1343     * terminator event causes the event-dispatching thread to
1344     * self destruct.
1345     */

1346    if (type == ConnectionEvent.CLOSED)
1347        terminateQueue();
1348    }
1349
1350    // Vector of folder listeners
1351
private volatile Vector JavaDoc folderListeners = null;
1352
1353    /**
1354     * Add a listener for Folder events on this Folder. <p>
1355     *
1356     * The implementation provided here adds this listener
1357     * to an internal list of FolderListeners.
1358     *
1359     * @param l the Listener for Folder events
1360     * @see javax.mail.event.FolderEvent
1361     */

1362    public synchronized void addFolderListener(FolderListener l) {
1363    if (folderListeners == null)
1364        folderListeners = new Vector JavaDoc();
1365    folderListeners.addElement(l);
1366    }
1367
1368    /**
1369     * Remove a Folder event listener. <p>
1370     *
1371     * The implementation provided here removes this listener
1372     * from the internal list of FolderListeners.
1373     *
1374     * @param l the listener
1375     * @see #addFolderListener
1376     */

1377    public synchronized void removeFolderListener(FolderListener l) {
1378    if (folderListeners != null)
1379        folderListeners.removeElement(l);
1380    }
1381
1382    /**
1383     * Notify all FolderListeners registered on this Folder and
1384     * this folder's Store. Folder implementations are expected
1385     * to use this method to broadcast Folder events. <p>
1386     *
1387     * The implementation provided here queues the event into
1388     * an internal event queue. An event dispatcher thread dequeues
1389     * events from the queue and dispatches them to the
1390     * FolderListeners registered on this folder. The implementation
1391     * also invokes <code>notifyFolderListeners</code> on this folder's
1392     * Store to notify any FolderListeners registered on the store.
1393     *
1394     * @param type type of FolderEvent
1395     * @see #notifyFolderRenamedListeners
1396     */

1397    protected void notifyFolderListeners(int type) {
1398    if (folderListeners != null) {
1399        FolderEvent e = new FolderEvent(this, this, type);
1400        queueEvent(e, folderListeners);
1401    }
1402    store.notifyFolderListeners(type, this);
1403    }
1404
1405    /**
1406     * Notify all FolderListeners registered on this Folder and
1407     * this folder's Store about the renaming of this folder.
1408     * Folder implementations are expected to use this method to
1409     * broadcast Folder events indicating the renaming of folders. <p>
1410     *
1411     * The implementation provided here queues the event into
1412     * an internal event queue. An event dispatcher thread dequeues
1413     * events from the queue and dispatches them to the
1414     * FolderListeners registered on this folder. The implementation
1415     * also invokes <code>notifyFolderRenamedListeners</code> on this
1416     * folder's Store to notify any FolderListeners registered on the store.
1417     *
1418     * @param folder Folder representing the new name.
1419     * @see #notifyFolderListeners
1420     * @since JavaMail 1.1
1421     */

1422    protected void notifyFolderRenamedListeners(Folder JavaDoc folder) {
1423    if (folderListeners != null) {
1424        FolderEvent e = new FolderEvent(this, this, folder,
1425                        FolderEvent.RENAMED);
1426        queueEvent(e, folderListeners);
1427    }
1428    store.notifyFolderRenamedListeners(this, folder);
1429    }
1430
1431    // Vector of MessageCount listeners
1432
private volatile Vector JavaDoc messageCountListeners = null;
1433
1434    /**
1435     * Add a listener for MessageCount events on this Folder. <p>
1436     *
1437     * The implementation provided here adds this listener
1438     * to an internal list of MessageCountListeners.
1439     *
1440     * @param l the Listener for MessageCount events
1441     * @see javax.mail.event.MessageCountEvent
1442     */

1443    public synchronized void addMessageCountListener(MessageCountListener l) {
1444    if (messageCountListeners == null)
1445        messageCountListeners = new Vector JavaDoc();
1446    messageCountListeners.addElement(l);
1447    }
1448
1449    /**
1450     * Remove a MessageCount listener. <p>
1451     *
1452     * The implementation provided here removes this listener
1453     * from the internal list of MessageCountListeners.
1454     *
1455     * @param l the listener
1456     * @see #addMessageCountListener
1457     */

1458    public synchronized void
1459            removeMessageCountListener(MessageCountListener l) {
1460    if (messageCountListeners != null)
1461        messageCountListeners.removeElement(l);
1462    }
1463
1464    /**
1465     * Notify all MessageCountListeners about the addition of messages
1466     * into this folder. Folder implementations are expected to use this
1467     * method to broadcast MessageCount events for indicating arrival of
1468     * new messages. <p>
1469     *
1470     * The provided implementation queues the event into
1471     * an internal event queue. An event dispatcher thread dequeues
1472     * events from the queue and dispatches them to the registered
1473     * MessageCountListeners. Note that the event dispatching occurs
1474     * in a separate thread, thus avoiding potential deadlock problems.
1475     */

1476    protected void notifyMessageAddedListeners(Message JavaDoc[] msgs) {
1477    if (messageCountListeners == null)
1478        return;
1479
1480    MessageCountEvent e = new MessageCountEvent(
1481                    this,
1482                    MessageCountEvent.ADDED,
1483                    false,
1484                    msgs);
1485
1486    queueEvent(e, messageCountListeners);
1487    }
1488
1489    /**
1490     * Notify all MessageCountListeners about the removal of messages
1491     * from this Folder. Folder implementations are expected to use this
1492     * method to broadcast MessageCount events indicating removal of
1493     * messages. <p>
1494     *
1495     * The provided implementation queues the event into
1496     * an internal event queue. An event dispatcher thread dequeues
1497     * events from the queue and dispatches them to the registered
1498     * MessageCountListeners. Note that the event dispatching occurs
1499     * in a separate thread, thus avoiding potential deadlock problems.
1500     */

1501    protected void notifyMessageRemovedListeners(boolean removed,
1502                         Message JavaDoc[] msgs) {
1503    if (messageCountListeners == null)
1504        return;
1505
1506    MessageCountEvent e = new MessageCountEvent(
1507                    this,
1508                    MessageCountEvent.REMOVED,
1509                    removed,
1510                    msgs);
1511    queueEvent(e, messageCountListeners);
1512    }
1513
1514    // Vector of MessageChanged listeners.
1515
private volatile Vector JavaDoc messageChangedListeners = null;
1516
1517    /**
1518     * Add a listener for MessageChanged events on this Folder. <p>
1519     *
1520     * The implementation provided here adds this listener
1521     * to an internal list of MessageChangedListeners.
1522     *
1523     * @param l the Listener for MessageChanged events
1524     * @see javax.mail.event.MessageChangedEvent
1525     */

1526    public synchronized void
1527            addMessageChangedListener(MessageChangedListener l) {
1528    if (messageChangedListeners == null)
1529        messageChangedListeners = new Vector JavaDoc();
1530    messageChangedListeners.addElement(l);
1531    }
1532
1533    /**
1534     * Remove a MessageChanged listener. <p>
1535     *
1536     * The implementation provided here removes this listener
1537     * from the internal list of MessageChangedListeners.
1538     *
1539     * @param l the listener
1540     * @see #addMessageChangedListener
1541     */

1542    public synchronized void
1543        removeMessageChangedListener(MessageChangedListener l) {
1544    if (messageChangedListeners != null)
1545        messageChangedListeners.removeElement(l);
1546    }
1547
1548    /**
1549     * Notify all MessageChangedListeners. Folder implementations are
1550     * expected to use this method to broadcast MessageChanged events. <p>
1551     *
1552     * The provided implementation queues the event into
1553     * an internal event queue. An event dispatcher thread dequeues
1554     * events from the queue and dispatches them to registered
1555     * MessageChangedListeners. Note that the event dispatching occurs
1556     * in a separate thread, thus avoiding potential deadlock problems.
1557     */

1558    protected void notifyMessageChangedListeners(int type, Message JavaDoc msg) {
1559    if (messageChangedListeners == null)
1560        return;
1561    
1562    MessageChangedEvent e = new MessageChangedEvent(this, type, msg);
1563    queueEvent(e, messageChangedListeners);
1564    }
1565
1566    /*
1567     * The queue of events to be delivered.
1568     */

1569    private EventQueue JavaDoc q;
1570
1571    /*
1572     * A lock for creating the EventQueue object. Only one thread should
1573     * create an EventQueue for this folder. We can't synchronize on the
1574     * folder's lock because that would violate the locking hierarchy in
1575     * some cases. For details, see the IMAP provider.
1576     */

1577    private Object JavaDoc qLock = new Object JavaDoc();
1578
1579    /*
1580     * Add the event and vector of listeners to the queue to be delivered.
1581     */

1582    private void queueEvent(MailEvent event, Vector JavaDoc vector) {
1583    // synchronize creation of the event queue
1584
synchronized (qLock) {
1585        if (q == null)
1586        q = new EventQueue JavaDoc();
1587    }
1588
1589    /*
1590         * Copy the vector in order to freeze the state of the set
1591         * of EventListeners the event should be delivered to prior
1592         * to delivery. This ensures that any changes made to the
1593         * Vector from a target listener's method during the delivery
1594         * of this event will not take effect until after the event is
1595         * delivered.
1596         */

1597    Vector JavaDoc v = (Vector JavaDoc)vector.clone();
1598    q.enqueue(event, v);
1599    }
1600
1601    static class TerminatorEvent extends MailEvent {
1602    private static final long serialVersionUID = 3765761925441296565L;
1603
1604    TerminatorEvent() {
1605        super(new Object JavaDoc());
1606    }
1607
1608    public void dispatch(Object JavaDoc listener) {
1609        // Kill the event dispatching thread.
1610
Thread.currentThread().interrupt();
1611    }
1612    }
1613
1614    // Dispatch the terminator
1615
private void terminateQueue() {
1616    synchronized (qLock) {
1617        if (q != null) {
1618        Vector JavaDoc dummyListeners = new Vector JavaDoc();
1619        dummyListeners.setSize(1); // need atleast one listener
1620
q.enqueue(new TerminatorEvent(), dummyListeners);
1621        q = null;
1622        }
1623    }
1624    }
1625
1626    protected void finalize() throws Throwable JavaDoc {
1627    super.finalize();
1628    terminateQueue();
1629    }
1630
1631    /**
1632     * override the default toString(), it will return the String
1633     * from Folder.getFullName() or if that is null, it will use
1634     * the default toString() behavior.
1635     */

1636
1637    public String JavaDoc toString() {
1638    String JavaDoc s = getFullName();
1639    if (s != null)
1640        return s;
1641    else
1642        return super.toString();
1643    }
1644}
1645
Popular Tags