FileDocCategorySizeDatePackage
MessageCache.javaAPI DocJavaMail 1.4.313267Tue Nov 17 10:38:10 GMT 2009com.sun.mail.imap

MessageCache

public class MessageCache extends Object
A cache of IMAPMessage objects along with the mapping from message number to IMAP sequence number. All operations on this object are protected by the messageCacheLock in IMAPFolder.

Fields Summary
private IMAPMessage[]
messages
private int[]
seqnums
private int
size
private IMAPFolder
folder
The folder these messages belong to.
private boolean
debug
private PrintStream
out
private static final int
SLOP
Grow the array by at least this much, to avoid constantly reallocating the array.
Constructors Summary
MessageCache(IMAPFolder folder, IMAPStore store, int size)
Construct a new message cache of the indicated size.


                  
          
	this.folder = folder;
	this.debug = store.getMessageCacheDebug();
	this.out = store.getSession().getDebugOut();
	if (debug)
	    out.println("DEBUG IMAP MC: create cache of size " + size);
	ensureCapacity(size);
    
Methods Summary
public voidaddMessages(int count)
Add count messages to the cache.

	if (debug)
	    out.println("DEBUG IMAP MC: add " + count + " messages");
	// don't have to do anything other than making sure there's space
	ensureCapacity(size + count);
    
private voidensureCapacity(int newsize)

	if (messages == null)
	    messages = new IMAPMessage[newsize + SLOP];
	else if (messages.length < newsize) {
	    if (debug)
		out.println("DEBUG IMAP MC: expand capacity to " + newsize);
	    IMAPMessage[] newm = new IMAPMessage[newsize + SLOP];
	    System.arraycopy(messages, 0, newm, 0, messages.length);
	    messages = newm;
	    if (seqnums != null) {
		int[] news = new int[newsize + SLOP];
		System.arraycopy(seqnums, 0, news, 0, seqnums.length);
		seqnums = news;
	    }
	} else if (newsize < size) {		// shrinking?
	    // this should never happen
	    if (debug)
		out.println("DEBUG IMAP MC: shrink capacity to " + newsize);
	    for (int msgnum = newsize + 1; msgnum <= size; msgnum++) {
		messages[msgnum-1] = null;
		if (seqnums != null)
		    seqnums[msgnum-1] = -1;
	    }
	}
	size = newsize;
    
public voidexpungeMessage(int seqnum)
Expunge the message with the given sequence number.

	int msgnum = msgnumOf(seqnum);
	if (msgnum < 0) {
	    if (debug)
		out.println("DEBUG IMAP MC: expunge no seqnum " + seqnum);
	    return;		// XXX - should never happen
	}
	IMAPMessage msg = messages[msgnum-1];
	if (msg != null) {
	    if (debug)
		out.println("DEBUG IMAP MC: expunge existing " + msgnum);
	    msg.setExpunged(true);
	}
	if (seqnums == null) {		// time to fill it in
	    if (debug)
		out.println("DEBUG IMAP MC: create seqnums array");
	    seqnums = new int[messages.length];
	    for (int i = 1; i < msgnum; i++)
		seqnums[i-1] = i;
	    seqnums[msgnum - 1] = 0;
	    for (int i = msgnum + 1; i <= seqnums.length; i++)
		seqnums[i-1] = i - 1;
	} else {
	    seqnums[msgnum - 1] = 0;
	    for (int i = msgnum + 1; i <= seqnums.length; i++) {
		assert seqnums[i-1] != 1;
		if (seqnums[i-1] > 0)
		    seqnums[i-1]--;
	    }
	}
    
public com.sun.mail.imap.IMAPMessagegetMessage(int msgnum)
Get the message object for the indicated message number. If the message object hasn't been created, create it.

	// check range
	if (msgnum < 1 || msgnum > size)
	    throw new ArrayIndexOutOfBoundsException(
				"message number out of bounds");
	IMAPMessage msg = messages[msgnum-1];
	if (msg == null) {
	    if (debug)
		out.println("DEBUG IMAP MC: create message number " + msgnum);
	    msg = new IMAPMessage(folder, msgnum);
	    messages[msgnum-1] = msg;
	    // mark message expunged if no seqnum
	    if (seqnumOf(msgnum) <= 0) {
		if (debug)
		    out.println("DEBUG IMAP MC: it's expunged!");
		msg.setExpunged(true);
	    }
	}
	return msg;
    
public com.sun.mail.imap.IMAPMessagegetMessageBySeqnum(int seqnum)
Get the message object for the indicated sequence number. If the message object hasn't been created, create it. Return null if there's no message with that sequence number.

	int msgnum = msgnumOf(seqnum);
	if (msgnum < 0) {		// XXX - < 1 ?
	    if (debug)
		out.println("DEBUG IMAP MC: no message seqnum " + seqnum);
	    return null;
	} else
	    return getMessage(msgnum);
    
private intmsgnumOf(int seqnum)
Return the message number for the given sequence number.

	if (seqnums == null)
	    return seqnum;
	if (seqnum < 1) {		// should never happen
	    if (debug)
		out.println("DEBUG IMAP MC: bad seqnum " + seqnum);
	    return -1;
	}
	for (int msgnum = seqnum; msgnum <= size; msgnum++) {
	    if (seqnums[msgnum-1] == seqnum)
		return msgnum;
	    if (seqnums[msgnum-1] > seqnum)
		break;		// message doesn't exist
	}
	return -1;
    
