0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common Development
0008: * and Distribution License("CDDL") (collectively, the "License"). You
0009: * may not use this file except in compliance with the License. You can obtain
0010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
0011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
0012: * language governing permissions and limitations under the License.
0013: *
0014: * When distributing the software, include this License Header Notice in each
0015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
0016: * Sun designates this particular file as subject to the "Classpath" exception
0017: * as provided by Sun in the GPL Version 2 section of the License file that
0018: * accompanied this code. If applicable, add the following below the License
0019: * Header, with the fields enclosed by brackets [] replaced by your own
0020: * identifying information: "Portions Copyrighted [year]
0021: * [name of copyright owner]"
0022: *
0023: * Contributor(s):
0024: *
0025: * If you wish your version of this file to be governed by only the CDDL or
0026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
0027: * elects to include this software in this distribution under the [CDDL or GPL
0028: * Version 2] license." If you don't indicate a single choice of license, a
0029: * recipient has the option to distribute your version of this file under
0030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
0031: * its licensees as provided above. However, if you add GPL Version 2 code
0032: * and therefore, elected the GPL Version 2 license, then the option applies
0033: * only if the new code is made subject to such option by the copyright
0034: * holder.
0035: */
0036:
0037: /*
0038: * @(#)Folder.java 1.58 07/05/04
0039: */
0040:
0041: package javax.mail;
0042:
0043: import java.io.*;
0044: import java.lang.*;
0045: import java.util.Vector;
0046: import java.util.StringTokenizer;
0047: import javax.mail.search.SearchTerm;
0048: import javax.mail.event.*;
0049:
0050: /**
0051: * Folder is an abstract class that represents a folder for mail
0052: * messages. Subclasses implement protocol specific Folders.<p>
0053: *
0054: * Folders can contain Messages, other Folders or both, thus providing
0055: * a tree-like hierarchy rooted at the Store's default folder. (Note
0056: * that some Folder implementations may not allow both Messages and
0057: * other Folders in the same Folder).<p>
0058: *
0059: * The interpretation of folder names is implementation dependent.
0060: * The different levels of hierarchy in a folder's full name
0061: * are separated from each other by the hierarchy delimiter
0062: * character.<p>
0063: *
0064: * The case-insensitive full folder name (that is, the full name
0065: * relative to the default folder for a Store) <strong>INBOX</strong>
0066: * is reserved to mean the "primary folder for this user on this
0067: * server". Not all Stores will provide an INBOX folder, and not
0068: * all users will have an INBOX folder at all times. The name
0069: * <strong>INBOX</strong> is reserved to refer to this folder,
0070: * when it exists, in Stores that provide it. <p>
0071: *
0072: * A Folder object obtained from a Store need not actually exist
0073: * in the backend store. The <code>exists</code> method tests whether
0074: * the folder exists or not. The <code>create</code> method
0075: * creates a Folder. <p>
0076: *
0077: * A Folder is initially in the closed state. Certain methods are valid
0078: * in this state; the documentation for those methods note this. A
0079: * Folder is opened by calling its 'open' method. All Folder methods,
0080: * except <code>open</code>, <code>delete</code> and
0081: * <code>renameTo</code>, are valid in this state. <p>
0082: *
0083: * The only way to get a Folder is by invoking the
0084: * <code>getFolder</code> method on Store, Folder, or Session, or by invoking
0085: * the <code>list</code> or <code>listSubscribed</code> methods
0086: * on Folder. Folder objects returned by the above methods are not
0087: * cached by the Store. Thus, invoking the <code>getFolder</code> method
0088: * with the same folder name multiple times will return distinct Folder
0089: * objects. Likewise for the <code>list</code> and <code>listSubscribed</code>
0090: * methods. <p>
0091: *
0092: * The Message objects within the Folder are cached by the Folder.
0093: * Thus, invoking <code>getMessage(msgno)</code> on the same message number
0094: * multiple times will return the same Message object, until an
0095: * expunge is done on this Folder. <p>
0096: *
0097: * Note that a Message's message number can change within a
0098: * session if the containing Folder is expunged using the expunge
0099: * method. Clients that use message numbers as references to messages
0100: * should be aware of this and should be prepared to deal with
0101: * situation (probably by flushing out existing message number references
0102: * and reloading them). Because of this complexity, it is better for
0103: * clients to use Message objects as references to messages, rather than
0104: * message numbers. Expunged Message objects still have to be
0105: * pruned, but other Message objects in that folder are not affected by the
0106: * expunge.
0107: *
0108: * @author John Mani
0109: * @author Bill Shannon
0110: */
0111:
0112: public abstract class Folder {
0113:
0114: /**
0115: * The parent store.
0116: */
0117: protected Store store;
0118:
0119: /**
0120: * The open mode of this folder. The open mode is
0121: * <code>Folder.READ_ONLY</code>, <code>Folder.READ_WRITE</code>,
0122: * or -1 if not known.
0123: * @since JavaMail 1.1
0124: */
0125: protected int mode = -1;
0126:
0127: /**
0128: * Constructor that takes a Store object.
0129: *
0130: * @param store the Store that holds this folder
0131: */
0132: protected Folder(Store store) {
0133: this .store = store;
0134: }
0135:
0136: /**
0137: * Returns the name of this Folder. <p>
0138: *
0139: * This method can be invoked on a closed Folder.
0140: *
0141: * @return name of the Folder
0142: */
0143: public abstract String getName();
0144:
0145: /**
0146: * Returns the full name of this Folder. If the folder resides under
0147: * the root hierarchy of this Store, the returned name is relative
0148: * to the root. Otherwise an absolute name, starting with the
0149: * hierarchy delimiter, is returned. <p>
0150: *
0151: * This method can be invoked on a closed Folder.
0152: *
0153: * @return full name of the Folder
0154: */
0155: public abstract String getFullName();
0156:
0157: /**
0158: * Return a URLName representing this folder. The returned URLName
0159: * does <em>not</em> include the password used to access the store.
0160: *
0161: * @return the URLName representing this folder
0162: * @see URLName
0163: * @since JavaMail 1.1
0164: */
0165: public URLName getURLName() throws MessagingException {
0166: URLName storeURL = getStore().getURLName();
0167: String fullname = getFullName();
0168: StringBuffer encodedName = new StringBuffer();
0169: char separator = getSeparator();
0170:
0171: if (fullname != null) {
0172: /*
0173: // We need to encode each of the folder's names.
0174: StringTokenizer tok = new StringTokenizer(
0175: fullname, new Character(separator).toString(), true);
0176:
0177: while (tok.hasMoreTokens()) {
0178: String s = tok.nextToken();
0179: if (s.charAt(0) == separator)
0180: encodedName.append(separator);
0181: else
0182: // XXX - should encode, but since there's no decoder...
0183: //encodedName.append(java.net.URLEncoder.encode(s));
0184: encodedName.append(s);
0185: }
0186: */
0187: // append the whole thing, until we can encode
0188: encodedName.append(fullname);
0189: }
0190:
0191: /*
0192: * Sure would be convenient if URLName had a
0193: * constructor that took a base URLName.
0194: */
0195: return new URLName(storeURL.getProtocol(), storeURL.getHost(),
0196: storeURL.getPort(), encodedName.toString(), storeURL
0197: .getUsername(), null /* no password */);
0198: }
0199:
0200: /**
0201: * Returns the Store that owns this Folder object.
0202: * This method can be invoked on a closed Folder.
0203: * @return the Store
0204: */
0205: public Store getStore() {
0206: return store;
0207: }
0208:
0209: /**
0210: * Returns the parent folder of this folder.
0211: * This method can be invoked on a closed Folder. If this folder
0212: * is the top of a folder hierarchy, this method returns null. <p>
0213: *
0214: * Note that since Folder objects are not cached, invoking this method
0215: * returns a new distinct Folder object.
0216: *
0217: * @return Parent folder
0218: */
0219: public abstract Folder getParent() throws MessagingException;
0220:
0221: /**
0222: * Tests if this folder physically exists on the Store.
0223: * This method can be invoked on a closed Folder.
0224: *
0225: * @return true if the folder exists, otherwise false
0226: * @see #create
0227: * @exception MessagingException typically if the connection
0228: * to the server is lost.
0229: */
0230: public abstract boolean exists() throws MessagingException;
0231:
0232: /**
0233: * Returns a list of Folders belonging to this Folder's namespace
0234: * that match the specified pattern. Patterns may contain the wildcard
0235: * characters <code>"%"</code>, which matches any character except hierarchy
0236: * delimiters, and <code>"*"</code>, which matches any character. <p>
0237: *
0238: * As an example, given the folder hierarchy: <pre>
0239: * Personal/
0240: * Finance/
0241: * Stocks
0242: * Bonus
0243: * StockOptions
0244: * Jokes
0245: * </pre>
0246: * <code>list("*")</code> on "Personal" will return the whole
0247: * hierarchy. <br>
0248: * <code>list("%")</code> on "Personal" will return "Finance" and
0249: * "Jokes". <br>
0250: * <code>list("Jokes")</code> on "Personal" will return "Jokes".<br>
0251: * <code>list("Stock*")</code> on "Finance" will return "Stocks"
0252: * and "StockOptions". <p>
0253: *
0254: * Folder objects are not cached by the Store, so invoking this
0255: * method on the same pattern multiple times will return that many
0256: * distinct Folder objects. <p>
0257: *
0258: * This method can be invoked on a closed Folder.
0259: *
0260: * @param pattern the match pattern
0261: * @return array of matching Folder objects. An empty
0262: * array is returned if no matching Folders exist.
0263: * @see #listSubscribed
0264: * @exception FolderNotFoundException if this folder does
0265: * not exist.
0266: * @exception MessagingException
0267: */
0268: public abstract Folder[] list(String pattern)
0269: throws MessagingException;
0270:
0271: /**
0272: * Returns a list of subscribed Folders belonging to this Folder's
0273: * namespace that match the specified pattern. If the folder does
0274: * not support subscription, this method should resolve to
0275: * <code>list</code>.
0276: * (The default implementation provided here, does just this).
0277: * The pattern can contain wildcards as for <code>list</code>. <p>
0278: *
0279: * Note that, at a given level of the folder hierarchy, a particular
0280: * folder may not be subscribed, but folders underneath that folder
0281: * in the folder hierarchy may be subscribed. In order to allow
0282: * walking the folder hierarchy, such unsubscribed folders may be
0283: * returned, indicating that a folder lower in the hierarchy is
0284: * subscribed. The <code>isSubscribed</code> method on a folder will
0285: * tell whether any particular folder is actually subscribed. <p>
0286: *
0287: * Folder objects are not cached by the Store, so invoking this
0288: * method on the same pattern multiple times will return that many
0289: * distinct Folder objects. <p>
0290: *
0291: * This method can be invoked on a closed Folder.
0292: *
0293: * @param pattern the match pattern
0294: * @return array of matching subscribed Folder objects. An
0295: * empty array is returned if no matching
0296: * subscribed folders exist.
0297: * @see #list
0298: * @exception FolderNotFoundException if this folder does
0299: * not exist.
0300: * @exception MessagingException
0301: */
0302: public Folder[] listSubscribed(String pattern)
0303: throws MessagingException {
0304: return list(pattern);
0305: }
0306:
0307: /**
0308: * Convenience method that returns the list of folders under this
0309: * Folder. This method just calls the <code>list(String pattern)</code>
0310: * method with <code>"%"</code> as the match pattern. This method can
0311: * be invoked on a closed Folder.
0312: *
0313: * @return array of Folder objects under this Folder. An
0314: * empty array is returned if no subfolders exist.
0315: * @see #list
0316: * @exception FolderNotFoundException if this folder does
0317: * not exist.
0318: * @exception MessagingException
0319: */
0320:
0321: public Folder[] list() throws MessagingException {
0322: return list("%");
0323: }
0324:
0325: /**
0326: * Convenience method that returns the list of subscribed folders
0327: * under this Folder. This method just calls the
0328: * <code>listSubscribed(String pattern)</code> method with <code>"%"</code>
0329: * as the match pattern. This method can be invoked on a closed Folder.
0330: *
0331: * @return array of subscribed Folder objects under this
0332: * Folder. An empty array is returned if no subscribed
0333: * subfolders exist.
0334: * @see #listSubscribed
0335: * @exception FolderNotFoundException if this folder does
0336: * not exist.
0337: * @exception MessagingException
0338: */
0339: public Folder[] listSubscribed() throws MessagingException {
0340: return listSubscribed("%");
0341: }
0342:
0343: /**
0344: * Return the delimiter character that separates this Folder's pathname
0345: * from the names of immediate subfolders. This method can be invoked
0346: * on a closed Folder.
0347: *
0348: * @exception FolderNotFoundException if the implementation
0349: * requires the folder to exist, but it does not
0350: * @return Hierarchy separator character
0351: */
0352: public abstract char getSeparator() throws MessagingException;
0353:
0354: /**
0355: * This folder can contain messages
0356: */
0357: public final static int HOLDS_MESSAGES = 0x01;
0358:
0359: /**
0360: * This folder can contain other folders
0361: */
0362: public final static int HOLDS_FOLDERS = 0x02;
0363:
0364: /**
0365: * Returns the type of this Folder, that is, whether this folder can hold
0366: * messages or subfolders or both. The returned value is an integer
0367: * bitfield with the appropriate bits set. This method can be invoked
0368: * on a closed folder.
0369: *
0370: * @return integer with appropriate bits set
0371: * @exception FolderNotFoundException if this folder does
0372: * not exist.
0373: * @see #HOLDS_FOLDERS
0374: * @see #HOLDS_MESSAGES
0375: */
0376: public abstract int getType() throws MessagingException;
0377:
0378: /**
0379: * Create this folder on the Store. When this folder is created, any
0380: * folders in its path that do not exist are also created. <p>
0381: *
0382: * If the creation is successful, a CREATED FolderEvent is delivered
0383: * to any FolderListeners registered on this Folder and this Store.
0384: *
0385: * @param type The type of this folder.
0386: *
0387: * @return true if the creation succeeds, else false.
0388: * @exception MessagingException
0389: * @see #HOLDS_FOLDERS
0390: * @see #HOLDS_MESSAGES
0391: * @see javax.mail.event.FolderEvent
0392: */
0393: public abstract boolean create(int type) throws MessagingException;
0394:
0395: /**
0396: * Returns true if this Folder is subscribed. <p>
0397: *
0398: * This method can be invoked on a closed Folder. <p>
0399: *
0400: * The default implementation provided here just returns true.
0401: *
0402: * @return true if this Folder is subscribed
0403: */
0404: public boolean isSubscribed() {
0405: return true;
0406: }
0407:
0408: /**
0409: * Subscribe or unsubscribe this Folder. Not all Stores support
0410: * subscription. <p>
0411: *
0412: * This method can be invoked on a closed Folder. <p>
0413: *
0414: * The implementation provided here just throws the
0415: * MethodNotSupportedException.
0416: *
0417: * @param subscribe true to subscribe, false to unsubscribe
0418: * @exception FolderNotFoundException if this folder does
0419: * not exist.
0420: * @exception MethodNotSupportedException if this store
0421: * does not support subscription
0422: * @exception MessagingException
0423: */
0424: public void setSubscribed(boolean subscribe)
0425: throws MessagingException {
0426: throw new MethodNotSupportedException();
0427: }
0428:
0429: /**
0430: * Returns true if this Folder has new messages since the last time
0431: * this indication was reset. When this indication is set or reset
0432: * depends on the Folder implementation (and in the case of IMAP,
0433: * depends on the server). This method can be used to implement
0434: * a lightweight "check for new mail" operation on a Folder without
0435: * opening it. (For example, a thread that monitors a mailbox and
0436: * flags when it has new mail.) This method should indicate whether
0437: * any messages in the Folder have the <code>RECENT</code> flag set. <p>
0438: *
0439: * Note that this is not an incremental check for new mail, i.e.,
0440: * it cannot be used to determine whether any new messages have
0441: * arrived since the last time this method was invoked. To
0442: * implement incremental checks, the Folder needs to be opened. <p>
0443: *
0444: * This method can be invoked on a closed Folder that can contain
0445: * Messages.
0446: *
0447: * @return true if the Store has new Messages
0448: * @exception FolderNotFoundException if this folder does
0449: * not exist.
0450: * @exception MessagingException
0451: */
0452: public abstract boolean hasNewMessages() throws MessagingException;
0453:
0454: /**
0455: * Return the Folder object corresponding to the given name. Note that
0456: * this folder does not physically have to exist in the Store. The
0457: * <code>exists()</code> method on a Folder indicates whether it really
0458: * exists on the Store. <p>
0459: *
0460: * In some Stores, name can be an absolute path if it starts with the
0461: * hierarchy delimiter. Otherwise, it is interpreted relative to
0462: * this Folder. <p>
0463: *
0464: * Folder objects are not cached by the Store, so invoking this
0465: * method on the same name multiple times will return that many
0466: * distinct Folder objects. <p>
0467: *
0468: * This method can be invoked on a closed Folder.
0469: *
0470: * @param name name of the Folder
0471: * @return Folder object
0472: * @exception MessagingException
0473: */
0474: public abstract Folder getFolder(String name)
0475: throws MessagingException;
0476:
0477: /**
0478: * Delete this Folder. This method will succeed only on a closed
0479: * Folder. <p>
0480: *
0481: * The <code>recurse</code> flag controls whether the deletion affects
0482: * subfolders or not. If true, all subfolders are deleted, then this
0483: * folder itself is deleted. If false, the behaviour is dependent on
0484: * the folder type and is elaborated below: <p>
0485: *
0486: * <ul>
0487: * <li>
0488: * The folder can contain only messages: (type == HOLDS_MESSAGES).
0489: * <br>
0490: * All messages within the folder are removed. The folder
0491: * itself is then removed. An appropriate FolderEvent is generated by
0492: * the Store and this folder. <p>
0493: *
0494: * <li>
0495: * The folder can contain only subfolders: (type == HOLDS_FOLDERS).
0496: * <br>
0497: * If this folder is empty (does not contain any
0498: * subfolders at all), it is removed. An appropriate FolderEvent is
0499: * generated by the Store and this folder.<br>
0500: * If this folder contains any subfolders, the delete fails
0501: * and returns false. <p>
0502: *
0503: * <li>
0504: * The folder can contain subfolders as well as messages: <br>
0505: * If the folder is empty (no messages or subfolders), it
0506: * is removed. If the folder contains no subfolders, but only messages,
0507: * then all messages are removed. The folder itself is then removed.
0508: * In both the above cases, an appropriate FolderEvent is
0509: * generated by the Store and this folder. <p>
0510: *
0511: * If the folder contains subfolders there are 3 possible
0512: * choices an implementation is free to do: <p>
0513: *
0514: * <ol>
0515: * <li> The operation fails, irrespective of whether this folder
0516: * contains messages or not. Some implementations might elect to go
0517: * with this simple approach. The delete() method returns false.
0518: *
0519: * <li> Any messages within the folder are removed. Subfolders
0520: * are not removed. The folder itself is not removed or affected
0521: * in any manner. The delete() method returns true. And the
0522: * exists() method on this folder will return true indicating that
0523: * this folder still exists. <br>
0524: * An appropriate FolderEvent is generated by the Store and this folder.
0525: *
0526: * <li> Any messages within the folder are removed. Subfolders are
0527: * not removed. The folder itself changes its type from
0528: * HOLDS_FOLDERS | HOLDS_MESSAGES to HOLDS_FOLDERS. Thus new
0529: * messages cannot be added to this folder, but new subfolders can
0530: * be created underneath. The delete() method returns true indicating
0531: * success. The exists() method on this folder will return true
0532: * indicating that this folder still exists. <br>
0533: * An appropriate FolderEvent is generated by the Store and this folder.
0534: * </ol>
0535: * </ul>
0536: *
0537: * @return true if the Folder is deleted successfully
0538: * @exception FolderNotFoundException if this folder does
0539: * not exist
0540: * @exception IllegalStateException if this folder is not in
0541: * the closed state.
0542: * @exception MessagingException
0543: * @see javax.mail.event.FolderEvent
0544: */
0545: public abstract boolean delete(boolean recurse)
0546: throws MessagingException;
0547:
0548: /**
0549: * Rename this Folder. This method will succeed only on a closed
0550: * Folder. <p>
0551: *
0552: * If the rename is successful, a RENAMED FolderEvent is delivered
0553: * to FolderListeners registered on this folder and its containing
0554: * Store.
0555: *
0556: * @param f a folder representing the new name for this Folder
0557: * @return true if the Folder is renamed successfully
0558: * @exception FolderNotFoundException if this folder does
0559: * not exist
0560: * @exception IllegalStateException if this folder is not in
0561: * the closed state.
0562: * @exception MessagingException
0563: * @see javax.mail.event.FolderEvent
0564: */
0565: public abstract boolean renameTo(Folder f)
0566: throws MessagingException;
0567:
0568: /**
0569: * The Folder is read only. The state and contents of this
0570: * folder cannot be modified.
0571: */
0572: public static final int READ_ONLY = 1;
0573:
0574: /**
0575: * The state and contents of this folder can be modified.
0576: */
0577: public static final int READ_WRITE = 2;
0578:
0579: /**
0580: * Open this Folder. This method is valid only on Folders that
0581: * can contain Messages and that are closed. <p>
0582: *
0583: * If this folder is opened successfully, an OPENED ConnectionEvent
0584: * is delivered to any ConnectionListeners registered on this
0585: * Folder. <p>
0586: *
0587: * The effect of opening multiple connections to the same folder
0588: * on a specifc Store is implementation dependent. Some implementations
0589: * allow multiple readers, but only one writer. Others allow
0590: * multiple writers as well as readers.
0591: *
0592: * @param mode open the Folder READ_ONLY or READ_WRITE
0593: * @exception FolderNotFoundException if this folder does
0594: * not exist.
0595: * @exception IllegalStateException if this folder is not in
0596: * the closed state.
0597: * @exception MessagingException
0598: * @see #READ_ONLY
0599: * @see #READ_WRITE
0600: * @see #getType()
0601: * @see javax.mail.event.ConnectionEvent
0602: */
0603: public abstract void open(int mode) throws MessagingException;
0604:
0605: /**
0606: * Close this Folder. This method is valid only on open Folders. <p>
0607: *
0608: * A CLOSED ConnectionEvent is delivered to any ConnectionListeners
0609: * registered on this Folder. Note that the folder is closed even
0610: * if this method terminates abnormally by throwing a
0611: * MessagingException.
0612: *
0613: * @param expunge expunges all deleted messages if this flag is true
0614: * @exception IllegalStateException if this folder is not opened
0615: * @exception MessagingException
0616: * @see javax.mail.event.ConnectionEvent
0617: */
0618: public abstract void close(boolean expunge)
0619: throws MessagingException;
0620:
0621: /**
0622: * Indicates whether this Folder is in the 'open' state.
0623: * @return true if this Folder is in the 'open' state.
0624: */
0625: public abstract boolean isOpen();
0626:
0627: /**
0628: * Return the open mode of this folder. Returns
0629: * <code>Folder.READ_ONLY</code>, <code>Folder.READ_WRITE</code>,
0630: * or -1 if the open mode is not known (usually only because an older
0631: * <code>Folder</code> provider has not been updated to use this new
0632: * method).
0633: *
0634: * @exception IllegalStateException if this folder is not opened
0635: * @return the open mode of this folder
0636: * @since JavaMail 1.1
0637: */
0638: public int getMode() {
0639: if (!isOpen())
0640: throw new IllegalStateException("Folder not open");
0641: return mode;
0642: }
0643:
0644: /**
0645: * Get the permanent flags supported by this Folder. Returns a Flags
0646: * object that contains all the flags supported. <p>
0647: *
0648: * The special flag <code>Flags.USER </code> indicates that this Folder
0649: * supports arbitrary user-defined flags. <p>
0650: *
0651: * The supported permanent flags for a folder may not be available
0652: * until the folder is opened.
0653: *
0654: * @return permanent flags, or null if not known
0655: */
0656: public abstract Flags getPermanentFlags();
0657:
0658: /**
0659: * Get total number of messages in this Folder. <p>
0660: *
0661: * This method can be invoked on a closed folder. However, note
0662: * that for some folder implementations, getting the total message
0663: * count can be an expensive operation involving actually opening
0664: * the folder. In such cases, a provider can choose not to support
0665: * this functionality in the closed state, in which case this method
0666: * must return -1. <p>
0667: *
0668: * Clients invoking this method on a closed folder must be aware
0669: * that this is a potentially expensive operation. Clients must
0670: * also be prepared to handle a return value of -1 in this case.
0671: *
0672: * @return total number of messages. -1 may be returned
0673: * by certain implementations if this method is
0674: * invoked on a closed folder.
0675: * @exception FolderNotFoundException if this folder does
0676: * not exist.
0677: * @exception MessagingException
0678: */
0679: public abstract int getMessageCount() throws MessagingException;
0680:
0681: /**
0682: * Get the number of new messages in this Folder. <p>
0683: *
0684: * This method can be invoked on a closed folder. However, note
0685: * that for some folder implementations, getting the new message
0686: * count can be an expensive operation involving actually opening
0687: * the folder. In such cases, a provider can choose not to support
0688: * this functionality in the closed state, in which case this method
0689: * must return -1. <p>
0690: *
0691: * Clients invoking this method on a closed folder must be aware
0692: * that this is a potentially expensive operation. Clients must
0693: * also be prepared to handle a return value of -1 in this case. <p>
0694: *
0695: * This implementation returns -1 if this folder is closed. Else
0696: * this implementation gets each Message in the folder using
0697: * <code>getMessage(int)</code> and checks whether its
0698: * <code>RECENT</code> flag is set. The total number of messages
0699: * that have this flag set is returned.
0700: *
0701: * @return number of new messages. -1 may be returned
0702: * by certain implementations if this method is
0703: * invoked on a closed folder.
0704: * @exception FolderNotFoundException if this folder does
0705: * not exist.
0706: * @exception MessagingException
0707: */
0708: public synchronized int getNewMessageCount()
0709: throws MessagingException {
0710: if (!isOpen())
0711: return -1;
0712:
0713: int newmsgs = 0;
0714: int total = getMessageCount();
0715: for (int i = 1; i <= total; i++) {
0716: try {
0717: if (getMessage(i).isSet(Flags.Flag.RECENT))
0718: newmsgs++;
0719: } catch (MessageRemovedException me) {
0720: // This is an expunged message, ignore it.
0721: continue;
0722: }
0723: }
0724: return newmsgs;
0725: }
0726:
0727: /**
0728: * Get the total number of unread messages in this Folder. <p>
0729: *
0730: * This method can be invoked on a closed folder. However, note
0731: * that for some folder implementations, getting the unread message
0732: * count can be an expensive operation involving actually opening
0733: * the folder. In such cases, a provider can choose not to support
0734: * this functionality in the closed state, in which case this method
0735: * must return -1. <p>
0736: *
0737: * Clients invoking this method on a closed folder must be aware
0738: * that this is a potentially expensive operation. Clients must
0739: * also be prepared to handle a return value of -1 in this case. <p>
0740: *
0741: * This implementation returns -1 if this folder is closed. Else
0742: * this implementation gets each Message in the folder using
0743: * <code>getMessage(int)</code> and checks whether its
0744: * <code>SEEN</code> flag is set. The total number of messages
0745: * that do not have this flag set is returned.
0746: *
0747: * @return total number of unread messages. -1 may be returned
0748: * by certain implementations if this method is
0749: * invoked on a closed folder.
0750: * @exception FolderNotFoundException if this folder does
0751: * not exist.
0752: * @exception MessagingException
0753: */
0754: public synchronized int getUnreadMessageCount()
0755: throws MessagingException {
0756: if (!isOpen())
0757: return -1;
0758:
0759: int unread = 0;
0760: int total = getMessageCount();
0761: for (int i = 1; i <= total; i++) {
0762: try {
0763: if (!getMessage(i).isSet(Flags.Flag.SEEN))
0764: unread++;
0765: } catch (MessageRemovedException me) {
0766: // This is an expunged message, ignore it.
0767: continue;
0768: }
0769: }
0770: return unread;
0771: }
0772:
0773: /**
0774: * Get the number of deleted messages in this Folder. <p>
0775: *
0776: * This method can be invoked on a closed folder. However, note
0777: * that for some folder implementations, getting the deleted message
0778: * count can be an expensive operation involving actually opening
0779: * the folder. In such cases, a provider can choose not to support
0780: * this functionality in the closed state, in which case this method
0781: * must return -1. <p>
0782: *
0783: * Clients invoking this method on a closed folder must be aware
0784: * that this is a potentially expensive operation. Clients must
0785: * also be prepared to handle a return value of -1 in this case. <p>
0786: *
0787: * This implementation returns -1 if this folder is closed. Else
0788: * this implementation gets each Message in the folder using
0789: * <code>getMessage(int)</code> and checks whether its
0790: * <code>DELETED</code> flag is set. The total number of messages
0791: * that have this flag set is returned.
0792: *
0793: * @return number of deleted messages. -1 may be returned
0794: * by certain implementations if this method is
0795: * invoked on a closed folder.
0796: * @exception FolderNotFoundException if this folder does
0797: * not exist.
0798: * @exception MessagingException
0799: * @since JavaMail 1.3
0800: */
0801: public synchronized int getDeletedMessageCount()
0802: throws MessagingException {
0803: if (!isOpen())
0804: return -1;
0805:
0806: int deleted = 0;
0807: int total = getMessageCount();
0808: for (int i = 1; i <= total; i++) {
0809: try {
0810: if (getMessage(i).isSet(Flags.Flag.DELETED))
0811: deleted++;
0812: } catch (MessageRemovedException me) {
0813: // This is an expunged message, ignore it.
0814: continue;
0815: }
0816: }
0817: return deleted;
0818: }
0819:
0820: /**
0821: * Get the Message object corresponding to the given message
0822: * number. A Message object's message number is the relative
0823: * position of this Message in its Folder. Messages are numbered
0824: * starting at 1 through the total number of message in the folder.
0825: * Note that the message number for a particular Message can change
0826: * during a session if other messages in the Folder are deleted and
0827: * the Folder is expunged. <p>
0828: *
0829: * Message objects are light-weight references to the actual message
0830: * that get filled up on demand. Hence Folder implementations are
0831: * expected to provide light-weight Message objects. <p>
0832: *
0833: * Unlike Folder objects, repeated calls to getMessage with the
0834: * same message number will return the same Message object, as
0835: * long as no messages in this folder have been expunged. <p>
0836: *
0837: * Since message numbers can change within a session if the folder
0838: * is expunged , clients are advised not to use message numbers as
0839: * references to messages. Use Message objects instead.
0840: *
0841: * @param msgnum the message number
0842: * @return the Message object
0843: * @see #getMessageCount
0844: * @see #fetch
0845: * @exception FolderNotFoundException if this folder does
0846: * not exist.
0847: * @exception IllegalStateException if this folder is not opened
0848: * @exception IndexOutOfBoundsException if the message number
0849: * is out of range.
0850: * @exception MessagingException
0851: */
0852: public abstract Message getMessage(int msgnum)
0853: throws MessagingException;
0854:
0855: /**
0856: * Get the Message objects for message numbers ranging from start
0857: * through end, both start and end inclusive. Note that message
0858: * numbers start at 1, not 0. <p>
0859: *
0860: * Message objects are light-weight references to the actual message
0861: * that get filled up on demand. Hence Folder implementations are
0862: * expected to provide light-weight Message objects. <p>
0863: *
0864: * This implementation uses getMessage(index) to obtain the required
0865: * Message objects. Note that the returned array must contain
0866: * <code>(end-start+1)</code> Message objects.
0867: *
0868: * @param start the number of the first message
0869: * @param end the number of the last message
0870: * @return the Message objects
0871: * @see #fetch
0872: * @exception FolderNotFoundException if this folder does
0873: * not exist.
0874: * @exception IllegalStateException if this folder is not opened.
0875: * @exception IndexOutOfBoundsException if the start or end
0876: * message numbers are out of range.
0877: * @exception MessagingException
0878: */
0879: public synchronized Message[] getMessages(int start, int end)
0880: throws MessagingException {
0881: Message[] msgs = new Message[end - start + 1];
0882: for (int i = start; i <= end; i++)
0883: msgs[i - start] = getMessage(i);
0884: return msgs;
0885: }
0886:
0887: /**
0888: * Get the Message objects for message numbers specified in
0889: * the array. <p>
0890: *
0891: * Message objects are light-weight references to the actual message
0892: * that get filled up on demand. Hence Folder implementations are
0893: * expected to provide light-weight Message objects. <p>
0894: *
0895: * This implementation uses getMessage(index) to obtain the required
0896: * Message objects. Note that the returned array must contain
0897: * <code>msgnums.length</code> Message objects
0898: *
0899: * @param msgnums the array of message numbers
0900: * @return the array of Message objects.
0901: * @see #fetch
0902: * @exception FolderNotFoundException if this folder does
0903: * not exist.
0904: * @exception IllegalStateException if this folder is not opened.
0905: * @exception IndexOutOfBoundsException if any message number
0906: * in the given array is out of range.
0907: * @exception MessagingException
0908: */
0909: public synchronized Message[] getMessages(int[] msgnums)
0910: throws MessagingException {
0911: int len = msgnums.length;
0912: Message[] msgs = new Message[len];
0913: for (int i = 0; i < len; i++)
0914: msgs[i] = getMessage(msgnums[i]);
0915: return msgs;
0916: }
0917:
0918: /**
0919: * Get all Message objects from this Folder. Returns an empty array
0920: * if the folder is empty.
0921: *
0922: * Clients can use Message objects (instead of sequence numbers)
0923: * as references to the messages within a folder; this method supplies
0924: * the Message objects to the client. Folder implementations are
0925: * expected to provide light-weight Message objects, which get
0926: * filled on demand. <p>
0927: *
0928: * This implementation invokes <code>getMessageCount()</code> to get
0929: * the current message count and then uses <code>getMessage()</code>
0930: * to get Message objects from 1 till the message count.
0931: *
0932: * @return array of Message objects, empty array if folder
0933: * is empty.
0934: * @see #fetch
0935: * @exception FolderNotFoundException if this folder does
0936: * not exist.
0937: * @exception IllegalStateException if this folder is not opened.
0938: * @exception MessagingException
0939: */
0940: public synchronized Message[] getMessages()
0941: throws MessagingException {
0942: if (!isOpen()) // otherwise getMessageCount might return -1
0943: throw new IllegalStateException("Folder not open");
0944: int total = getMessageCount();
0945: Message[] msgs = new Message[total];
0946: for (int i = 1; i <= total; i++)
0947: msgs[i - 1] = getMessage(i);
0948: return msgs;
0949: }
0950:
0951: /**
0952: * Append given Messages to this folder. This method can be
0953: * invoked on a closed Folder. An appropriate MessageCountEvent
0954: * is delivered to any MessageCountListener registered on this
0955: * folder when the messages arrive in the folder. <p>
0956: *
0957: * Folder implementations must not abort this operation if a
0958: * Message in the given message array turns out to be an
0959: * expunged Message.
0960: *
0961: * @param msgs array of Messages to be appended
0962: * @exception FolderNotFoundException if this folder does
0963: * not exist.
0964: * @exception MessagingException if the append failed.
0965: */
0966: public abstract void appendMessages(Message[] msgs)
0967: throws MessagingException;
0968:
0969: /**
0970: * Prefetch the items specified in the FetchProfile for the
0971: * given Messages. <p>
0972: *
0973: * Clients use this method to indicate that the specified items are
0974: * needed en-masse for the given message range. Implementations are
0975: * expected to retrieve these items for the given message range in
0976: * a efficient manner. Note that this method is just a hint to the
0977: * implementation to prefetch the desired items. <p>
0978: *
0979: * An example is a client filling its header-view window with
0980: * the Subject, From and X-mailer headers for all messages in the
0981: * folder.<p>
0982: * <blockquote><pre>
0983: *
0984: * Message[] msgs = folder.getMessages();
0985: *
0986: * FetchProfile fp = new FetchProfile();
0987: * fp.add(FetchProfile.Item.ENVELOPE);
0988: * fp.add("X-mailer");
0989: * folder.fetch(msgs, fp);
0990: *
0991: * for (int i = 0; i < folder.getMessageCount(); i++) {
0992: * display(msg[i].getFrom());
0993: * display(msg[i].getSubject());
0994: * display(msg[i].getHeader("X-mailer"));
0995: * }
0996: *
0997: * </pre></blockquote><p>
0998: *
0999: * The implementation provided here just returns without
1000: * doing anything useful. Providers wanting to provide a real
1001: * implementation for this method should override this method.
1002: *
1003: * @param msgs fetch items for these messages
1004: * @param fp the FetchProfile
1005: * @exception IllegalStateException if this folder is not opened
1006: * @exception MessagingException.
1007: */
1008: public void fetch(Message[] msgs, FetchProfile fp)
1009: throws MessagingException {
1010: return;
1011: }
1012:
1013: /**
1014: * Set the specified flags on the messages specified in the array.
1015: * This will result in appropriate MessageChangedEvents being
1016: * delivered to any MessageChangedListener registered on this
1017: * Message's containing folder. <p>
1018: *
1019: * Note that the specified Message objects <strong>must</strong>
1020: * belong to this folder. Certain Folder implementations can
1021: * optimize the operation of setting Flags for a group of messages,
1022: * so clients might want to use this method, rather than invoking
1023: * <code>Message.setFlags</code> for each Message. <p>
1024: *
1025: * This implementation degenerates to invoking <code>setFlags()</code>
1026: * on each Message object. Specific Folder implementations that can
1027: * optimize this case should do so.
1028: * Also, an implementation must not abort the operation if a Message
1029: * in the array turns out to be an expunged Message.
1030: *
1031: * @param msgs the array of message objects
1032: * @param flag Flags object containing the flags to be set
1033: * @param value set the flags to this boolean value
1034: * @exception IllegalStateException if this folder is not opened
1035: * or if it has been opened READ_ONLY.
1036: * @exception MessagingException
1037: * @see Message#setFlags
1038: * @see javax.mail.event.MessageChangedEvent
1039: */
1040: public synchronized void setFlags(Message[] msgs, Flags flag,
1041: boolean value) throws MessagingException {
1042: for (int i = 0; i < msgs.length; i++) {
1043: try {
1044: msgs[i].setFlags(flag, value);
1045: } catch (MessageRemovedException me) {
1046: // This message is expunged, skip
1047: }
1048: }
1049: }
1050:
1051: /**
1052: * Set the specified flags on the messages numbered from start
1053: * through end, both start and end inclusive. Note that message
1054: * numbers start at 1, not 0.
1055: * This will result in appropriate MessageChangedEvents being
1056: * delivered to any MessageChangedListener registered on this
1057: * Message's containing folder. <p>
1058: *
1059: * Certain Folder implementations can
1060: * optimize the operation of setting Flags for a group of messages,
1061: * so clients might want to use this method, rather than invoking
1062: * <code>Message.setFlags</code> for each Message. <p>
1063: *
1064: * The default implementation uses <code>getMessage(int)</code> to
1065: * get each <code>Message</code> object and then invokes
1066: * <code>setFlags</code> on that object to set the flags.
1067: * Specific Folder implementations that can optimize this case should do so.
1068: * Also, an implementation must not abort the operation if a message
1069: * number refers to an expunged message.
1070: *
1071: * @param start the number of the first message
1072: * @param end the number of the last message
1073: * @param flag Flags object containing the flags to be set
1074: * @param value set the flags to this boolean value
1075: * @exception IllegalStateException if this folder is not opened
1076: * or if it has been opened READ_ONLY.
1077: * @exception IndexOutOfBoundsException if the start or end
1078: * message numbers are out of range.
1079: * @exception MessagingException
1080: * @see Message#setFlags
1081: * @see javax.mail.event.MessageChangedEvent
1082: */
1083: public synchronized void setFlags(int start, int end, Flags flag,
1084: boolean value) throws MessagingException {
1085: for (int i = start; i <= end; i++) {
1086: try {
1087: Message msg = getMessage(i);
1088: msg.setFlags(flag, value);
1089: } catch (MessageRemovedException me) {
1090: // This message is expunged, skip
1091: }
1092: }
1093: }
1094:
1095: /**
1096: * Set the specified flags on the messages whose message numbers
1097: * are in the array.
1098: * This will result in appropriate MessageChangedEvents being
1099: * delivered to any MessageChangedListener registered on this
1100: * Message's containing folder. <p>
1101: *
1102: * Certain Folder implementations can
1103: * optimize the operation of setting Flags for a group of messages,
1104: * so clients might want to use this method, rather than invoking
1105: * <code>Message.setFlags</code> for each Message. <p>
1106: *
1107: * The default implementation uses <code>getMessage(int)</code> to
1108: * get each <code>Message</code> object and then invokes
1109: * <code>setFlags</code> on that object to set the flags.
1110: * Specific Folder implementations that can optimize this case should do so.
1111: * Also, an implementation must not abort the operation if a message
1112: * number refers to an expunged message.
1113: *
1114: * @param msgnums the array of message numbers
1115: * @param flag Flags object containing the flags to be set
1116: * @param value set the flags to this boolean value
1117: * @exception IllegalStateException if this folder is not opened
1118: * or if it has been opened READ_ONLY.
1119: * @exception IndexOutOfBoundsException if any message number
1120: * in the given array is out of range.
1121: * @exception MessagingException
1122: * @see Message#setFlags
1123: * @see javax.mail.event.MessageChangedEvent
1124: */
1125: public synchronized void setFlags(int[] msgnums, Flags flag,
1126: boolean value) throws MessagingException {
1127: for (int i = 0; i < msgnums.length; i++) {
1128: try {
1129: Message msg = getMessage(msgnums[i]);
1130: msg.setFlags(flag, value);
1131: } catch (MessageRemovedException me) {
1132: // This message is expunged, skip
1133: }
1134: }
1135: }
1136:
1137: /**
1138: * Copy the specified Messages from this Folder into another
1139: * Folder. This operation appends these Messages to the
1140: * destination Folder. The destination Folder does not have to
1141: * be opened. An appropriate MessageCountEvent
1142: * is delivered to any MessageCountListener registered on the
1143: * destination folder when the messages arrive in the folder. <p>
1144: *
1145: * Note that the specified Message objects <strong>must</strong>
1146: * belong to this folder. Folder implementations might be able
1147: * to optimize this method by doing server-side copies. <p>
1148: *
1149: * This implementation just invokes <code>appendMessages()</code>
1150: * on the destination folder to append the given Messages. Specific
1151: * folder implementations that support server-side copies should
1152: * do so, if the destination folder's Store is the same as this
1153: * folder's Store.
1154: * Also, an implementation must not abort the operation if a
1155: * Message in the array turns out to be an expunged Message.
1156: *
1157: * @param msgs the array of message objects
1158: * @param folder the folder to copy the messages to
1159: * @exception FolderNotFoundException if the destination
1160: * folder does not exist.
1161: * @exception IllegalStateException if this folder is not opened.
1162: * @exception MessagingException
1163: * @see #appendMessages
1164: */
1165: public void copyMessages(Message[] msgs, Folder folder)
1166: throws MessagingException {
1167: if (!folder.exists())
1168: throw new FolderNotFoundException(folder.getFullName()
1169: + " does not exist", folder);
1170:
1171: folder.appendMessages(msgs);
1172: }
1173:
1174: /**
1175: * Expunge (permanently remove) messages marked DELETED. Returns an
1176: * array containing the expunged message objects. The
1177: * <code>getMessageNumber</code> method
1178: * on each of these message objects returns that Message's original
1179: * (that is, prior to the expunge) sequence number. A MessageCountEvent
1180: * containing the expunged messages is delivered to any
1181: * MessageCountListeners registered on the folder. <p>
1182: *
1183: * Expunge causes the renumbering of Message objects subsequent to
1184: * the expunged messages. Clients that use message numbers as
1185: * references to messages should be aware of this and should be
1186: * prepared to deal with the situation (probably by flushing out
1187: * existing message number caches and reloading them). Because of
1188: * this complexity, it is better for clients to use Message objects
1189: * as references to messages, rather than message numbers. Any
1190: * expunged Messages objects still have to be pruned, but other
1191: * Messages in that folder are not affected by the expunge. <p>
1192: *
1193: * After a message is expunged, only the <code>isExpunged</code> and
1194: * <code>getMessageNumber</code> methods are still valid on the
1195: * corresponding Message object; other methods may throw
1196: * <code>MessageRemovedException</code>
1197: *
1198: * @return array of expunged Message objects
1199: * @exception FolderNotFoundException if this folder does not
1200: * exist
1201: * @exception IllegalStateException if this folder is not opened.
1202: * @exception MessagingException
1203: * @see Message#isExpunged
1204: * @see javax.mail.event.MessageCountEvent
1205: */
1206: public abstract Message[] expunge() throws MessagingException;
1207:
1208: /**
1209: * Search this Folder for messages matching the specified
1210: * search criterion. Returns an array containing the matching
1211: * messages . Returns an empty array if no matches were found. <p>
1212: *
1213: * This implementation invokes
1214: * <code>search(term, getMessages())</code>, to apply the search
1215: * over all the messages in this folder. Providers that can implement
1216: * server-side searching might want to override this method to provide
1217: * a more efficient implementation.
1218: *
1219: * @param term the search criterion
1220: * @return array of matching messages
1221: * @exception javax.mail.search.SearchException if the search
1222: * term is too complex for the implementation to handle.
1223: * @exception FolderNotFoundException if this folder does
1224: * not exist.
1225: * @exception IllegalStateException if this folder is not opened.
1226: * @exception MessagingException
1227: * @see javax.mail.search.SearchTerm
1228: */
1229: public Message[] search(SearchTerm term) throws MessagingException {
1230: return search(term, getMessages());
1231: }
1232:
1233: /**
1234: * Search the given array of messages for those that match the
1235: * specified search criterion. Returns an array containing the
1236: * matching messages. Returns an empty array if no matches were
1237: * found. <p>
1238: *
1239: * Note that the specified Message objects <strong>must</strong>
1240: * belong to this folder. <p>
1241: *
1242: * This implementation iterates through the given array of messages,
1243: * and applies the search criterion on each message by calling
1244: * its <code>match()</code> method with the given term. The
1245: * messages that succeed in the match are returned. Providers
1246: * that can implement server-side searching might want to override
1247: * this method to provide a more efficient implementation. If the
1248: * search term is too complex or contains user-defined terms that
1249: * cannot be executed on the server, providers may elect to either
1250: * throw a SearchException or degenerate to client-side searching by
1251: * calling <code>super.search()</code> to invoke this implementation.
1252: *
1253: * @param term the search criterion
1254: * @param msgs the messages to be searched
1255: * @return array of matching messages
1256: * @exception javax.mail.search.SearchException if the search
1257: * term is too complex for the implementation to handle.
1258: * @exception IllegalStateException if this folder is not opened
1259: * @exception MessagingException
1260: * @see javax.mail.search.SearchTerm
1261: */
1262: public Message[] search(SearchTerm term, Message[] msgs)
1263: throws MessagingException {
1264: Vector matchedMsgs = new Vector();
1265:
1266: // Run thru the given messages
1267: for (int i = 0; i < msgs.length; i++) {
1268: try {
1269: if (msgs[i].match(term)) // matched
1270: matchedMsgs.addElement(msgs[i]); // add it
1271: } catch (MessageRemovedException mrex) {
1272: }
1273: }
1274:
1275: Message[] m = new Message[matchedMsgs.size()];
1276: matchedMsgs.copyInto(m);
1277: return m;
1278: }
1279:
1280: /*
1281: * The set of listeners are stored in Vectors appropriate to their
1282: * type. We mark all listener Vectors as "volatile" because, while
1283: * we initialize them inside this folder's synchronization lock,
1284: * they are accessed (checked for null) in the "notify" methods,
1285: * which can't be synchronized due to lock ordering constraints.
1286: * Since the listener fields (the handles on the Vector objects)
1287: * are only ever set, and are never cleared, we believe this is
1288: * safe. The code that dispatches the notifications will either
1289: * see the null and assume there are no listeners or will see the
1290: * Vector and will process the listeners. There's an inherent race
1291: * between adding a listener and notifying the listeners; the lack
1292: * of synchronization during notification does not make the race
1293: * condition significantly worse. If one thread is setting a
1294: * listener at the "same" time an event is being dispatched, the
1295: * dispatch code might not see the listener right away. The
1296: * dispatch code doesn't have to worry about the Vector handle
1297: * being set to null, and thus using an out-of-date set of
1298: * listeners, because we never set the field to null.
1299: */
1300:
1301: // Vector of connection listeners.
1302: private volatile Vector connectionListeners = null;
1303:
1304: /**
1305: * Add a listener for Connection events on this Folder. <p>
1306: *
1307: * The implementation provided here adds this listener
1308: * to an internal list of ConnectionListeners.
1309: *
1310: * @param l the Listener for Connection events
1311: * @see javax.mail.event.ConnectionEvent
1312: */
1313: public synchronized void addConnectionListener(ConnectionListener l) {
1314: if (connectionListeners == null)
1315: connectionListeners = new Vector();
1316: connectionListeners.addElement(l);
1317: }
1318:
1319: /**
1320: * Remove a Connection event listener. <p>
1321: *
1322: * The implementation provided here removes this listener
1323: * from the internal list of ConnectionListeners.
1324: *
1325: * @param l the listener
1326: * @see #addConnectionListener
1327: */
1328: public synchronized void removeConnectionListener(
1329: ConnectionListener l) {
1330: if (connectionListeners != null)
1331: connectionListeners.removeElement(l);
1332: }
1333:
1334: /**
1335: * Notify all ConnectionListeners. Folder implementations are
1336: * expected to use this method to broadcast connection events. <p>
1337: *
1338: * The provided implementation queues the event into
1339: * an internal event queue. An event dispatcher thread dequeues
1340: * events from the queue and dispatches them to the registered
1341: * ConnectionListeners. Note that the event dispatching occurs
1342: * in a separate thread, thus avoiding potential deadlock problems.
1343: *
1344: * @param type the ConnectionEvent type
1345: * @see javax.mail.event.ConnectionEvent
1346: */
1347: protected void notifyConnectionListeners(int type) {
1348: if (connectionListeners != null) {
1349: ConnectionEvent e = new ConnectionEvent(this , type);
1350: queueEvent(e, connectionListeners);
1351: }
1352:
1353: /* Fix for broken JDK1.1.x Garbage collector :
1354: * The 'conservative' GC in JDK1.1.x occasionally fails to
1355: * garbage-collect Threads which are in the wait state.
1356: * This would result in thread (and consequently memory) leaks.
1357: *
1358: * We attempt to fix this by sending a 'terminator' event
1359: * to the queue, after we've sent the CLOSED event. The
1360: * terminator event causes the event-dispatching thread to
1361: * self destruct.
1362: */
1363: if (type == ConnectionEvent.CLOSED)
1364: terminateQueue();
1365: }
1366:
1367: // Vector of folder listeners
1368: private volatile Vector folderListeners = null;
1369:
1370: /**
1371: * Add a listener for Folder events on this Folder. <p>
1372: *
1373: * The implementation provided here adds this listener
1374: * to an internal list of FolderListeners.
1375: *
1376: * @param l the Listener for Folder events
1377: * @see javax.mail.event.FolderEvent
1378: */
1379: public synchronized void addFolderListener(FolderListener l) {
1380: if (folderListeners == null)
1381: folderListeners = new Vector();
1382: folderListeners.addElement(l);
1383: }
1384:
1385: /**
1386: * Remove a Folder event listener. <p>
1387: *
1388: * The implementation provided here removes this listener
1389: * from the internal list of FolderListeners.
1390: *
1391: * @param l the listener
1392: * @see #addFolderListener
1393: */
1394: public synchronized void removeFolderListener(FolderListener l) {
1395: if (folderListeners != null)
1396: folderListeners.removeElement(l);
1397: }
1398:
1399: /**
1400: * Notify all FolderListeners registered on this Folder and
1401: * this folder's Store. Folder implementations are expected
1402: * to use this method to broadcast Folder events. <p>
1403: *
1404: * The implementation provided here queues the event into
1405: * an internal event queue. An event dispatcher thread dequeues
1406: * events from the queue and dispatches them to the
1407: * FolderListeners registered on this folder. The implementation
1408: * also invokes <code>notifyFolderListeners</code> on this folder's
1409: * Store to notify any FolderListeners registered on the store.
1410: *
1411: * @param type type of FolderEvent
1412: * @see #notifyFolderRenamedListeners
1413: */
1414: protected void notifyFolderListeners(int type) {
1415: if (folderListeners != null) {
1416: FolderEvent e = new FolderEvent(this , this , type);
1417: queueEvent(e, folderListeners);
1418: }
1419: store.notifyFolderListeners(type, this );
1420: }
1421:
1422: /**
1423: * Notify all FolderListeners registered on this Folder and
1424: * this folder's Store about the renaming of this folder.
1425: * Folder implementations are expected to use this method to
1426: * broadcast Folder events indicating the renaming of folders. <p>
1427: *
1428: * The implementation provided here queues the event into
1429: * an internal event queue. An event dispatcher thread dequeues
1430: * events from the queue and dispatches them to the
1431: * FolderListeners registered on this folder. The implementation
1432: * also invokes <code>notifyFolderRenamedListeners</code> on this
1433: * folder's Store to notify any FolderListeners registered on the store.
1434: *
1435: * @param folder Folder representing the new name.
1436: * @see #notifyFolderListeners
1437: * @since JavaMail 1.1
1438: */
1439: protected void notifyFolderRenamedListeners(Folder folder) {
1440: if (folderListeners != null) {
1441: FolderEvent e = new FolderEvent(this , this , folder,
1442: FolderEvent.RENAMED);
1443: queueEvent(e, folderListeners);
1444: }
1445: store.notifyFolderRenamedListeners(this , folder);
1446: }
1447:
1448: // Vector of MessageCount listeners
1449: private volatile Vector messageCountListeners = null;
1450:
1451: /**
1452: * Add a listener for MessageCount events on this Folder. <p>
1453: *
1454: * The implementation provided here adds this listener
1455: * to an internal list of MessageCountListeners.
1456: *
1457: * @param l the Listener for MessageCount events
1458: * @see javax.mail.event.MessageCountEvent
1459: */
1460: public synchronized void addMessageCountListener(
1461: MessageCountListener l) {
1462: if (messageCountListeners == null)
1463: messageCountListeners = new Vector();
1464: messageCountListeners.addElement(l);
1465: }
1466:
1467: /**
1468: * Remove a MessageCount listener. <p>
1469: *
1470: * The implementation provided here removes this listener
1471: * from the internal list of MessageCountListeners.
1472: *
1473: * @param l the listener
1474: * @see #addMessageCountListener
1475: */
1476: public synchronized void removeMessageCountListener(
1477: MessageCountListener l) {
1478: if (messageCountListeners != null)
1479: messageCountListeners.removeElement(l);
1480: }
1481:
1482: /**
1483: * Notify all MessageCountListeners about the addition of messages
1484: * into this folder. Folder implementations are expected to use this
1485: * method to broadcast MessageCount events for indicating arrival of
1486: * new messages. <p>
1487: *
1488: * The provided implementation queues the event into
1489: * an internal event queue. An event dispatcher thread dequeues
1490: * events from the queue and dispatches them to the registered
1491: * MessageCountListeners. Note that the event dispatching occurs
1492: * in a separate thread, thus avoiding potential deadlock problems.
1493: */
1494: protected void notifyMessageAddedListeners(Message[] msgs) {
1495: if (messageCountListeners == null)
1496: return;
1497:
1498: MessageCountEvent e = new MessageCountEvent(this ,
1499: MessageCountEvent.ADDED, false, msgs);
1500:
1501: queueEvent(e, messageCountListeners);
1502: }
1503:
1504: /**
1505: * Notify all MessageCountListeners about the removal of messages
1506: * from this Folder. Folder implementations are expected to use this
1507: * method to broadcast MessageCount events indicating removal of
1508: * messages. <p>
1509: *
1510: * The provided implementation queues the event into
1511: * an internal event queue. An event dispatcher thread dequeues
1512: * events from the queue and dispatches them to the registered
1513: * MessageCountListeners. Note that the event dispatching occurs
1514: * in a separate thread, thus avoiding potential deadlock problems.
1515: */
1516: protected void notifyMessageRemovedListeners(boolean removed,
1517: Message[] msgs) {
1518: if (messageCountListeners == null)
1519: return;
1520:
1521: MessageCountEvent e = new MessageCountEvent(this ,
1522: MessageCountEvent.REMOVED, removed, msgs);
1523: queueEvent(e, messageCountListeners);
1524: }
1525:
1526: // Vector of MessageChanged listeners.
1527: private volatile Vector messageChangedListeners = null;
1528:
1529: /**
1530: * Add a listener for MessageChanged events on this Folder. <p>
1531: *
1532: * The implementation provided here adds this listener
1533: * to an internal list of MessageChangedListeners.
1534: *
1535: * @param l the Listener for MessageChanged events
1536: * @see javax.mail.event.MessageChangedEvent
1537: */
1538: public synchronized void addMessageChangedListener(
1539: MessageChangedListener l) {
1540: if (messageChangedListeners == null)
1541: messageChangedListeners = new Vector();
1542: messageChangedListeners.addElement(l);
1543: }
1544:
1545: /**
1546: * Remove a MessageChanged listener. <p>
1547: *
1548: * The implementation provided here removes this listener
1549: * from the internal list of MessageChangedListeners.
1550: *
1551: * @param l the listener
1552: * @see #addMessageChangedListener
1553: */
1554: public synchronized void removeMessageChangedListener(
1555: MessageChangedListener l) {
1556: if (messageChangedListeners != null)
1557: messageChangedListeners.removeElement(l);
1558: }
1559:
1560: /**
1561: * Notify all MessageChangedListeners. Folder implementations are
1562: * expected to use this method to broadcast MessageChanged events. <p>
1563: *
1564: * The provided implementation queues the event into
1565: * an internal event queue. An event dispatcher thread dequeues
1566: * events from the queue and dispatches them to registered
1567: * MessageChangedListeners. Note that the event dispatching occurs
1568: * in a separate thread, thus avoiding potential deadlock problems.
1569: */
1570: protected void notifyMessageChangedListeners(int type, Message msg) {
1571: if (messageChangedListeners == null)
1572: return;
1573:
1574: MessageChangedEvent e = new MessageChangedEvent(this , type, msg);
1575: queueEvent(e, messageChangedListeners);
1576: }
1577:
1578: /*
1579: * The queue of events to be delivered.
1580: */
1581: private EventQueue q;
1582:
1583: /*
1584: * A lock for creating the EventQueue object. Only one thread should
1585: * create an EventQueue for this folder. We can't synchronize on the
1586: * folder's lock because that would violate the locking hierarchy in
1587: * some cases. For details, see the IMAP provider.
1588: */
1589: private Object qLock = new Object();
1590:
1591: /*
1592: * Add the event and vector of listeners to the queue to be delivered.
1593: */
1594: private void queueEvent(MailEvent event, Vector vector) {
1595: // synchronize creation of the event queue
1596: synchronized (qLock) {
1597: if (q == null)
1598: q = new EventQueue();
1599: }
1600:
1601: /*
1602: * Copy the vector in order to freeze the state of the set
1603: * of EventListeners the event should be delivered to prior
1604: * to delivery. This ensures that any changes made to the
1605: * Vector from a target listener's method during the delivery
1606: * of this event will not take effect until after the event is
1607: * delivered.
1608: */
1609: Vector v = (Vector) vector.clone();
1610: q.enqueue(event, v);
1611: }
1612:
1613: static class TerminatorEvent extends MailEvent {
1614: private static final long serialVersionUID = 3765761925441296565L;
1615:
1616: TerminatorEvent() {
1617: super (new Object());
1618: }
1619:
1620: public void dispatch(Object listener) {
1621: // Kill the event dispatching thread.
1622: Thread.currentThread().interrupt();
1623: }
1624: }
1625:
1626: // Dispatch the terminator
1627: private void terminateQueue() {
1628: synchronized (qLock) {
1629: if (q != null) {
1630: Vector dummyListeners = new Vector();
1631: dummyListeners.setSize(1); // need atleast one listener
1632: q.enqueue(new TerminatorEvent(), dummyListeners);
1633: q = null;
1634: }
1635: }
1636: }
1637:
1638: protected void finalize() throws Throwable {
1639: super .finalize();
1640: terminateQueue();
1641: }
1642:
1643: /**
1644: * override the default toString(), it will return the String
1645: * from Folder.getFullName() or if that is null, it will use
1646: * the default toString() behavior.
1647: */
1648:
1649: public String toString() {
1650: String s = getFullName();
1651: if (s != null)
1652: return s;
1653: else
1654: return super.toString();
1655: }
1656: }
|