You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by jb...@apache.org on 2005/01/20 06:09:17 UTC
svn commit: r125714 - /geronimo/trunk/specs/javamail/src/java/javax/mail/Folder.java
Author: jboynes
Date: Wed Jan 19 21:09:16 2005
New Revision: 125714
URL: http://svn.apache.org/viewcvs?view=rev&rev=125714
Log:
add javadoc
Modified:
geronimo/trunk/specs/javamail/src/java/javax/mail/Folder.java
Modified: geronimo/trunk/specs/javamail/src/java/javax/mail/Folder.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/specs/javamail/src/java/javax/mail/Folder.java?view=diff&rev=125714&p1=geronimo/trunk/specs/javamail/src/java/javax/mail/Folder.java&r1=125713&p2=geronimo/trunk/specs/javamail/src/java/javax/mail/Folder.java&r2=125714
==============================================================================
--- geronimo/trunk/specs/javamail/src/java/javax/mail/Folder.java (original)
+++ geronimo/trunk/specs/javamail/src/java/javax/mail/Folder.java Wed Jan 19 21:09:16 2005
@@ -17,325 +17,708 @@
package javax.mail;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import javax.mail.Flags.Flag;
import javax.mail.event.ConnectionEvent;
import javax.mail.event.ConnectionListener;
import javax.mail.event.FolderEvent;
import javax.mail.event.FolderListener;
+import javax.mail.event.MailEvent;
import javax.mail.event.MessageChangedEvent;
import javax.mail.event.MessageChangedListener;
import javax.mail.event.MessageCountEvent;
import javax.mail.event.MessageCountListener;
-import javax.mail.event.TransportListener;
import javax.mail.search.SearchTerm;
/**
+ * An abstract representation of a folder in a mail system; subclasses would
+ * implement Folders for each supported protocol.
+ * <p/>
+ * Depending on protocol and implementation, folders may contain other folders, messages,
+ * or both as indicated by the {@link Folder#HOLDS_FOLDERS} and {@link Folder#HOLDS_MESSAGES} flags.
+ * If the immplementation supports hierarchical folders, the format of folder names is
+ * implementation dependent; however, components of the name are separated by the
+ * delimiter character returned by {@link Folder#getSeparator()}.
+ * <p/>
+ * The case-insensitive folder name "INBOX" is reserved to refer to the primary folder
+ * for the current user on the current server; not all stores will provide an INBOX
+ * and it may not be available at all times.
+ *
* @version $Rev$ $Date$
*/
public abstract class Folder {
- // Constants from J2SE 1.4 doc (Constant Values)
- public static final int HOLDS_FOLDERS = 2;
+ /**
+ * Flag that indicates that a folder can contain messages.
+ */
public static final int HOLDS_MESSAGES = 1;
- private static final Message[] MESSAGE_ARRAY = new Message[0];
+ /**
+ * Flag that indicates that a folder can contain other folders.
+ */
+ public static final int HOLDS_FOLDERS = 2;
+
+ /**
+ * Flag indicating that this folder cannot be modified.
+ */
public static final int READ_ONLY = 1;
+ /**
+ * Flag indictaing that this folder can be modified.
+ * Question: what does it mean if both are set?
+ */
public static final int READ_WRITE = 2;
- private List _connectionListeners = new LinkedList();
- private List _folderListeners = new LinkedList();
- private List _messageChangedListeners = new LinkedList();
- private List _messageCountListeners = new LinkedList();
- private boolean _subscribed;
- protected int mode;
- protected Store store;
+ /**
+ * The store that this folder is part of.
+ */
+ protected Store store;
+ /**
+ * The current mode of this folder.
+ * When open, this can be {@link #READ_ONLY} or {@link #READ_WRITE};
+ * otherwise is set to -1.
+ */
+ protected int mode = -1;
+
+ private final List connectionListeners = new ArrayList(2);
+ private final List folderListeners = new ArrayList(2);
+ private final List messageChangedListeners = new ArrayList(2);
+ private final List messageCountListeners = new ArrayList(2);
+
+ /**
+ * Constructor that initializes the Store.
+ *
+ * @param store the store that this folder is part of
+ */
protected Folder(Store store) {
this.store = store;
}
- public void addConnectionListener(ConnectionListener listener) {
- _connectionListeners.add(listener);
- }
-
- public void addFolderListener(FolderListener listener) {
- _folderListeners.add(listener);
- }
+ /**
+ * Return the name of this folder.
+ * This can be invoked when the folder is closed.
+ *
+ * @return this folder's name
+ */
+ public abstract String getName();
- public void addMessageChangedListener(MessageChangedListener listener) {
- _messageChangedListeners.add(listener);
- }
+ /**
+ * Return the full absolute name of this folder.
+ * This can be invoked when the folder is closed.
+ *
+ * @return the full name of this folder
+ */
+ public abstract String getFullName();
- public void addMessageCountListener(MessageCountListener listener) {
- _messageCountListeners.add(listener);
+ /**
+ * Return the URLName for this folder, which includes the location of the store.
+ *
+ * @return the URLName for this folder
+ * @throws MessagingException
+ */
+ public URLName getURLName() throws MessagingException {
+ // todo shouldn't this include the full name of the folder?
+ return store.getURLName();
}
- public abstract void appendMessages(Message[] messages)
- throws MessagingException;
-
- public abstract void close(boolean expunge) throws MessagingException;
-
- public void copyMessages(Message[] messages, Folder folder)
- throws MessagingException {
- folder.appendMessages(messages);
+ /**
+ * Return the store that this folder is part of.
+ *
+ * @return the store this folder is part of
+ */
+ public Store getStore() {
+ return store;
}
- public abstract boolean create(int type) throws MessagingException;
-
- public abstract boolean delete(boolean recurse) throws MessagingException;
+ /**
+ * Return the parent for this folder; if the folder is at the root of a heirarchy
+ * this returns null.
+ * This can be invoked when the folder is closed.
+ *
+ * @return this folder's parent
+ * @throws MessagingException
+ */
+ public abstract Folder getParent() throws MessagingException;
+ /**
+ * Check to see if this folder physically exists in the store.
+ * This can be invoked when the folder is closed.
+ *
+ * @return true if the folder really exists
+ * @throws MessagingException if there was a problem accessing the store
+ */
public abstract boolean exists() throws MessagingException;
- public abstract Message[] expunge() throws MessagingException;
+ /**
+ * Return a list of folders from this Folder's namespace that match the supplied pattern.
+ * Patterns may contain the following wildcards:
+ * <ul><li>'%' which matches any characater except hierarchy delimiters</li>
+ * <li>'*' which matches any character including hierarchy delimiters</li>
+ * </ul>
+ * This can be invoked when the folder is closed.
+ *
+ * @param pattern the pattern to search for
+ * @return a, possibly empty, array containing Folders that matched the pattern
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract Folder[] list(String pattern) throws MessagingException;
- public void fetch(Message[] messages, FetchProfile profile)
- throws MessagingException {
- // default does not do anything
- return;
+ /**
+ * Return a list of folders to which the user is subscribed and which match the supplied pattern.
+ * If the store does not support the concept of subscription then this should match against
+ * all folders; the default implementation of this method achieves this by defaulting to the
+ * {@link #list(String)} method.
+ *
+ * @param pattern the pattern to search for
+ * @return a, possibly empty, array containing subscribed Folders that matched the pattern
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public Folder[] listSubscribed(String pattern) throws MessagingException {
+ return list(pattern);
}
- protected void finalize() throws Throwable {
- try {
- super.finalize();
- } finally {
- }
+ /**
+ * Convenience method that invokes {@link #list(String)} with the pattern "%".
+ *
+ * @return a, possibly empty, array of subfolders
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public Folder[] list() throws MessagingException {
+ return list("%");
}
- private int getCount(Flag flag) throws MessagingException {
- return getCount(flag, true);
+ /**
+ * Convenience method that invokes {@link #listSubscribed(String)} with the pattern "%".
+ *
+ * @return a, possibly empty, array of subscribed subfolders
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public Folder[] listSubscribed() throws MessagingException {
+ return listSubscribed("%");
}
- private int getCount(Flag flag, boolean value) throws MessagingException {
- if (isOpen()) {
- Message[] messages = getMessages();
- int total = 0;
- for (int i = 0; i < messages.length; i++) {
- if (messages[i].getFlags().contains(flag) == value) {
- total++;
- }
- }
- return total;
- } else {
- return -1;
- }
+ /**
+ * Return the character used by this folder's Store to separate path components.
+ *
+ * @return the name separater character
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract char getSeparator() throws MessagingException;
+
+ /**
+ * Return the type of this folder, indicating whether it can contain subfolders,
+ * messages, or both. The value returned is a bitmask with the appropriate bits set.
+ *
+ * @return the type of this folder
+ * @throws MessagingException if there was a problem accessing the store
+ * @see #HOLDS_FOLDERS
+ * @see #HOLDS_MESSAGES
+ */
+ public abstract int getType() throws MessagingException;
+
+ /**
+ * Create a new folder capable of containing subfoldera and/or messages as
+ * determined by the type parameter. Any hierarchy defined by the folder
+ * name will be recursively created.
+ * If the folder was sucessfully created, a {@link FolderEvent#CREATED CREATED FolderEvent}
+ * is sent to all FolderListeners registered with this Folder or with the Store.
+ *
+ * @param type the type, indicating if this folder should contain subfolders, messages or both
+ * @return true if the folder was sucessfully created
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract boolean create(int type) throws MessagingException;
+
+ /**
+ * Determine if the user is subscribed to this Folder. The default implementation in
+ * this class always returns true.
+ *
+ * @return true is the user is subscribed to this Folder
+ */
+ public boolean isSubscribed() {
+ return true;
}
- public int getDeletedMessageCount() throws MessagingException {
- return getCount(Flags.Flag.DELETED);
+ /**
+ * Set the user's subscription to this folder.
+ * Not all Stores support subscription; the default implementation in this class
+ * always throws a MethodNotSupportedException
+ *
+ * @param subscribed whether to subscribe to this Folder
+ * @throws MessagingException if there was a problem accessing the store
+ * @throws MethodNotSupportedException if the Store does not support subscription
+ */
+ public void setSubscribed(boolean subscribed) throws MessagingException {
+ throw new MethodNotSupportedException();
}
- public abstract Folder getFolder(String name) throws MessagingException;
+ /**
+ * Check to see if this Folder conatins messages with the {@link Flag.RECENT} flag set.
+ * This can be used when the folder is closed to perform a light-weight check for new mail;
+ * to perform an incremental check for new mail the folder must be opened.
+ *
+ * @return true if the Store has recent messages
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract boolean hasNewMessages() throws MessagingException;
- public abstract String getFullName();
+ /**
+ * Get the Folder determined by the supplied name; if the name is relative
+ * then it is interpreted relative to this folder. This does not check that
+ * the named folder actually exists.
+ *
+ * @param name the name of the folder to return
+ * @return the named folder
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract Folder getFolder(String name) throws MessagingException;
- public abstract Message getMessage(int id) throws MessagingException;
+ /**
+ * Delete this folder and possibly any subfolders. This operation can only be
+ * performed on a closed folder.
+ * If recurse is true, then all subfolders are deleted first, then any messages in
+ * this folder are removed and it is finally deleted; {@link FolderEvent#DELETED}
+ * events are sent as appropriate.
+ * If recurse is false, then the behaviour depends on the folder type and store
+ * implementation as followd:
+ * <ul>
+ * <li>If the folder can only conrain messages, then all messages are removed and
+ * then the folder is deleted; a {@link FolderEvent#DELETED} event is sent.</li>
+ * <li>If the folder can onlu contain subfolders, then if it is empty it will be
+ * deleted and a {@link FolderEvent#DELETED} event is sent; if the folder is not
+ * empty then the delete fails and this method returns false.</li>
+ * <li>If the folder can contain both subfolders and messages, then if the folder
+ * does not contain any subfolders, any messages are deleted, the folder itself
+ * is deleted and a {@link FolderEvent#DELETED} event is sent; if the folder does
+ * contain subfolders then the implementation may choose from the following three
+ * behaviors:
+ * <ol>
+ * <li>it may return false indicting the operation failed</li>
+ * <li>it may remove all messages within the folder, send a {@link FolderEvent#DELETED}
+ * event, and then return true to indicate the delete was performed. Note this does
+ * not delete the folder itself and the {@link #exists()} operation for this folder
+ * will return true</li>
+ * <li>it may remove all messages within the folder as per the previous option; in
+ * addition it may change the type of the Folder to only HOLDS_FOLDERS indictaing
+ * that messages may no longer be added</li>
+ * </li>
+ * </ul>
+ * FolderEvents are sent to all listeners registered with this folder or
+ * with the Store.
+ *
+ * @param recurse whether subfolders should be recursively deleted as well
+ * @return true if the delete operation succeeds
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract boolean delete(boolean recurse) throws MessagingException;
- public abstract int getMessageCount() throws MessagingException;
+ /**
+ * Rename this folder; the folder must be closed.
+ * If the rename is successfull, a {@link FolderEvent#RENAMED} event is sent to
+ * all listeners registered with this folder or with the store.
+ *
+ * @param newName the new name for this folder
+ * @return true if the rename succeeded
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract boolean renameTo(Folder newName) throws MessagingException;
- public Message[] getMessages() throws MessagingException {
- return getMessages(1, getMessageCount());
- }
+ /**
+ * Open this folder; the folder must be able to contain messages and
+ * must currently be closed. If the folder is opened successfully then
+ * a {@link ConnectionEvent#OPENED} event is sent to listeners registered
+ * with this Folder.
+ * <p/>
+ * Whether the Store allows multiple connections or if it allows multiple
+ * writers is implementation defined.
+ *
+ * @param mode READ_ONLY or READ_WRITE
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract void open(int mode) throws MessagingException;
- public Message[] getMessages(int from, int to) throws MessagingException {
- if (to == -1 || to < from) {
- throw new IndexOutOfBoundsException("Invalid message range: " + from + " to " + to);
- }
- Message[] result = new Message[to - from + 1];
- for (int i = from; i <= to; i++) {
- result[i] = getMessage(i);
- }
- return result;
- }
+ /**
+ * Close this folder; it must already be open.
+ * A {@link ConnectionEvent#CLOSED} event is sent to all listeners registered
+ * with this folder.
+ *
+ * @param expunge whether to expunge all deleted messages
+ * @throws MessagingException if there was a problem accessing the store; the folder is still closed
+ */
+ public abstract void close(boolean expunge) throws MessagingException;
- public Message[] getMessages(int ids[]) throws MessagingException {
- Message[] result = new Message[ids.length];
- for (int i = 0; i < ids.length; i++) {
- result[i] = getMessage(ids[i]);
- }
- return result;
- }
+ /**
+ * Indicates that the folder has been opened.
+ *
+ * @return true if the folder is open
+ */
+ public abstract boolean isOpen();
+ /**
+ * Return the mode of this folder ass passed to {@link #open(int)}, or -1 if
+ * the folder is closed.
+ *
+ * @return the mode this folder was opened with
+ */
public int getMode() {
return mode;
}
- public abstract String getName();
-
- public int getNewMessageCount() throws MessagingException {
- return getCount(Flags.Flag.RECENT);
- }
-
- public abstract Folder getParent() throws MessagingException;
-
+ /**
+ * Get the flags supported by this folder.
+ *
+ * @return the flags supported by this folder, or null if unknown
+ * @see Flags
+ */
public abstract Flags getPermanentFlags();
- public abstract char getSeparator() throws MessagingException;
+ /**
+ * Return the number of messages this folder contains.
+ * If this operation is invoked on a closed folder, the implementation
+ * may choose to return -1 to avoid the expense of opening the folder.
+ *
+ * @return the number of messages, or -1 if unknown
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract int getMessageCount() throws MessagingException;
- public Store getStore() {
- return store;
+ /**
+ * Return the numbew of messages in this folder that have the {@link Flag.RECENT} flag set.
+ * If this operation is invoked on a closed folder, the implementation
+ * may choose to return -1 to avoid the expense of opening the folder.
+ * The default implmentation of this method iterates over all messages
+ * in the folder; subclasses should override if possible to provide a more
+ * efficient implementation.
+ *
+ * @return the number of new messages, or -1 if unknown
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public int getNewMessageCount() throws MessagingException {
+ return getCount(Flags.Flag.RECENT, true);
}
- public abstract int getType() throws MessagingException;
-
+ /**
+ * Return the numbew of messages in this folder that do not have the {@link Flag.SEEN} flag set.
+ * If this operation is invoked on a closed folder, the implementation
+ * may choose to return -1 to avoid the expense of opening the folder.
+ * The default implmentation of this method iterates over all messages
+ * in the folder; subclasses should override if possible to provide a more
+ * efficient implementation.
+ *
+ * @return the number of new messages, or -1 if unknown
+ * @throws MessagingException if there was a problem accessing the store
+ */
public int getUnreadMessageCount() throws MessagingException {
return getCount(Flags.Flag.SEEN, false);
}
- public URLName getURLName() throws MessagingException {
- return store.getURLName();
+ /**
+ * Return the numbew of messages in this folder that have the {@link Flag.DELETED} flag set.
+ * If this operation is invoked on a closed folder, the implementation
+ * may choose to return -1 to avoid the expense of opening the folder.
+ * The default implmentation of this method iterates over all messages
+ * in the folder; subclasses should override if possible to provide a more
+ * efficient implementation.
+ *
+ * @return the number of new messages, or -1 if unknown
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public int getDeletedMessageCount() throws MessagingException {
+ return getCount(Flags.Flag.DELETED, true);
}
- public abstract boolean hasNewMessages() throws MessagingException;
-
- public abstract boolean isOpen();
-
- public boolean isSubscribed() {
- return _subscribed;
+ private int getCount(Flag flag, boolean value) throws MessagingException {
+ if (!isOpen()) {
+ return -1;
+ }
+ Message[] messages = getMessages();
+ int total = 0;
+ for (int i = 0; i < messages.length; i++) {
+ if (messages[i].getFlags().contains(flag) == value) {
+ total++;
+ }
+ }
+ return total;
}
- public Folder[] list() throws MessagingException {
- return list("%");
+ /**
+ * Retrieve the message with the specified index in this Folder;
+ * messages indices start at 1 not zero.
+ * Clients should note that the index for a specific message may change
+ * if the folder is expunged; {@link Message} objects should be used as
+ * references instead.
+ *
+ * @param index the index of the message to fetch
+ * @return the message
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract Message getMessage(int index) throws MessagingException;
+
+ /**
+ * Retrieve messages with index between start and end inclusive
+ *
+ * @param start index of first message
+ * @param end index of last message
+ * @return an array of messages from start to end inclusive
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public Message[] getMessages(int start, int end) throws MessagingException {
+ Message[] result = new Message[end - start + 1];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = getMessage(start++);
+ }
+ return result;
}
- public abstract Folder[] list(String pattern) throws MessagingException;
+ /**
+ * Retrieve messages with the specified indices.
+ *
+ * @param ids the indices of the messages to fetch
+ * @return the specified messages
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public Message[] getMessages(int ids[]) throws MessagingException {
+ Message[] result = new Message[ids.length];
+ for (int i = 0; i < ids.length; i++) {
+ result[i] = getMessage(ids[i]);
+ }
+ return result;
+ }
- public Folder[] listSubscribed() throws MessagingException {
- return listSubscribed("%");
+ /**
+ * Retrieve all messages.
+ *
+ * @return all messages in this folder
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public Message[] getMessages() throws MessagingException {
+ return getMessages(1, getMessageCount());
}
- public Folder[] listSubscribed(String pattern) throws MessagingException {
- return list(pattern);
+ /**
+ * Append the supplied messages to this folder. A {@link MessageCountEvent} is sent
+ * to all listeners registered with this folder when all messages have been appended.
+ * If the array contains a previously expunged message, it must be re-appended to the Store
+ * and implementations must not abort this operation.
+ *
+ * @param messages the messages to append
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract void appendMessages(Message[] messages) throws MessagingException;
+
+ /**
+ * Hint to the store to prefetch information on the supplied messaged.
+ * Subclasses should override this method to provide an efficient implementation;
+ * the default implementation in this class simply returns.
+ *
+ * @param messages messages for which information should be fetched
+ * @param profile the information to fetch
+ * @throws MessagingException if there was a problem accessing the store
+ * @see FetchProfile
+ */
+ public void fetch(Message[] messages, FetchProfile profile) throws MessagingException {
+ return;
}
- protected void notifyConnectionListeners(int type) {
- ConnectionEvent event = new ConnectionEvent(this, type);
- Iterator it = _connectionListeners.iterator();
- while (it.hasNext()) {
- TransportListener listener = (TransportListener) it.next();
- event.dispatch(listener);
+ /**
+ * Set flags on the messages to the supplied value; all messages must belong to this folder.
+ * This method may be overridden by subclasses that can optimize the setting
+ * of flags on multiple messages at once; the default implementation simply calls
+ * {@link Message#setFlags(Flags, boolean)} for each supplied messages.
+ *
+ * @param messages whose flags should be set
+ * @param flags the set of flags to modify
+ * @param value the value the flags should be set to
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public void setFlags(Message[] messages, Flags flags, boolean value) throws MessagingException {
+ for (int i = 0; i < messages.length; i++) {
+ Message message = messages[i];
+ message.setFlags(flags, value);
}
}
- protected void notifyFolderListeners(int type) {
- Iterator it = _folderListeners.iterator();
- FolderEvent event = new FolderEvent(this, this, type);
- while (it.hasNext()) {
- FolderListener listener = (FolderListener) it.next();
- event.dispatch(listener);
+ /**
+ * Set flags on a range of messages to the supplied value.
+ * This method may be overridden by subclasses that can optimize the setting
+ * of flags on multiple messages at once; the default implementation simply
+ * gets each message and then calls {@link Message#setFlags(Flags, boolean)}.
+ *
+ * @param start first message end set
+ * @param end last message end set
+ * @param flags the set of flags end modify
+ * @param value the value the flags should be set end
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public void setFlags(int start, int end, Flags flags, boolean value) throws MessagingException {
+ for (int i = start; i <= end; i++) {
+ Message message = getMessage(i);
+ message.setFlags(flags, value);
}
}
- protected void notifyFolderRenamedListeners(Folder newFolder) {
- Iterator it = _folderListeners.iterator();
- FolderEvent event =
- new FolderEvent(this, this, newFolder, FolderEvent.RENAMED);
- while (it.hasNext()) {
- FolderListener listener = (FolderListener) it.next();
- event.dispatch(listener);
+ /**
+ * Set flags on a set of messages to the supplied value.
+ * This method may be overridden by subclasses that can optimize the setting
+ * of flags on multiple messages at once; the default implementation simply
+ * gets each message and then calls {@link Message#setFlags(Flags, boolean)}.
+ *
+ * @param ids the indexes of the messages to set
+ * @param flags the set of flags end modify
+ * @param value the value the flags should be set end
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public void setFlags(int ids[], Flags flags, boolean value) throws MessagingException {
+ for (int i = 0; i < ids.length; i++) {
+ Message message = getMessage(ids[i]);
+ message.setFlags(flags, value);
}
}
- protected void notifyMessageAddedListeners(Message[] messages) {
- Iterator it = _messageChangedListeners.iterator();
- MessageCountEvent event =
- new MessageCountEvent(this,
- MessageCountEvent.ADDED,
- false,
- messages);
- while (it.hasNext()) {
- MessageCountEvent listener = (MessageCountEvent) it.next();
- event.dispatch(listener);
- }
+ /**
+ * Copy the specified messages to another folder.
+ * The default implementation simply appends the supplied messages to the
+ * target folder using {@link #appendMessages(Message[])}.
+ * @param messages the messages to copy
+ * @param folder the folder to copy to
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public void copyMessages(Message[] messages, Folder folder) throws MessagingException {
+ folder.appendMessages(messages);
}
- protected void notifyMessageChangedListeners(int type, Message message) {
- Iterator it = _messageChangedListeners.iterator();
- MessageChangedEvent event =
- new MessageChangedEvent(this, type, message);
- while (it.hasNext()) {
- MessageCountEvent listener = (MessageCountEvent) it.next();
- event.dispatch(listener);
- }
+ /**
+ * Permanently delete all supplied messages that have the DELETED flag set from the Store.
+ * The original message indices of all messages actually deleted are returned and a
+ * {@link MessageCountEvent} event is sent to all listeners with this folder. The expunge
+ * may cause the indices of all messaged that remain in the folder to change.
+ *
+ * @return the original indices of messages that were actually deleted
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public abstract Message[] expunge() throws MessagingException;
+
+ /**
+ * Search this folder for messages matching the supplied search criteria.
+ * The default implementation simply invoke <code>search(term, getMessages())
+ * applying the search over all messages in the folder; subclasses may provide
+ * a more efficient mechanism.
+ *
+ * @param term the search criteria
+ * @return an array containing messages that match the criteria
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public Message[] search(SearchTerm term) throws MessagingException {
+ return search(term, getMessages());
}
- protected void notifyMessageRemovedListeners(boolean removed,
- Message[] messages) {
- Iterator it = _messageChangedListeners.iterator();
- MessageCountEvent event =
- new MessageCountEvent(this,
- MessageCountEvent.REMOVED,
- removed,
- messages);
- while (it.hasNext()) {
- MessageCountEvent listener = (MessageCountEvent) it.next();
- event.dispatch(listener);
+ /**
+ * Search the supplied messages for those that match the supplied criteria;
+ * messages must belong to this folder.
+ * The default implementation iterates through the messages, returning those
+ * whose {@link Message#match(javax.mail.search.SearchTerm)} method returns true;
+ * subclasses may provide a more efficient implementation.
+ *
+ * @param term the search criteria
+ * @param messages the messages to search
+ * @return an array containing messages that match the criteria
+ * @throws MessagingException if there was a problem accessing the store
+ */
+ public Message[] search(SearchTerm term, Message[] messages) throws MessagingException {
+ List result = new ArrayList(messages.length);
+ for (int i = 0; i < messages.length; i++) {
+ Message message = messages[i];
+ if (message.match(term)) {
+ result.add(message);
+ }
}
+ return (Message[]) result.toArray(new Message[result.size()]);
}
- public abstract void open(int mode) throws MessagingException;
+ public void addConnectionListener(ConnectionListener listener) {
+ connectionListeners.add(listener);
+ }
public void removeConnectionListener(ConnectionListener listener) {
- _connectionListeners.remove(listener);
+ connectionListeners.remove(listener);
+ }
+
+ protected void notifyConnectionListeners(int type) {
+ notifyListeners(connectionListeners, new ConnectionEvent(this, type));
+ }
+
+ public void addFolderListener(FolderListener listener) {
+ folderListeners.add(listener);
}
public void removeFolderListener(FolderListener listener) {
- _folderListeners.remove(listener);
+ folderListeners.remove(listener);
}
- public void removeMessageChangedListener(MessageChangedListener listener) {
- _messageChangedListeners.remove(listener);
+ protected void notifyFolderListeners(int type) {
+ notifyListeners(folderListeners, new FolderEvent(this, this, type));
+ }
+
+ protected void notifyFolderRenamedListeners(Folder newFolder) {
+ notifyListeners(folderListeners, new FolderEvent(this, this, newFolder, FolderEvent.RENAMED));
+ }
+
+ public void addMessageCountListener(MessageCountListener listener) {
+ messageCountListeners.add(listener);
}
public void removeMessageCountListener(MessageCountListener listener) {
- _messageCountListeners.remove(listener);
+ messageCountListeners.remove(listener);
}
- public abstract boolean renameTo(Folder newName) throws MessagingException;
+ protected void notifyMessageAddedListeners(Message[] messages) {
+ MailEvent event = new MessageCountEvent(this, MessageCountEvent.ADDED, false, messages);
+ notifyListeners(messageChangedListeners, event);
+ }
- public Message[] search(SearchTerm term) throws MessagingException {
- return search(term, getMessages());
+ protected void notifyMessageRemovedListeners(boolean removed, Message[] messages) {
+ MessageCountEvent event = new MessageCountEvent(this, MessageCountEvent.REMOVED, removed, messages);
+ notifyListeners(messageChangedListeners, event);
}
- public Message[] search(SearchTerm term, Message[] messages)
- throws MessagingException {
- List result = new LinkedList();
- for (int i = 0; i < messages.length; i++) {
- Message message = messages[i];
- if (term.match(message)) {
- result.add(message);
- }
- }
- return (Message[]) result.toArray(MESSAGE_ARRAY);
+ public void addMessageChangedListener(MessageChangedListener listener) {
+ messageChangedListeners.add(listener);
}
- public void setFlags(int from, int to, Flags flags, boolean value)
- throws MessagingException {
- setFlags(getMessages(from, to), flags, value);
+ public void removeMessageChangedListener(MessageChangedListener listener) {
+ messageChangedListeners.remove(listener);
}
- public void setFlags(int ids[], Flags flags, boolean value)
- throws MessagingException {
- setFlags(getMessages(ids), flags, value);
+ protected void notifyMessageChangedListeners(int type, Message message) {
+ MessageChangedEvent event = new MessageChangedEvent(this, type, message);
+ notifyListeners(messageChangedListeners, event);
}
- public void setFlags(Message[] messages, Flags flags, boolean value)
- throws MessagingException {
- for (int i = 0; i < messages.length; i++) {
- Message message = messages[i];
- message.setFlags(flags, value);
+ private void notifyListeners(Collection listeners, MailEvent event) {
+ // todo do we need to dispatch these events using a different thread?
+ for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
+ event.dispatch(iterator.next());
}
}
- public void setSubscribed(boolean subscribed) throws MessagingException {
- _subscribed = subscribed;
+ /**
+ * Unregisters all listeners.
+ */
+ protected void finalize() throws Throwable {
+ connectionListeners.clear();
+ folderListeners.clear();
+ messageChangedListeners.clear();
+ messageCountListeners.clear();
+ store = null;
+ super.finalize();
}
+ /**
+ * Returns the full name of this folder; if null, returns the value from the superclass.
+ * @return a string form of this folder
+ */
public String toString() {
String name = getFullName();
- if (name == null) {
- return super.toString();
- } else {
- return name;
- }
+ return name == null ? super.toString() : name;
}
}