public com.sun.mail.imap.IMAPMessage[]removeExpungedMessages()
Remove all the expunged messages from the array, returning a list of removed message objects.

	if (debug)
	    out.println("DEBUG IMAP MC: remove expunged messages");
	List mlist = new ArrayList();	// list of expunged messages

	/*
	 * Walk through the array compressing it by copying
	 * higher numbered messages further down in the array,
	 * effectively removing expunged messages from the array.
	 * oldnum is the index we use to walk through the array.
	 * newnum is the index where we copy the next valid message.
	 * oldnum == newnum until we encounter an expunged message.
	 */
	int oldnum = 1;
	int newnum = 1;
	while (oldnum <= size) {
	    // is message expunged?
	    if (seqnumOf(oldnum) <= 0) {
		IMAPMessage m = getMessage(oldnum);
		mlist.add(m);
	    } else {
		// keep this message
		if (newnum != oldnum) {
		    // move message down in the array (compact array)
		    messages[newnum-1] = messages[oldnum-1];
		    if (messages[newnum-1] != null)
			messages[newnum-1].setMessageNumber(newnum);
		}
		newnum++;
	    }
	    oldnum++;
	}
	seqnums = null;
	shrink(newnum, oldnum);

	IMAPMessage[] rmsgs = new IMAPMessage[mlist.size()];
	if (debug)
	    out.println("DEBUG IMAP MC: return " + rmsgs.length);
	mlist.toArray(rmsgs);
	return rmsgs;
    
public com.sun.mail.imap.IMAPMessage[]removeExpungedMessages(Message[] msgs)
Remove expunged messages in msgs from the array, returning a list of removed message objects. All messages in msgs must be IMAPMessage objects from this folder.

	if (debug)
	    out.println("DEBUG IMAP MC: remove expunged messages");
	List mlist = new ArrayList();	// list of expunged messages

	/*
	 * Copy the message numbers of the expunged messages into
	 * a separate array and sort the array to make it easier to
	 * process later.
	 */
	int[] mnum = new int[msgs.length];
	for (int i = 0; i < msgs.length; i++)
	    mnum[i] = msgs[i].getMessageNumber();
	Arrays.sort(mnum);

	/*
	 * Walk through the array compressing it by copying
	 * higher numbered messages further down in the array,
	 * effectively removing expunged messages from the array.
	 * oldnum is the index we use to walk through the array.
	 * newnum is the index where we copy the next valid message.
	 * oldnum == newnum until we encounter an expunged message.
	 *
	 * Even though we know the message number of the first possibly
	 * expunged message, we still start scanning at message number 1
	 * so that we can check whether there's any message whose
	 * sequence number is different than its message number.  If there
	 * is, we can't throw away the seqnums array when we're done.
	 */
	int oldnum = 1;
	int newnum = 1;
	int mnumi = 0;		// index into mnum
	boolean keepSeqnums = false;
	while (oldnum <= size) {
	    /*
	     * Are there still expunged messsages in msgs to consider,
	     * and is the message we're considering the next one in the
	     * list, and is it expunged?
	     */
	    if (mnumi < mnum.length &&
		    oldnum == mnum[mnumi] &&
		    seqnumOf(oldnum) <= 0) {
		IMAPMessage m = getMessage(oldnum);
		mlist.add(m);
		/*
		 * Just in case there are duplicate entries in the msgs array,
		 * we keep advancing mnumi past any duplicates, but of course
		 * stop when we get to the end of the array.
		 */
		while (mnumi < mnum.length && mnum[mnumi] <= oldnum)
		    mnumi++;	// consider next message in array
	    } else {
		// keep this message
		if (newnum != oldnum) {
		    // move message down in the array (compact array)
		    messages[newnum-1] = messages[oldnum-1];
		    if (messages[newnum-1] != null)
			messages[newnum-1].setMessageNumber(newnum);
		    if (seqnums != null)
			seqnums[newnum-1] = seqnums[oldnum-1];
		}
		if (seqnums != null && seqnums[newnum-1] != newnum)
		    keepSeqnums = true;
		newnum++;
	    }
	    oldnum++;
	}

	if (!keepSeqnums)
	    seqnums = null;
	shrink(newnum, oldnum);

	IMAPMessage[] rmsgs = new IMAPMessage[mlist.size()];
	if (debug)
	    out.println("DEBUG IMAP MC: return " + rmsgs.length);
	mlist.toArray(rmsgs);
	return rmsgs;
    
public intseqnumOf(int msgnum)
Return the sequence number for the given message number.

	if (seqnums == null)
	    return msgnum;
	else
	    return seqnums[msgnum-1];
    
private voidshrink(int newend, int oldend)
Shrink the messages and seqnums arrays. newend is one past last valid element. oldend is one past the previous last valid element.

	size = newend - 1;
	if (debug)
	    out.println("DEBUG IMAP MC: size now " + size);
	if (size == 0) {	// no messages left
	    messages = null;
	    seqnums = null;
	} else if (size > SLOP && size < messages.length / 2) {
	    // if array shrinks by too much, reallocate it
	    if (debug)
		out.println("DEBUG IMAP MC: reallocate array");
	    IMAPMessage[] newm = new IMAPMessage[size + SLOP];
	    System.arraycopy(messages, 0, newm, 0, size);
	    messages = newm;
	    if (seqnums != null) {
		int[] news = new int[size + SLOP];
		System.arraycopy(seqnums, 0, news, 0, size);
		seqnums = news;
	    }
	} else {
	    if (debug)
		out.println("DEBUG IMAP MC: clean " + newend + " to " + oldend);
	    // clear out unused entries in array
	    for (int msgnum = newend; msgnum < oldend; msgnum++) {
		messages[msgnum-1] = null;
		if (seqnums != null)
		    seqnums[msgnum-1] = 0;
	    }
	}
    
public intsize()
Size of cache.

	return size;