Skip to content

Package: Folder

Folder

nameinstructionbranchcomplexitylinemethod
Folder(Store)
M: 69 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 20 C: 0
0%
M: 1 C: 0
0%
addConnectionListener(ConnectionListener)
M: 13 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
addFolderListener(FolderListener)
M: 13 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
addMessageChangedListener(MessageChangedListener)
M: 13 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
addMessageCountListener(MessageCountListener)
M: 13 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
close()
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
copyMessages(Message[], Folder)
M: 21 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
fetch(Message[], FetchProfile)
M: 1 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
finalize()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getDeletedMessageCount()
M: 29 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
getMessages()
M: 31 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getMessages(int, int)
M: 24 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getMessages(int[])
M: 23 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
getMode()
M: 11 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getNewMessageCount()
M: 29 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
getStore()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getURLName()
M: 32 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
getUnreadMessageCount()
M: 29 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
isSubscribed()
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
list()
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
listSubscribed()
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
listSubscribed(String)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
notifyConnectionListeners(int)
M: 21 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
notifyFolderListeners(int)
M: 21 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
notifyFolderRenamedListeners(Folder)
M: 22 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
notifyMessageAddedListeners(Message[])
M: 18 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
notifyMessageChangedListeners(int, Message)
M: 17 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
notifyMessageRemovedListeners(boolean, Message[])
M: 18 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
queueEvent(MailEvent, Vector)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
removeConnectionListener(ConnectionListener)
M: 9 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
removeFolderListener(FolderListener)
M: 9 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
removeMessageChangedListener(MessageChangedListener)
M: 9 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
removeMessageCountListener(MessageCountListener)
M: 9 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
search(SearchTerm)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
search(SearchTerm, Message[])
M: 37 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
setFlags(Message[], Flags, boolean)
M: 17 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
setFlags(int, int, Flags, boolean)
M: 18 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
setFlags(int[], Flags, boolean)
M: 21 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
setSubscribed(boolean)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
toString()
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package jakarta.mail;
18:
19: import jakarta.mail.event.ConnectionEvent;
20: import jakarta.mail.event.ConnectionListener;
21: import jakarta.mail.event.FolderEvent;
22: import jakarta.mail.event.FolderListener;
23: import jakarta.mail.event.MailEvent;
24: import jakarta.mail.event.MessageChangedEvent;
25: import jakarta.mail.event.MessageChangedListener;
26: import jakarta.mail.event.MessageCountEvent;
27: import jakarta.mail.event.MessageCountListener;
28: import jakarta.mail.search.SearchTerm;
29:
30: import java.util.ArrayList;
31: import java.util.EventListener;
32: import java.util.List;
33: import java.util.Vector;
34: import java.util.concurrent.Executor;
35:
36: /**
37: * Folder is an abstract class that represents a folder for mail
38: * messages. Subclasses implement protocol specific Folders.<p>
39: *
40: * Folders can contain Messages, other Folders or both, thus providing
41: * a tree-like hierarchy rooted at the Store's default folder. (Note
42: * that some Folder implementations may not allow both Messages and
43: * other Folders in the same Folder).<p>
44: *
45: * The interpretation of folder names is implementation dependent.
46: * The different levels of hierarchy in a folder's full name
47: * are separated from each other by the hierarchy delimiter
48: * character.<p>
49: *
50: * The case-insensitive full folder name (that is, the full name
51: * relative to the default folder for a Store) <strong>INBOX</strong>
52: * is reserved to mean the "primary folder for this user on this
53: * server". Not all Stores will provide an INBOX folder, and not
54: * all users will have an INBOX folder at all times. The name
55: * <strong>INBOX</strong> is reserved to refer to this folder,
56: * when it exists, in Stores that provide it. <p>
57: *
58: * A Folder object obtained from a Store need not actually exist
59: * in the backend store. The <code>exists</code> method tests whether
60: * the folder exists or not. The <code>create</code> method
61: * creates a Folder. <p>
62: *
63: * A Folder is initially in the closed state. Certain methods are valid
64: * in this state; the documentation for those methods note this. A
65: * Folder is opened by calling its 'open' method. All Folder methods,
66: * except <code>open</code>, <code>delete</code> and
67: * <code>renameTo</code>, are valid in this state. <p>
68: *
69: * The only way to get a Folder is by invoking the
70: * <code>getFolder</code> method on Store, Folder, or Session, or by invoking
71: * the <code>list</code> or <code>listSubscribed</code> methods
72: * on Folder. Folder objects returned by the above methods are not
73: * cached by the Store. Thus, invoking the <code>getFolder</code> method
74: * with the same folder name multiple times will return distinct Folder
75: * objects. Likewise for the <code>list</code> and <code>listSubscribed</code>
76: * methods. <p>
77: *
78: * The Message objects within the Folder are cached by the Folder.
79: * Thus, invoking <code>getMessage(msgno)</code> on the same message number
80: * multiple times will return the same Message object, until an
81: * expunge is done on this Folder. <p>
82: *
83: * Message objects from a Folder are only valid while a Folder is open
84: * and should not be accessed after the Folder is closed, even if the
85: * Folder is subsequently reopened. Instead, new Message objects must
86: * be fetched from the Folder after the Folder is reopened. <p>
87: *
88: * Note that a Message's message number can change within a
89: * session if the containing Folder is expunged using the expunge
90: * method. Clients that use message numbers as references to messages
91: * should be aware of this and should be prepared to deal with this
92: * situation (probably by flushing out existing message number references
93: * and reloading them). Because of this complexity, it is better for
94: * clients to use Message objects as references to messages, rather than
95: * message numbers. Expunged Message objects still have to be
96: * pruned, but other Message objects in that folder are not affected by the
97: * expunge.
98: *
99: * @author John Mani
100: * @author Bill Shannon
101: */
102:
103: public abstract class Folder implements AutoCloseable {
104:
105: /**
106: * The parent store.
107: */
108: protected Store store;
109:
110: /**
111: * The open mode of this folder. The open mode is
112: * <code>Folder.READ_ONLY</code>, <code>Folder.READ_WRITE</code>,
113: * or -1 if not known.
114: *
115: * @since JavaMail 1.1
116: */
117: protected int mode = -1;
118:
119: /*
120: * The queue of events to be delivered.
121: */
122: private final EventQueue q;
123:
124: /**
125: * Constructor that takes a Store object.
126: *
127: * @param store the Store that holds this folder
128: */
129: protected Folder(Store store) {
130: this.store = store;
131:
132: // create or choose the appropriate event queue
133: Session session = store.getSession();
134: String scope =
135: session.getProperties().getProperty("mail.event.scope", "folder");
136: Executor executor =
137: (Executor) session.getProperties().get("mail.event.executor");
138:• if (scope.equalsIgnoreCase("application"))
139: q = EventQueue.getApplicationEventQueue(executor);
140:• else if (scope.equalsIgnoreCase("session"))
141: q = session.getEventQueue();
142:• else if (scope.equalsIgnoreCase("store"))
143: q = store.getEventQueue();
144: else // if (scope.equalsIgnoreCase("folder"))
145: q = new EventQueue(executor);
146: }
147:
148: /**
149: * Returns the name of this Folder. <p>
150: *
151: * This method can be invoked on a closed Folder.
152: *
153: * @return name of the Folder
154: */
155: public abstract String getName();
156:
157: /**
158: * Returns the full name of this Folder. If the folder resides under
159: * the root hierarchy of this Store, the returned name is relative
160: * to the root. Otherwise an absolute name, starting with the
161: * hierarchy delimiter, is returned. <p>
162: *
163: * This method can be invoked on a closed Folder.
164: *
165: * @return full name of the Folder
166: */
167: public abstract String getFullName();
168:
169: /**
170: * Return a URLName representing this folder. The returned URLName
171: * does <em>not</em> include the password used to access the store.
172: *
173: * @return the URLName representing this folder
174: * @throws MessagingException for failures
175: * @see URLName
176: * @since JavaMail 1.1
177: */
178: public URLName getURLName() throws MessagingException {
179: URLName storeURL = getStore().getURLName();
180: String fullname = getFullName();
181: StringBuilder encodedName = new StringBuilder();
182:
183:• if (fullname != null) {
184:          /*
185:          // We need to encode each of the folder's names.
186:          char separator = getSeparator();
187:          StringTokenizer tok = new StringTokenizer(
188:                 fullname, new Character(separator).toString(), true);
189:
190:          while (tok.hasMoreTokens()) {
191:                 String s = tok.nextToken();
192:                 if (s.charAt(0) == separator)
193:                  encodedName.append(separator);
194:                 else
195:                  // XXX - should encode, but since there's no decoder...
196:                  //encodedName.append(java.net.URLEncoder.encode(s));
197:                  encodedName.append(s);
198:          }
199:          */
200: // append the whole thing, until we can encode
201: encodedName.append(fullname);
202: }
203:
204: /*
205: * Sure would be convenient if URLName had a
206: * constructor that took a base URLName.
207: */
208: return new URLName(storeURL.getProtocol(), storeURL.getHost(),
209: storeURL.getPort(), encodedName.toString(),
210: storeURL.getUsername(),
211: null /* no password */);
212: }
213:
214: /**
215: * Returns the Store that owns this Folder object.
216: * This method can be invoked on a closed Folder.
217: *
218: * @return the Store
219: */
220: public Store getStore() {
221: return store;
222: }
223:
224: /**
225: * Returns the parent folder of this folder.
226: * This method can be invoked on a closed Folder. If this folder
227: * is the top of a folder hierarchy, this method returns null. <p>
228: *
229: * Note that since Folder objects are not cached, invoking this method
230: * returns a new distinct Folder object.
231: *
232: * @return Parent folder
233: * @throws MessagingException for failures
234: */
235: public abstract Folder getParent() throws MessagingException;
236:
237: /**
238: * Tests if this folder physically exists on the Store.
239: * This method can be invoked on a closed Folder.
240: *
241: * @return true if the folder exists, otherwise false
242: * @throws MessagingException typically if the connection
243: * to the server is lost.
244: * @see #create
245: */
246: public abstract boolean exists() throws MessagingException;
247:
248: /**
249: * Returns a list of Folders belonging to this Folder's namespace
250: * that match the specified pattern. Patterns may contain the wildcard
251: * characters <code>"%"</code>, which matches any character except hierarchy
252: * delimiters, and <code>"*"</code>, which matches any character. <p>
253: *
254: * As an example, given the folder hierarchy: <pre>
255: * Personal/
256: * Finance/
257: * Stocks
258: * Bonus
259: * StockOptions
260: * Jokes
261: * </pre>
262: * <code>list("*")</code> on "Personal" will return the whole
263: * hierarchy. <br>
264: * <code>list("%")</code> on "Personal" will return "Finance" and
265: * "Jokes". <br>
266: * <code>list("Jokes")</code> on "Personal" will return "Jokes".<br>
267: * <code>list("Stock*")</code> on "Finance" will return "Stocks"
268: * and "StockOptions". <p>
269: *
270: * Folder objects are not cached by the Store, so invoking this
271: * method on the same pattern multiple times will return that many
272: * distinct Folder objects. <p>
273: *
274: * This method can be invoked on a closed Folder.
275: *
276: * @param pattern the match pattern
277: * @return array of matching Folder objects. An empty
278: * array is returned if no matching Folders exist.
279: * @throws FolderNotFoundException if this folder does
280: * not exist.
281: * @throws MessagingException for other failures
282: * @see #listSubscribed
283: */
284: public abstract Folder[] list(String pattern) throws MessagingException;
285:
286: /**
287: * Returns a list of subscribed Folders belonging to this Folder's
288: * namespace that match the specified pattern. If the folder does
289: * not support subscription, this method should resolve to
290: * <code>list</code>.
291: * (The default implementation provided here, does just this).
292: * The pattern can contain wildcards as for <code>list</code>. <p>
293: *
294: * Note that, at a given level of the folder hierarchy, a particular
295: * folder may not be subscribed, but folders underneath that folder
296: * in the folder hierarchy may be subscribed. In order to allow
297: * walking the folder hierarchy, such unsubscribed folders may be
298: * returned, indicating that a folder lower in the hierarchy is
299: * subscribed. The <code>isSubscribed</code> method on a folder will
300: * tell whether any particular folder is actually subscribed. <p>
301: *
302: * Folder objects are not cached by the Store, so invoking this
303: * method on the same pattern multiple times will return that many
304: * distinct Folder objects. <p>
305: *
306: * This method can be invoked on a closed Folder.
307: *
308: * @param pattern the match pattern
309: * @return array of matching subscribed Folder objects. An
310: * empty array is returned if no matching
311: * subscribed folders exist.
312: * @throws FolderNotFoundException if this folder does
313: * not exist.
314: * @throws MessagingException for other failures
315: * @see #list
316: */
317: public Folder[] listSubscribed(String pattern) throws MessagingException {
318: return list(pattern);
319: }
320:
321: /**
322: * Convenience method that returns the list of folders under this
323: * Folder. This method just calls the <code>list(String pattern)</code>
324: * method with <code>"%"</code> as the match pattern. This method can
325: * be invoked on a closed Folder.
326: *
327: * @return array of Folder objects under this Folder. An
328: * empty array is returned if no subfolders exist.
329: * @throws FolderNotFoundException if this folder does
330: * not exist.
331: * @throws MessagingException for other failures
332: * @see #list
333: */
334:
335: public Folder[] list() throws MessagingException {
336: return list("%");
337: }
338:
339: /**
340: * Convenience method that returns the list of subscribed folders
341: * under this Folder. This method just calls the
342: * <code>listSubscribed(String pattern)</code> method with <code>"%"</code>
343: * as the match pattern. This method can be invoked on a closed Folder.
344: *
345: * @return array of subscribed Folder objects under this
346: * Folder. An empty array is returned if no subscribed
347: * subfolders exist.
348: * @throws FolderNotFoundException if this folder does
349: * not exist.
350: * @throws MessagingException for other failures
351: * @see #listSubscribed
352: */
353: public Folder[] listSubscribed() throws MessagingException {
354: return listSubscribed("%");
355: }
356:
357: /**
358: * Return the delimiter character that separates this Folder's pathname
359: * from the names of immediate subfolders. This method can be invoked
360: * on a closed Folder.
361: *
362: * @return Hierarchy separator character
363: * @throws FolderNotFoundException if the implementation
364: * requires the folder to exist, but it does not
365: */
366: public abstract char getSeparator() throws MessagingException;
367:
368: /**
369: * This folder can contain messages
370: */
371: public final static int HOLDS_MESSAGES = 0x01;
372:
373: /**
374: * This folder can contain other folders
375: */
376: public final static int HOLDS_FOLDERS = 0x02;
377:
378: /**
379: * Returns the type of this Folder, that is, whether this folder can hold
380: * messages or subfolders or both. The returned value is an integer
381: * bitfield with the appropriate bits set. This method can be invoked
382: * on a closed folder.
383: *
384: * @return integer with appropriate bits set
385: * @throws FolderNotFoundException if this folder does
386: * not exist.
387: * @see #HOLDS_MESSAGES
388: * @see #HOLDS_FOLDERS
389: */
390: public abstract int getType() throws MessagingException;
391:
392: /**
393: * Create this folder on the Store. When this folder is created, any
394: * folders in its path that do not exist are also created. <p>
395: *
396: * If the creation is successful, a CREATED FolderEvent is delivered
397: * to any FolderListeners registered on this Folder and this Store.
398: *
399: * @param type The type of this folder.
400: * @return true if the creation succeeds, else false.
401: * @throws MessagingException for failures
402: * @see #HOLDS_MESSAGES
403: * @see jakarta.mail.event.FolderEvent
404: * @see #HOLDS_FOLDERS
405: */
406: public abstract boolean create(int type) throws MessagingException;
407:
408: /**
409: * Returns true if this Folder is subscribed. <p>
410: *
411: * This method can be invoked on a closed Folder. <p>
412: *
413: * The default implementation provided here just returns true.
414: *
415: * @return true if this Folder is subscribed
416: */
417: public boolean isSubscribed() {
418: return true;
419: }
420:
421: /**
422: * Subscribe or unsubscribe this Folder. Not all Stores support
423: * subscription. <p>
424: *
425: * This method can be invoked on a closed Folder. <p>
426: *
427: * The implementation provided here just throws the
428: * MethodNotSupportedException.
429: *
430: * @param subscribe true to subscribe, false to unsubscribe
431: * @throws FolderNotFoundException if this folder does
432: * not exist.
433: * @throws MethodNotSupportedException if this store
434: * does not support subscription
435: * @throws MessagingException for other failures
436: */
437: public void setSubscribed(boolean subscribe)
438: throws MessagingException {
439: throw new MethodNotSupportedException();
440: }
441:
442: /**
443: * Returns true if this Folder has new messages since the last time
444: * this indication was reset. When this indication is set or reset
445: * depends on the Folder implementation (and in the case of IMAP,
446: * depends on the server). This method can be used to implement
447: * a lightweight "check for new mail" operation on a Folder without
448: * opening it. (For example, a thread that monitors a mailbox and
449: * flags when it has new mail.) This method should indicate whether
450: * any messages in the Folder have the <code>RECENT</code> flag set. <p>
451: *
452: * Note that this is not an incremental check for new mail, i.e.,
453: * it cannot be used to determine whether any new messages have
454: * arrived since the last time this method was invoked. To
455: * implement incremental checks, the Folder needs to be opened. <p>
456: *
457: * This method can be invoked on a closed Folder that can contain
458: * Messages.
459: *
460: * @return true if the Store has new Messages
461: * @throws FolderNotFoundException if this folder does
462: * not exist.
463: * @throws MessagingException for other failures
464: */
465: public abstract boolean hasNewMessages() throws MessagingException;
466:
467: /**
468: * Return the Folder object corresponding to the given name. Note that
469: * this folder does not physically have to exist in the Store. The
470: * <code>exists()</code> method on a Folder indicates whether it really
471: * exists on the Store. <p>
472: *
473: * In some Stores, name can be an absolute path if it starts with the
474: * hierarchy delimiter. Otherwise, it is interpreted relative to
475: * this Folder. <p>
476: *
477: * Folder objects are not cached by the Store, so invoking this
478: * method on the same name multiple times will return that many
479: * distinct Folder objects. <p>
480: *
481: * This method can be invoked on a closed Folder.
482: *
483: * @param name name of the Folder
484: * @return Folder object
485: * @throws MessagingException for failures
486: */
487: public abstract Folder getFolder(String name)
488: throws MessagingException;
489:
490: /**
491: * Delete this Folder. This method will succeed only on a closed
492: * Folder. <p>
493: *
494: * The <code>recurse</code> flag controls whether the deletion affects
495: * subfolders or not. If true, all subfolders are deleted, then this
496: * folder itself is deleted. If false, the behaviour is dependent on
497: * the folder type and is elaborated below:
498: *
499: * <ul>
500: * <li>
501: * The folder can contain only messages: (type == HOLDS_MESSAGES).
502: * <br>
503: * All messages within the folder are removed. The folder
504: * itself is then removed. An appropriate FolderEvent is generated by
505: * the Store and this folder.
506: *
507: * <li>
508: * The folder can contain only subfolders: (type == HOLDS_FOLDERS).
509: * <br>
510: * If this folder is empty (does not contain any
511: * subfolders at all), it is removed. An appropriate FolderEvent is
512: * generated by the Store and this folder.<br>
513: * If this folder contains any subfolders, the delete fails
514: * and returns false.
515: *
516: * <li>
517: * The folder can contain subfolders as well as messages: <br>
518: * If the folder is empty (no messages or subfolders), it
519: * is removed. If the folder contains no subfolders, but only messages,
520: * then all messages are removed. The folder itself is then removed.
521: * In both the above cases, an appropriate FolderEvent is
522: * generated by the Store and this folder. <p>
523: *
524: * If the folder contains subfolders there are 3 possible
525: * choices an implementation is free to do:
526: *
527: * <ol>
528: * <li> The operation fails, irrespective of whether this folder
529: * contains messages or not. Some implementations might elect to go
530: * with this simple approach. The delete() method returns false.
531: *
532: * <li> Any messages within the folder are removed. Subfolders
533: * are not removed. The folder itself is not removed or affected
534: * in any manner. The delete() method returns true. And the
535: * exists() method on this folder will return true indicating that
536: * this folder still exists. <br>
537: * An appropriate FolderEvent is generated by the Store and this folder.
538: *
539: * <li> Any messages within the folder are removed. Subfolders are
540: * not removed. The folder itself changes its type from
541: * HOLDS_FOLDERS | HOLDS_MESSAGES to HOLDS_FOLDERS. Thus new
542: * messages cannot be added to this folder, but new subfolders can
543: * be created underneath. The delete() method returns true indicating
544: * success. The exists() method on this folder will return true
545: * indicating that this folder still exists. <br>
546: * An appropriate FolderEvent is generated by the Store and this folder.
547: * </ol>
548: * </ul>
549: *
550: * @param recurse also delete subfolders?
551: * @return true if the Folder is deleted successfully
552: * @throws FolderNotFoundException if this folder does
553: * not exist
554: * @throws IllegalStateException if this folder is not in
555: * the closed state.
556: * @throws MessagingException for other failures
557: * @see jakarta.mail.event.FolderEvent
558: */
559: public abstract boolean delete(boolean recurse)
560: throws MessagingException;
561:
562: /**
563: * Rename this Folder. This method will succeed only on a closed
564: * Folder. <p>
565: *
566: * If the rename is successful, a RENAMED FolderEvent is delivered
567: * to FolderListeners registered on this folder and its containing
568: * Store.
569: *
570: * @param f a folder representing the new name for this Folder
571: * @return true if the Folder is renamed successfully
572: * @throws FolderNotFoundException if this folder does
573: * not exist
574: * @throws IllegalStateException if this folder is not in
575: * the closed state.
576: * @throws MessagingException for other failures
577: * @see jakarta.mail.event.FolderEvent
578: */
579: public abstract boolean renameTo(Folder f) throws MessagingException;
580:
581: /**
582: * The Folder is read only. The state and contents of this
583: * folder cannot be modified.
584: */
585: public static final int READ_ONLY = 1;
586:
587: /**
588: * The state and contents of this folder can be modified.
589: */
590: public static final int READ_WRITE = 2;
591:
592: /**
593: * Open this Folder. This method is valid only on Folders that
594: * can contain Messages and that are closed. <p>
595: *
596: * If this folder is opened successfully, an OPENED ConnectionEvent
597: * is delivered to any ConnectionListeners registered on this
598: * Folder. <p>
599: *
600: * The effect of opening multiple connections to the same folder
601: * on a specifc Store is implementation dependent. Some implementations
602: * allow multiple readers, but only one writer. Others allow
603: * multiple writers as well as readers.
604: *
605: * @param mode open the Folder READ_ONLY or READ_WRITE
606: * @throws FolderNotFoundException if this folder does
607: * not exist.
608: * @throws IllegalStateException if this folder is not in
609: * the closed state.
610: * @throws MessagingException for other failures
611: * @see #READ_ONLY
612: * @see #READ_WRITE
613: * @see #getType()
614: * @see jakarta.mail.event.ConnectionEvent
615: */
616: public abstract void open(int mode) throws MessagingException;
617:
618: /**
619: * Close this Folder. This method is valid only on open Folders. <p>
620: *
621: * A CLOSED ConnectionEvent is delivered to any ConnectionListeners
622: * registered on this Folder. Note that the folder is closed even
623: * if this method terminates abnormally by throwing a
624: * MessagingException.
625: *
626: * @param expunge expunges all deleted messages if this flag is true
627: * @throws IllegalStateException if this folder is not opened
628: * @throws MessagingException for other failures
629: * @see jakarta.mail.event.ConnectionEvent
630: */
631: public abstract void close(boolean expunge) throws MessagingException;
632:
633: /**
634: * Close this Folder and expunge deleted messages. <p>
635: *
636: * A CLOSED ConnectionEvent is delivered to any ConnectionListeners
637: * registered on this Folder. Note that the folder is closed even
638: * if this method terminates abnormally by throwing a
639: * MessagingException. <p>
640: *
641: * This method supports the {@link java.lang.AutoCloseable AutoCloseable}
642: * interface. <p>
643: *
644: * This implementation calls <code>close(true)</code>.
645: *
646: * @throws IllegalStateException if this folder is not opened
647: * @throws MessagingException for other failures
648: * @see jakarta.mail.event.ConnectionEvent
649: * @since JavaMail 1.6
650: */
651: @Override
652: public void close() throws MessagingException {
653: close(true);
654: }
655:
656: /**
657: * Indicates whether this Folder is in the 'open' state.
658: *
659: * @return true if this Folder is in the 'open' state.
660: */
661: public abstract boolean isOpen();
662:
663: /**
664: * Return the open mode of this folder. Returns
665: * <code>Folder.READ_ONLY</code>, <code>Folder.READ_WRITE</code>,
666: * or -1 if the open mode is not known (usually only because an older
667: * <code>Folder</code> provider has not been updated to use this new
668: * method).
669: *
670: * @return the open mode of this folder
671: * @throws IllegalStateException if this folder is not opened
672: * @since JavaMail 1.1
673: */
674: public synchronized int getMode() {
675:• if (!isOpen())
676: throw new IllegalStateException("Folder not open");
677: return mode;
678: }
679:
680: /**
681: * Get the permanent flags supported by this Folder. Returns a Flags
682: * object that contains all the flags supported. <p>
683: *
684: * The special flag <code>Flags.Flag.USER </code> indicates that this Folder
685: * supports arbitrary user-defined flags. <p>
686: *
687: * The supported permanent flags for a folder may not be available
688: * until the folder is opened.
689: *
690: * @return permanent flags, or null if not known
691: */
692: public abstract Flags getPermanentFlags();
693:
694: /**
695: * Get total number of messages in this Folder. <p>
696: *
697: * This method can be invoked on a closed folder. However, note
698: * that for some folder implementations, getting the total message
699: * count can be an expensive operation involving actually opening
700: * the folder. In such cases, a provider can choose not to support
701: * this functionality in the closed state, in which case this method
702: * must return -1. <p>
703: *
704: * Clients invoking this method on a closed folder must be aware
705: * that this is a potentially expensive operation. Clients must
706: * also be prepared to handle a return value of -1 in this case.
707: *
708: * @return total number of messages. -1 may be returned
709: * by certain implementations if this method is
710: * invoked on a closed folder.
711: * @throws FolderNotFoundException if this folder does
712: * not exist.
713: * @throws MessagingException for other failures
714: */
715: public abstract int getMessageCount() throws MessagingException;
716:
717: /**
718: * Get the number of new messages in this Folder. <p>
719: *
720: * This method can be invoked on a closed folder. However, note
721: * that for some folder implementations, getting the new message
722: * count can be an expensive operation involving actually opening
723: * the folder. In such cases, a provider can choose not to support
724: * this functionality in the closed state, in which case this method
725: * must return -1. <p>
726: *
727: * Clients invoking this method on a closed folder must be aware
728: * that this is a potentially expensive operation. Clients must
729: * also be prepared to handle a return value of -1 in this case. <p>
730: *
731: * This implementation returns -1 if this folder is closed. Else
732: * this implementation gets each Message in the folder using
733: * <code>getMessage(int)</code> and checks whether its
734: * <code>RECENT</code> flag is set. The total number of messages
735: * that have this flag set is returned.
736: *
737: * @return number of new messages. -1 may be returned
738: * by certain implementations if this method is
739: * invoked on a closed folder.
740: * @throws FolderNotFoundException if this folder does
741: * not exist.
742: * @throws MessagingException for other failures
743: */
744: public synchronized int getNewMessageCount()
745: throws MessagingException {
746:• if (!isOpen())
747: return -1;
748:
749: int newmsgs = 0;
750: int total = getMessageCount();
751:• for (int i = 1; i <= total; i++) {
752: try {
753:• if (getMessage(i).isSet(Flags.Flag.RECENT))
754: newmsgs++;
755: } catch (MessageRemovedException me) {
756: // This is an expunged message, ignore it.
757: continue;
758: }
759: }
760: return newmsgs;
761: }
762:
763: /**
764: * Get the total number of unread messages in this Folder. <p>
765: *
766: * This method can be invoked on a closed folder. However, note
767: * that for some folder implementations, getting the unread message
768: * count can be an expensive operation involving actually opening
769: * the folder. In such cases, a provider can choose not to support
770: * this functionality in the closed state, in which case this method
771: * must return -1. <p>
772: *
773: * Clients invoking this method on a closed folder must be aware
774: * that this is a potentially expensive operation. Clients must
775: * also be prepared to handle a return value of -1 in this case. <p>
776: *
777: * This implementation returns -1 if this folder is closed. Else
778: * this implementation gets each Message in the folder using
779: * <code>getMessage(int)</code> and checks whether its
780: * <code>SEEN</code> flag is set. The total number of messages
781: * that do not have this flag set is returned.
782: *
783: * @return total number of unread messages. -1 may be returned
784: * by certain implementations if this method is
785: * invoked on a closed folder.
786: * @throws FolderNotFoundException if this folder does
787: * not exist.
788: * @throws MessagingException for other failures
789: */
790: public synchronized int getUnreadMessageCount()
791: throws MessagingException {
792:• if (!isOpen())
793: return -1;
794:
795: int unread = 0;
796: int total = getMessageCount();
797:• for (int i = 1; i <= total; i++) {
798: try {
799:• if (!getMessage(i).isSet(Flags.Flag.SEEN))
800: unread++;
801: } catch (MessageRemovedException me) {
802: // This is an expunged message, ignore it.
803: continue;
804: }
805: }
806: return unread;
807: }
808:
809: /**
810: * Get the number of deleted messages in this Folder. <p>
811: *
812: * This method can be invoked on a closed folder. However, note
813: * that for some folder implementations, getting the deleted message
814: * count can be an expensive operation involving actually opening
815: * the folder. In such cases, a provider can choose not to support
816: * this functionality in the closed state, in which case this method
817: * must return -1. <p>
818: *
819: * Clients invoking this method on a closed folder must be aware
820: * that this is a potentially expensive operation. Clients must
821: * also be prepared to handle a return value of -1 in this case. <p>
822: *
823: * This implementation returns -1 if this folder is closed. Else
824: * this implementation gets each Message in the folder using
825: * <code>getMessage(int)</code> and checks whether its
826: * <code>DELETED</code> flag is set. The total number of messages
827: * that have this flag set is returned.
828: *
829: * @return number of deleted messages. -1 may be returned
830: * by certain implementations if this method is
831: * invoked on a closed folder.
832: * @throws FolderNotFoundException if this folder does
833: * not exist.
834: * @throws MessagingException for other failures
835: * @since JavaMail 1.3
836: */
837: public synchronized int getDeletedMessageCount() throws MessagingException {
838:• if (!isOpen())
839: return -1;
840:
841: int deleted = 0;
842: int total = getMessageCount();
843:• for (int i = 1; i <= total; i++) {
844: try {
845:• if (getMessage(i).isSet(Flags.Flag.DELETED))
846: deleted++;
847: } catch (MessageRemovedException me) {
848: // This is an expunged message, ignore it.
849: continue;
850: }
851: }
852: return deleted;
853: }
854:
855: /**
856: * Get the Message object corresponding to the given message
857: * number. A Message object's message number is the relative
858: * position of this Message in its Folder. Messages are numbered
859: * starting at 1 through the total number of message in the folder.
860: * Note that the message number for a particular Message can change
861: * during a session if other messages in the Folder are deleted and
862: * the Folder is expunged. <p>
863: *
864: * Message objects are light-weight references to the actual message
865: * that get filled up on demand. Hence Folder implementations are
866: * expected to provide light-weight Message objects. <p>
867: *
868: * Unlike Folder objects, repeated calls to getMessage with the
869: * same message number will return the same Message object, as
870: * long as no messages in this folder have been expunged. <p>
871: *
872: * Since message numbers can change within a session if the folder
873: * is expunged , clients are advised not to use message numbers as
874: * references to messages. Use Message objects instead.
875: *
876: * @param msgnum the message number
877: * @return the Message object
878: * @throws FolderNotFoundException if this folder does
879: * not exist.
880: * @throws IllegalStateException if this folder is not opened
881: * @throws IndexOutOfBoundsException if the message number
882: * is out of range.
883: * @throws MessagingException for other failures
884: * @see #getMessageCount
885: * @see #fetch
886: */
887: public abstract Message getMessage(int msgnum)
888: throws MessagingException;
889:
890: /**
891: * Get the Message objects for message numbers ranging from start
892: * through end, both start and end inclusive. Note that message
893: * numbers start at 1, not 0. <p>
894: *
895: * Message objects are light-weight references to the actual message
896: * that get filled up on demand. Hence Folder implementations are
897: * expected to provide light-weight Message objects. <p>
898: *
899: * This implementation uses getMessage(index) to obtain the required
900: * Message objects. Note that the returned array must contain
901: * <code>(end-start+1)</code> Message objects.
902: *
903: * @param start the number of the first message
904: * @param end the number of the last message
905: * @return the Message objects
906: * @throws FolderNotFoundException if this folder does
907: * not exist.
908: * @throws IllegalStateException if this folder is not opened.
909: * @throws IndexOutOfBoundsException if the start or end
910: * message numbers are out of range.
911: * @throws MessagingException for other failures
912: * @see #fetch
913: */
914: public synchronized Message[] getMessages(int start, int end)
915: throws MessagingException {
916: Message[] msgs = new Message[end - start + 1];
917:• for (int i = start; i <= end; i++)
918: msgs[i - start] = getMessage(i);
919: return msgs;
920: }
921:
922: /**
923: * Get the Message objects for message numbers specified in
924: * the array. <p>
925: *
926: * Message objects are light-weight references to the actual message
927: * that get filled up on demand. Hence Folder implementations are
928: * expected to provide light-weight Message objects. <p>
929: *
930: * This implementation uses getMessage(index) to obtain the required
931: * Message objects. Note that the returned array must contain
932: * <code>msgnums.length</code> Message objects
933: *
934: * @param msgnums the array of message numbers
935: * @return the array of Message objects.
936: * @throws FolderNotFoundException if this folder does
937: * not exist.
938: * @throws IllegalStateException if this folder is not opened.
939: * @throws IndexOutOfBoundsException if any message number
940: * in the given array is out of range.
941: * @throws MessagingException for other failures
942: * @see #fetch
943: */
944: public synchronized Message[] getMessages(int[] msgnums)
945: throws MessagingException {
946: int len = msgnums.length;
947: Message[] msgs = new Message[len];
948:• for (int i = 0; i < len; i++)
949: msgs[i] = getMessage(msgnums[i]);
950: return msgs;
951: }
952:
953: /**
954: * Get all Message objects from this Folder. Returns an empty array
955: * if the folder is empty.
956: *
957: * Clients can use Message objects (instead of sequence numbers)
958: * as references to the messages within a folder; this method supplies
959: * the Message objects to the client. Folder implementations are
960: * expected to provide light-weight Message objects, which get
961: * filled on demand. <p>
962: *
963: * This implementation invokes <code>getMessageCount()</code> to get
964: * the current message count and then uses <code>getMessage()</code>
965: * to get Message objects from 1 till the message count.
966: *
967: * @return array of Message objects, empty array if folder
968: * is empty.
969: * @throws FolderNotFoundException if this folder does
970: * not exist.
971: * @throws IllegalStateException if this folder is not opened.
972: * @throws MessagingException for other failures
973: * @see #fetch
974: */
975: public synchronized Message[] getMessages() throws MessagingException {
976:• if (!isOpen()) // otherwise getMessageCount might return -1
977: throw new IllegalStateException("Folder not open");
978: int total = getMessageCount();
979: Message[] msgs = new Message[total];
980:• for (int i = 1; i <= total; i++)
981: msgs[i - 1] = getMessage(i);
982: return msgs;
983: }
984:
985: /**
986: * Append given Messages to this folder. This method can be
987: * invoked on a closed Folder. An appropriate MessageCountEvent
988: * is delivered to any MessageCountListener registered on this
989: * folder when the messages arrive in the folder. <p>
990: *
991: * Folder implementations must not abort this operation if a
992: * Message in the given message array turns out to be an
993: * expunged Message.
994: *
995: * @param msgs array of Messages to be appended
996: * @throws MessagingException if the append failed.
997: * @throws FolderNotFoundException if this folder does
998: * not exist.
999: */
1000: public abstract void appendMessages(Message[] msgs)
1001: throws MessagingException;
1002:
1003: /**
1004: * Prefetch the items specified in the FetchProfile for the
1005: * given Messages. <p>
1006: *
1007: * Clients use this method to indicate that the specified items are
1008: * needed en-masse for the given message range. Implementations are
1009: * expected to retrieve these items for the given message range in
1010: * a efficient manner. Note that this method is just a hint to the
1011: * implementation to prefetch the desired items. <p>
1012: *
1013: * An example is a client filling its header-view window with
1014: * the Subject, From and X-mailer headers for all messages in the
1015: * folder.
1016: * <blockquote><pre>
1017: *
1018: * Message[] msgs = folder.getMessages();
1019: *
1020: * FetchProfile fp = new FetchProfile();
1021: * fp.add(FetchProfile.Item.ENVELOPE);
1022: * fp.add("X-mailer");
1023: * folder.fetch(msgs, fp);
1024: *
1025: * for (int i = 0; i < folder.getMessageCount(); i++) {
1026: * display(msg[i].getFrom());
1027: * display(msg[i].getSubject());
1028: * display(msg[i].getHeader("X-mailer"));
1029: * }
1030: *
1031: * </pre></blockquote><p>
1032: *
1033: * The implementation provided here just returns without
1034: * doing anything useful. Providers wanting to provide a real
1035: * implementation for this method should override this method.
1036: *
1037: * @param msgs fetch items for these messages
1038: * @param fp the FetchProfile
1039: * @throws IllegalStateException if this folder is not opened
1040: * @throws MessagingException for other failures
1041: */
1042: public void fetch(Message[] msgs, FetchProfile fp)
1043: throws MessagingException {
1044: return;
1045: }
1046:
1047: /**
1048: * Set the specified flags on the messages specified in the array.
1049: * This will result in appropriate MessageChangedEvents being
1050: * delivered to any MessageChangedListener registered on this
1051: * Message's containing folder. <p>
1052: *
1053: * Note that the specified Message objects <strong>must</strong>
1054: * belong to this folder. Certain Folder implementations can
1055: * optimize the operation of setting Flags for a group of messages,
1056: * so clients might want to use this method, rather than invoking
1057: * <code>Message.setFlags</code> for each Message. <p>
1058: *
1059: * This implementation degenerates to invoking <code>setFlags()</code>
1060: * on each Message object. Specific Folder implementations that can
1061: * optimize this case should do so.
1062: * Also, an implementation must not abort the operation if a Message
1063: * in the array turns out to be an expunged Message.
1064: *
1065: * @param msgs the array of message objects
1066: * @param flag Flags object containing the flags to be set
1067: * @param value set the flags to this boolean value
1068: * @throws IllegalStateException if this folder is not opened
1069: * or if it has been opened READ_ONLY.
1070: * @throws MessagingException for other failures
1071: * @see Message#setFlags
1072: * @see jakarta.mail.event.MessageChangedEvent
1073: */
1074: public synchronized void setFlags(Message[] msgs,
1075: Flags flag, boolean value) throws MessagingException {
1076:• for (int i = 0; i < msgs.length; i++) {
1077: try {
1078: msgs[i].setFlags(flag, value);
1079: } catch (MessageRemovedException me) {
1080: // This message is expunged, skip
1081: }
1082: }
1083: }
1084:
1085: /**
1086: * Set the specified flags on the messages numbered from start
1087: * through end, both start and end inclusive. Note that message
1088: * numbers start at 1, not 0.
1089: * This will result in appropriate MessageChangedEvents being
1090: * delivered to any MessageChangedListener registered on this
1091: * Message's containing folder. <p>
1092: *
1093: * Certain Folder implementations can
1094: * optimize the operation of setting Flags for a group of messages,
1095: * so clients might want to use this method, rather than invoking
1096: * <code>Message.setFlags</code> for each Message. <p>
1097: *
1098: * The default implementation uses <code>getMessage(int)</code> to
1099: * get each <code>Message</code> object and then invokes
1100: * <code>setFlags</code> on that object to set the flags.
1101: * Specific Folder implementations that can optimize this case should do so.
1102: * Also, an implementation must not abort the operation if a message
1103: * number refers to an expunged message.
1104: *
1105: * @param start the number of the first message
1106: * @param end the number of the last message
1107: * @param flag Flags object containing the flags to be set
1108: * @param value set the flags to this boolean value
1109: * @throws IllegalStateException if this folder is not opened
1110: * or if it has been opened READ_ONLY.
1111: * @throws IndexOutOfBoundsException if the start or end
1112: * message numbers are out of range.
1113: * @throws MessagingException for other failures
1114: * @see Message#setFlags
1115: * @see jakarta.mail.event.MessageChangedEvent
1116: */
1117: public synchronized void setFlags(int start, int end,
1118: Flags flag, boolean value) throws MessagingException {
1119:• for (int i = start; i <= end; i++) {
1120: try {
1121: Message msg = getMessage(i);
1122: msg.setFlags(flag, value);
1123: } catch (MessageRemovedException me) {
1124: // This message is expunged, skip
1125: }
1126: }
1127: }
1128:
1129: /**
1130: * Set the specified flags on the messages whose message numbers
1131: * are in the array.
1132: * This will result in appropriate MessageChangedEvents being
1133: * delivered to any MessageChangedListener registered on this
1134: * Message's containing folder. <p>
1135: *
1136: * Certain Folder implementations can
1137: * optimize the operation of setting Flags for a group of messages,
1138: * so clients might want to use this method, rather than invoking
1139: * <code>Message.setFlags</code> for each Message. <p>
1140: *
1141: * The default implementation uses <code>getMessage(int)</code> to
1142: * get each <code>Message</code> object and then invokes
1143: * <code>setFlags</code> on that object to set the flags.
1144: * Specific Folder implementations that can optimize this case should do so.
1145: * Also, an implementation must not abort the operation if a message
1146: * number refers to an expunged message.
1147: *
1148: * @param msgnums the array of message numbers
1149: * @param flag Flags object containing the flags to be set
1150: * @param value set the flags to this boolean value
1151: * @throws IllegalStateException if this folder is not opened
1152: * or if it has been opened READ_ONLY.
1153: * @throws IndexOutOfBoundsException if any message number
1154: * in the given array is out of range.
1155: * @throws MessagingException for other failures
1156: * @see Message#setFlags
1157: * @see jakarta.mail.event.MessageChangedEvent
1158: */
1159: public synchronized void setFlags(int[] msgnums,
1160: Flags flag, boolean value) throws MessagingException {
1161:• for (int i = 0; i < msgnums.length; i++) {
1162: try {
1163: Message msg = getMessage(msgnums[i]);
1164: msg.setFlags(flag, value);
1165: } catch (MessageRemovedException me) {
1166: // This message is expunged, skip
1167: }
1168: }
1169: }
1170:
1171: /**
1172: * Copy the specified Messages from this Folder into another
1173: * Folder. This operation appends these Messages to the
1174: * destination Folder. The destination Folder does not have to
1175: * be opened. An appropriate MessageCountEvent
1176: * is delivered to any MessageCountListener registered on the
1177: * destination folder when the messages arrive in the folder. <p>
1178: *
1179: * Note that the specified Message objects <strong>must</strong>
1180: * belong to this folder. Folder implementations might be able
1181: * to optimize this method by doing server-side copies. <p>
1182: *
1183: * This implementation just invokes <code>appendMessages()</code>
1184: * on the destination folder to append the given Messages. Specific
1185: * folder implementations that support server-side copies should
1186: * do so, if the destination folder's Store is the same as this
1187: * folder's Store.
1188: * Also, an implementation must not abort the operation if a
1189: * Message in the array turns out to be an expunged Message.
1190: *
1191: * @param msgs the array of message objects
1192: * @param folder the folder to copy the messages to
1193: * @throws FolderNotFoundException if the destination
1194: * folder does not exist.
1195: * @throws IllegalStateException if this folder is not opened.
1196: * @throws MessagingException for other failures
1197: * @see #appendMessages
1198: */
1199: public void copyMessages(Message[] msgs, Folder folder)
1200: throws MessagingException {
1201:• if (!folder.exists())
1202: throw new FolderNotFoundException(
1203: folder.getFullName() + " does not exist",
1204: folder);
1205:
1206: folder.appendMessages(msgs);
1207: }
1208:
1209: /**
1210: * Expunge (permanently remove) messages marked DELETED. Returns an
1211: * array containing the expunged message objects. The
1212: * <code>getMessageNumber</code> method
1213: * on each of these message objects returns that Message's original
1214: * (that is, prior to the expunge) sequence number. A MessageCountEvent
1215: * containing the expunged messages is delivered to any
1216: * MessageCountListeners registered on the folder. <p>
1217: *
1218: * Expunge causes the renumbering of Message objects subsequent to
1219: * the expunged messages. Clients that use message numbers as
1220: * references to messages should be aware of this and should be
1221: * prepared to deal with the situation (probably by flushing out
1222: * existing message number caches and reloading them). Because of
1223: * this complexity, it is better for clients to use Message objects
1224: * as references to messages, rather than message numbers. Any
1225: * expunged Messages objects still have to be pruned, but other
1226: * Messages in that folder are not affected by the expunge. <p>
1227: *
1228: * After a message is expunged, only the <code>isExpunged</code> and
1229: * <code>getMessageNumber</code> methods are still valid on the
1230: * corresponding Message object; other methods may throw
1231: * <code>MessageRemovedException</code>
1232: *
1233: * @return array of expunged Message objects
1234: * @throws FolderNotFoundException if this folder does not
1235: * exist
1236: * @throws IllegalStateException if this folder is not opened.
1237: * @throws MessagingException for other failures
1238: * @see Message#isExpunged
1239: * @see jakarta.mail.event.MessageCountEvent
1240: */
1241: public abstract Message[] expunge() throws MessagingException;
1242:
1243: /**
1244: * Search this Folder for messages matching the specified
1245: * search criterion. Returns an array containing the matching
1246: * messages . Returns an empty array if no matches were found. <p>
1247: *
1248: * This implementation invokes
1249: * <code>search(term, getMessages())</code>, to apply the search
1250: * over all the messages in this folder. Providers that can implement
1251: * server-side searching might want to override this method to provide
1252: * a more efficient implementation.
1253: *
1254: * @param term the search criterion
1255: * @return array of matching messages
1256: * @throws jakarta.mail.search.SearchException if the search
1257: * term is too complex for the implementation to handle.
1258: * @throws FolderNotFoundException if this folder does
1259: * not exist.
1260: * @throws IllegalStateException if this folder is not opened.
1261: * @throws MessagingException for other failures
1262: * @see jakarta.mail.search.SearchTerm
1263: */
1264: public Message[] search(SearchTerm term) throws MessagingException {
1265: return search(term, getMessages());
1266: }
1267:
1268: /**
1269: * Search the given array of messages for those that match the
1270: * specified search criterion. Returns an array containing the
1271: * matching messages. Returns an empty array if no matches were
1272: * found. <p>
1273: *
1274: * Note that the specified Message objects <strong>must</strong>
1275: * belong to this folder. <p>
1276: *
1277: * This implementation iterates through the given array of messages,
1278: * and applies the search criterion on each message by calling
1279: * its <code>match()</code> method with the given term. The
1280: * messages that succeed in the match are returned. Providers
1281: * that can implement server-side searching might want to override
1282: * this method to provide a more efficient implementation. If the
1283: * search term is too complex or contains user-defined terms that
1284: * cannot be executed on the server, providers may elect to either
1285: * throw a SearchException or degenerate to client-side searching by
1286: * calling <code>super.search()</code> to invoke this implementation.
1287: *
1288: * @param term the search criterion
1289: * @param msgs the messages to be searched
1290: * @return array of matching messages
1291: * @throws jakarta.mail.search.SearchException if the search
1292: * term is too complex for the implementation to handle.
1293: * @throws IllegalStateException if this folder is not opened
1294: * @throws MessagingException for other failures
1295: * @see jakarta.mail.search.SearchTerm
1296: */
1297: public Message[] search(SearchTerm term, Message[] msgs)
1298: throws MessagingException {
1299: List<Message> matchedMsgs = new ArrayList<>();
1300:
1301: // Run thru the given messages
1302:• for (Message msg : msgs) {
1303: try {
1304:• if (msg.match(term)) // matched
1305: matchedMsgs.add(msg); // add it
1306: } catch (MessageRemovedException mrex) {
1307: }
1308: }
1309:
1310: return matchedMsgs.toArray(new Message[matchedMsgs.size()]);
1311: }
1312:
1313: /*
1314: * The set of listeners are stored in Vectors appropriate to their
1315: * type. We mark all listener Vectors as "volatile" because, while
1316: * we initialize them inside this folder's synchronization lock,
1317: * they are accessed (checked for null) in the "notify" methods,
1318: * which can't be synchronized due to lock ordering constraints.
1319: * Since the listener fields (the handles on the Vector objects)
1320: * are only ever set, and are never cleared, we believe this is
1321: * safe. The code that dispatches the notifications will either
1322: * see the null and assume there are no listeners or will see the
1323: * Vector and will process the listeners. There's an inherent race
1324: * between adding a listener and notifying the listeners; the lack
1325: * of synchronization during notification does not make the race
1326: * condition significantly worse. If one thread is setting a
1327: * listener at the "same" time an event is being dispatched, the
1328: * dispatch code might not see the listener right away. The
1329: * dispatch code doesn't have to worry about the Vector handle
1330: * being set to null, and thus using an out-of-date set of
1331: * listeners, because we never set the field to null.
1332: */
1333:
1334: // Vector of connection listeners.
1335: private volatile Vector<ConnectionListener> connectionListeners = null;
1336:
1337: /**
1338: * Add a listener for Connection events on this Folder. <p>
1339: *
1340: * The implementation provided here adds this listener
1341: * to an internal list of ConnectionListeners.
1342: *
1343: * @param l the Listener for Connection events
1344: * @see jakarta.mail.event.ConnectionEvent
1345: */
1346: public synchronized void
1347: addConnectionListener(ConnectionListener l) {
1348:• if (connectionListeners == null)
1349: connectionListeners = new Vector<>();
1350: connectionListeners.addElement(l);
1351: }
1352:
1353: /**
1354: * Remove a Connection event listener. <p>
1355: *
1356: * The implementation provided here removes this listener
1357: * from the internal list of ConnectionListeners.
1358: *
1359: * @param l the listener
1360: * @see #addConnectionListener
1361: */
1362: public synchronized void
1363: removeConnectionListener(ConnectionListener l) {
1364:• if (connectionListeners != null)
1365: connectionListeners.removeElement(l);
1366: }
1367:
1368: /**
1369: * Notify all ConnectionListeners. Folder implementations are
1370: * expected to use this method to broadcast connection events. <p>
1371: *
1372: * The provided implementation queues the event into
1373: * an internal event queue. An event dispatcher thread dequeues
1374: * events from the queue and dispatches them to the registered
1375: * ConnectionListeners. Note that the event dispatching occurs
1376: * in a separate thread, thus avoiding potential deadlock problems.
1377: *
1378: * @param type the ConnectionEvent type
1379: * @see jakarta.mail.event.ConnectionEvent
1380: */
1381: protected void notifyConnectionListeners(int type) {
1382:• if (connectionListeners != null) {
1383: ConnectionEvent e = new ConnectionEvent(this, type);
1384: queueEvent(e, connectionListeners);
1385: }
1386:
1387: /* Fix for broken JDK1.1.x Garbage collector :
1388: * The 'conservative' GC in JDK1.1.x occasionally fails to
1389: * garbage-collect Threads which are in the wait state.
1390: * This would result in thread (and consequently memory) leaks.
1391: *
1392: * We attempt to fix this by sending a 'terminator' event
1393: * to the queue, after we've sent the CLOSED event. The
1394: * terminator event causes the event-dispatching thread to
1395: * self destruct.
1396: */
1397:• if (type == ConnectionEvent.CLOSED)
1398: q.terminateQueue();
1399: }
1400:
1401: // Vector of folder listeners
1402: private volatile Vector<FolderListener> folderListeners = null;
1403:
1404: /**
1405: * Add a listener for Folder events on this Folder. <p>
1406: *
1407: * The implementation provided here adds this listener
1408: * to an internal list of FolderListeners.
1409: *
1410: * @param l the Listener for Folder events
1411: * @see jakarta.mail.event.FolderEvent
1412: */
1413: public synchronized void addFolderListener(FolderListener l) {
1414:• if (folderListeners == null)
1415: folderListeners = new Vector<>();
1416: folderListeners.addElement(l);
1417: }
1418:
1419: /**
1420: * Remove a Folder event listener. <p>
1421: *
1422: * The implementation provided here removes this listener
1423: * from the internal list of FolderListeners.
1424: *
1425: * @param l the listener
1426: * @see #addFolderListener
1427: */
1428: public synchronized void removeFolderListener(FolderListener l) {
1429:• if (folderListeners != null)
1430: folderListeners.removeElement(l);
1431: }
1432:
1433: /**
1434: * Notify all FolderListeners registered on this Folder and
1435: * this folder's Store. Folder implementations are expected
1436: * to use this method to broadcast Folder events. <p>
1437: *
1438: * The implementation provided here queues the event into
1439: * an internal event queue. An event dispatcher thread dequeues
1440: * events from the queue and dispatches them to the
1441: * FolderListeners registered on this folder. The implementation
1442: * also invokes <code>notifyFolderListeners</code> on this folder's
1443: * Store to notify any FolderListeners registered on the store.
1444: *
1445: * @param type type of FolderEvent
1446: * @see #notifyFolderRenamedListeners
1447: */
1448: protected void notifyFolderListeners(int type) {
1449:• if (folderListeners != null) {
1450: FolderEvent e = new FolderEvent(this, this, type);
1451: queueEvent(e, folderListeners);
1452: }
1453: store.notifyFolderListeners(type, this);
1454: }
1455:
1456: /**
1457: * Notify all FolderListeners registered on this Folder and
1458: * this folder's Store about the renaming of this folder.
1459: * Folder implementations are expected to use this method to
1460: * broadcast Folder events indicating the renaming of folders. <p>
1461: *
1462: * The implementation provided here queues the event into
1463: * an internal event queue. An event dispatcher thread dequeues
1464: * events from the queue and dispatches them to the
1465: * FolderListeners registered on this folder. The implementation
1466: * also invokes <code>notifyFolderRenamedListeners</code> on this
1467: * folder's Store to notify any FolderListeners registered on the store.
1468: *
1469: * @param folder Folder representing the new name.
1470: * @see #notifyFolderListeners
1471: * @since JavaMail 1.1
1472: */
1473: protected void notifyFolderRenamedListeners(Folder folder) {
1474:• if (folderListeners != null) {
1475: FolderEvent e = new FolderEvent(this, this, folder,
1476: FolderEvent.RENAMED);
1477: queueEvent(e, folderListeners);
1478: }
1479: store.notifyFolderRenamedListeners(this, folder);
1480: }
1481:
1482: // Vector of MessageCount listeners
1483: private volatile Vector<MessageCountListener> messageCountListeners = null;
1484:
1485: /**
1486: * Add a listener for MessageCount events on this Folder. <p>
1487: *
1488: * The implementation provided here adds this listener
1489: * to an internal list of MessageCountListeners.
1490: *
1491: * @param l the Listener for MessageCount events
1492: * @see jakarta.mail.event.MessageCountEvent
1493: */
1494: public synchronized void addMessageCountListener(MessageCountListener l) {
1495:• if (messageCountListeners == null)
1496: messageCountListeners = new Vector<>();
1497: messageCountListeners.addElement(l);
1498: }
1499:
1500: /**
1501: * Remove a MessageCount listener. <p>
1502: *
1503: * The implementation provided here removes this listener
1504: * from the internal list of MessageCountListeners.
1505: *
1506: * @param l the listener
1507: * @see #addMessageCountListener
1508: */
1509: public synchronized void
1510: removeMessageCountListener(MessageCountListener l) {
1511:• if (messageCountListeners != null)
1512: messageCountListeners.removeElement(l);
1513: }
1514:
1515: /**
1516: * Notify all MessageCountListeners about the addition of messages
1517: * into this folder. Folder implementations are expected to use this
1518: * method to broadcast MessageCount events for indicating arrival of
1519: * new messages. <p>
1520: *
1521: * The provided implementation queues the event into
1522: * an internal event queue. An event dispatcher thread dequeues
1523: * events from the queue and dispatches them to the registered
1524: * MessageCountListeners. Note that the event dispatching occurs
1525: * in a separate thread, thus avoiding potential deadlock problems.
1526: *
1527: * @param msgs the messages that were added
1528: */
1529: protected void notifyMessageAddedListeners(Message[] msgs) {
1530:• if (messageCountListeners == null)
1531: return;
1532:
1533: MessageCountEvent e = new MessageCountEvent(
1534: this,
1535: MessageCountEvent.ADDED,
1536: false,
1537: msgs);
1538:
1539: queueEvent(e, messageCountListeners);
1540: }
1541:
1542: /**
1543: * Notify all MessageCountListeners about the removal of messages
1544: * from this Folder. Folder implementations are expected to use this
1545: * method to broadcast MessageCount events indicating removal of
1546: * messages. <p>
1547: *
1548: * The provided implementation queues the event into
1549: * an internal event queue. An event dispatcher thread dequeues
1550: * events from the queue and dispatches them to the registered
1551: * MessageCountListeners. Note that the event dispatching occurs
1552: * in a separate thread, thus avoiding potential deadlock problems.
1553: *
1554: * @param removed was the message removed by this client?
1555: * @param msgs the messages that were removed
1556: */
1557: protected void notifyMessageRemovedListeners(boolean removed,
1558: Message[] msgs) {
1559:• if (messageCountListeners == null)
1560: return;
1561:
1562: MessageCountEvent e = new MessageCountEvent(
1563: this,
1564: MessageCountEvent.REMOVED,
1565: removed,
1566: msgs);
1567: queueEvent(e, messageCountListeners);
1568: }
1569:
1570: // Vector of MessageChanged listeners.
1571: private volatile Vector<MessageChangedListener> messageChangedListeners
1572: = null;
1573:
1574: /**
1575: * Add a listener for MessageChanged events on this Folder. <p>
1576: *
1577: * The implementation provided here adds this listener
1578: * to an internal list of MessageChangedListeners.
1579: *
1580: * @param l the Listener for MessageChanged events
1581: * @see jakarta.mail.event.MessageChangedEvent
1582: */
1583: public synchronized void
1584: addMessageChangedListener(MessageChangedListener l) {
1585:• if (messageChangedListeners == null)
1586: messageChangedListeners = new Vector<>();
1587: messageChangedListeners.addElement(l);
1588: }
1589:
1590: /**
1591: * Remove a MessageChanged listener. <p>
1592: *
1593: * The implementation provided here removes this listener
1594: * from the internal list of MessageChangedListeners.
1595: *
1596: * @param l the listener
1597: * @see #addMessageChangedListener
1598: */
1599: public synchronized void
1600: removeMessageChangedListener(MessageChangedListener l) {
1601:• if (messageChangedListeners != null)
1602: messageChangedListeners.removeElement(l);
1603: }
1604:
1605: /**
1606: * Notify all MessageChangedListeners. Folder implementations are
1607: * expected to use this method to broadcast MessageChanged events. <p>
1608: *
1609: * The provided implementation queues the event into
1610: * an internal event queue. An event dispatcher thread dequeues
1611: * events from the queue and dispatches them to registered
1612: * MessageChangedListeners. Note that the event dispatching occurs
1613: * in a separate thread, thus avoiding potential deadlock problems.
1614: *
1615: * @param type the MessageChangedEvent type
1616: * @param msg the message that changed
1617: */
1618: protected void notifyMessageChangedListeners(int type, Message msg) {
1619:• if (messageChangedListeners == null)
1620: return;
1621:
1622: MessageChangedEvent e = new MessageChangedEvent(this, type, msg);
1623: queueEvent(e, messageChangedListeners);
1624: }
1625:
1626: /*
1627: * Add the event and vector of listeners to the queue to be delivered.
1628: */
1629: @SuppressWarnings("unchecked")
1630: private void queueEvent(MailEvent event,
1631: Vector<? extends EventListener> vector) {
1632: /*
1633: * Copy the vector in order to freeze the state of the set
1634: * of EventListeners the event should be delivered to prior
1635: * to delivery. This ensures that any changes made to the
1636: * Vector from a target listener's method during the delivery
1637: * of this event will not take effect until after the event is
1638: * delivered.
1639: */
1640: Vector<? extends EventListener> v = (Vector) vector.clone();
1641: q.enqueue(event, v);
1642: }
1643:
1644: @Override
1645: protected void finalize() throws Throwable {
1646: try {
1647: q.terminateQueue();
1648: } finally {
1649: super.finalize();
1650: }
1651: }
1652:
1653: /**
1654: * override the default toString(), it will return the String
1655: * from Folder.getFullName() or if that is null, it will use
1656: * the default toString() behavior.
1657: */
1658:
1659: @Override
1660: public String toString() {
1661: String s = getFullName();
1662:• if (s != null)
1663: return s;
1664: else
1665: return super.toString();
1666: }
1667: }