001: /***
002: * jwma Java WebMail
003: * Copyright (c) 2000-2003 jwma team
004: *
005: * jwma is free software; you can distribute and use this source
006: * under the terms of the BSD-style license received along with
007: * the distribution.
008: ***/package dtw.webmail.model;
009:
010: import java.util.*;
011: import java.io.*;
012: import javax.mail.*;
013: import javax.mail.internet.*;
014:
015: import org.apache.log4j.Logger;
016:
017: import dtw.webmail.*;
018: import dtw.webmail.util.*;
019:
020: /**
021: * Class implementing a list for <tt>JwmaMessageInfo</tt>
022: * instances.
023: * It has caching functionality, which reduces the need to
024: * reconstruct the list after moving and deleting messages.
025: *
026: * @author Dieter Wimberger
027: * @version 0.9.7 07/02/2003
028: */
029: public class JwmaMessageInfoListImpl {
030:
031: //logging
032: private static Logger log = Logger
033: .getLogger(JwmaMessageInfoListImpl.class);
034:
035: //instance attributes
036: protected List m_MessageInfos;
037: protected boolean m_HasDeleted = false;
038: protected int m_LastSortCriteria = MessageSortCriterias.NUMBER_NUMERICAL;
039:
040: /**
041: * Constructs a new <tt>JwmaMessagListImpl</tt>.
042: */
043: private JwmaMessageInfoListImpl() {
044: }//JwmaMessageInfoListImpl
045:
046: /**
047: * Returns the size of this list.
048: *
049: * @return the size of this list.
050: */
051: public int size() {
052: return m_MessageInfos.size();
053: }//size
054:
055: /**
056: * Returns an array of <tt>JwmaMessageInfo[]</tt> listing
057: * the info's stored in this list.
058: *
059: * @return an array of <tt>JwmaMessageInfo</tt> instances.
060: *
061: * @see dtw.webmail.model.JwmaMessageInfoListImpl#listMessageInfos()
062: */
063: public JwmaMessageInfoImpl[] listMessageInfos() {
064: //create array from it
065: JwmaMessageInfoImpl[] list = new JwmaMessageInfoImpl[m_MessageInfos
066: .size()];
067: return (JwmaMessageInfoImpl[]) m_MessageInfos.toArray(list);
068: }//listMessageInfos
069:
070: /**
071: * Sorts this <tt>MessageInfoListImpl</tt> by the given criteria.
072: * If the criteria does not match any existing <tt>Comparator</tt>
073: * then the method returns without action.
074: * The used criteria is remembered for possible re-sorting.
075: *
076: * @param criteria the criteria used for sorting.
077: *
078: * @see dtw.webmail.util.MessageSortCriterias
079: * @see dtw.webmail.util.MessageSortingUtil
080: */
081: public void sort(int criteria) {
082: sort(criteria, true);
083: }//sort
084:
085: /**
086: * Sorts this <tt>MessageInfoListImpl</tt> by the given criteria.
087: * If the criteria does not match any existing <tt>Comparator</tt>
088: * then the method returns without action.
089: *
090: * @param criteria the criteria used for sorting.
091: * @param remember flags to remember or forget the criteria used for sorting.
092: *
093: * @see dtw.webmail.util.MessageSortCriterias
094: * @see dtw.webmail.util.MessageSortingUtil
095: */
096: private void sort(int criteria, boolean remember) {
097: //get the comparator
098: Comparator comp = null;
099: try {
100: comp = MessageSortingUtil.CRITERIA_COMPARATOR[criteria];
101: } catch (IndexOutOfBoundsException ex) {
102: return;
103: }
104: //sort it
105: Collections.sort(m_MessageInfos, comp);
106:
107: //possibly remember the criteria
108: if (remember) {
109: m_LastSortCriteria = criteria;
110: }
111: }//sort(boolean)
112:
113: /**
114: * Returns the last used sort criteria as <tt>int</tt>.
115: *
116: * @return the last sort criteria as <tt>int</tt>.
117: */
118: public int getLastSortCriteria() {
119: return m_LastSortCriteria;
120: }//getLastSortCriteria
121:
122: /**
123: * Returns the message number of the next message in the list,
124: * observing the sorting.
125: * The method returns -1 if the message does not exist in the list,
126: * or when there is no next message.
127: *
128: * @param msgnum the message number of the message to start from.
129: * @return the messagenumber of the next message as <tt>int</tt>.
130: */
131: public int getNextMessageNumber(int msgnum) {
132: int listindex = getListIndex(msgnum);
133: if (listindex == -1 || listindex == (m_MessageInfos.size() - 1)) {
134: return -1;
135: } else {
136: return ((JwmaMessageInfoImpl) m_MessageInfos
137: .get(listindex + 1)).getMessageNumber();
138: }
139: }//getNextMessageNumber
140:
141: /**
142: * Returns the message number of the previous message in the list,
143: * observing the sorting.
144: * The method returns -1 if the message does not exist in the list,
145: * or when there is no previous message.
146: *
147: * @param msgnum the message number of the message to start from.
148: * @return the messagenumber of the previous message as <tt>int</tt>.
149: */
150: public int getPreviousMessageNumber(int msgnum) {
151: int listindex = getListIndex(msgnum);
152: if (listindex == -1 || listindex == 0) {
153: return -1;
154: } else {
155: return ((JwmaMessageInfoImpl) m_MessageInfos
156: .get(listindex - 1)).getMessageNumber();
157: }
158: }//getNextMessageNumber
159:
160: /**
161: * Returns the list index of message given by it's
162: * message number.
163: *
164: * @return the list index as <tt>int</tt>.
165: */
166: public int getListIndex(int msgnum) {
167: for (Iterator iter = iterator(); iter.hasNext();) {
168: JwmaMessageInfoImpl msginfo = (JwmaMessageInfoImpl) iter
169: .next();
170: if (msginfo.getMessageNumber() == msgnum) {
171: return m_MessageInfos.indexOf(msginfo);
172: }
173: }
174: return -1;
175: }//getListIndex
176:
177: /**
178: * Returns an Iterator over the <tt>JwmaMessageInfoImpl</tt> instances
179: * contained within this list.
180: *
181: * @return the <tt>Iterator</tt> over the items in this list.
182: */
183: public Iterator iterator() {
184: return m_MessageInfos.iterator();
185: }//iterator
186:
187: /**
188: * Removes the items with the given numbers from this list.
189: *
190: * @param msgsnums the numbers of the items to be removed as <tt>int[]</tt>.
191: */
192: public void remove(int[] msgsnums) {
193: for (Iterator iter = iterator(); iter.hasNext();) {
194: int num = ((JwmaMessageInfoImpl) iter.next())
195: .getMessageNumber();
196: for (int n = 0; n < msgsnums.length; n++) {
197: if (num == msgsnums[n]) {
198: iter.remove();
199: }
200: }
201: }
202: }//remove
203:
204: /**
205: * Removes items that are flagged deleted from this list.
206: * This method can be used to clean out those messages
207: * when the folder was closed with expunging.
208: */
209: public void removeDeleted() {
210: if (m_HasDeleted) {
211: JwmaMessageInfoImpl msg = null;
212: for (Iterator iter = iterator(); iter.hasNext();) {
213: msg = (JwmaMessageInfoImpl) iter.next();
214: if (msg.isDeleted()) {
215: iter.remove();
216: }
217: }
218: m_HasDeleted = false;
219: }
220: }//removeDeleted
221:
222: /**
223: * Renumbers the items in this list.
224: * This message should be called if items were removed from
225: * this list.
226: */
227: public void renumber() {
228: //ensure integrity by sorting back the message numbers
229: sort(MessageSortCriterias.NUMBER_NUMERICAL, false);
230:
231: int i = 1;
232: for (Iterator iter = iterator(); iter.hasNext(); i++) {
233: ((JwmaMessageInfoImpl) iter.next()).setMessageNumber(i);
234: }
235:
236: //ensure the right order by sorting back to the users last
237: //applied criteria
238: sort(m_LastSortCriteria, false);
239: }//renumber
240:
241: /**
242: * Builds the list of <tt>JwmaMessageInfoImpl</tt> instances from
243: * the given array of messages.
244: *
245: * @param messages array of <tt>javax.mail.Message</tt> instances.
246: *
247: * @throws JwmaException if it fails to create a <tt>JwmaMessageInfoImpl</tt>
248: * instance.
249: */
250: private void buildMessageInfoList(Message[] messages)
251: throws JwmaException {
252:
253: m_MessageInfos = new ArrayList(messages.length);
254: JwmaMessageInfoImpl msginfo = null;
255: for (int i = 0; i < messages.length; i++) {
256: msginfo = JwmaMessageInfoImpl
257: .createJwmaMessageInfoImpl(messages[i]);
258: //flag deleted messages
259: if (msginfo.isDeleted() && !m_HasDeleted) {
260: m_HasDeleted = true;
261: }
262: m_MessageInfos.add(msginfo);
263: }
264: }//buildMessageInfoList
265:
266: /**
267: * Factory method that creates a new <tt>JwmaMessageInfoListImpl</tt> instance
268: * from the given array of messages.
269: *
270: * @param messages array of <tt>javax.mail.Message</tt> instances.
271: *
272: * @return the newly created <tt>JwmaMessageInfoListImpl</tt> instance.
273: *
274: * @throws JwmaException if it fails to build the list.
275: */
276: public static JwmaMessageInfoListImpl createJwmaMessageInfoListImpl(
277: Message[] messages) throws JwmaException {
278:
279: JwmaMessageInfoListImpl msglist = new JwmaMessageInfoListImpl();
280: //buildMessageInfoList
281: msglist.buildMessageInfoList(messages);
282: return msglist;
283:
284: }//createJwmaMessageList
285:
286: /**
287: * Factory method that creates a new <tt>JwmaMessageInfoListImpl</tt> instance
288: * wrapping the list of messages in the given folder.
289: *
290: * @param f the <tt>javax.mail.Folder</tt> instance, the new list instance should
291: * be created for.
292: *
293: * @return the newly created <tt>JwmaMessageInfoListImpl</tt> instance.
294: *
295: * @throws JwmaException if it fails retrieve the list of <tt>javax.mail.Message</tt>
296: * instances from the folder, or when it fails to build the list.
297: */
298: public static JwmaMessageInfoListImpl createJwmaMessageInfoListImpl(
299: Folder f) throws JwmaException {
300:
301: try {
302: //for listing only
303: if (!f.isOpen()) {
304: f.open(Folder.READ_ONLY);
305: }
306: Message[] msgs = f.getMessages();
307: //fetch messages with a slim profile
308: FetchProfile fp = new FetchProfile();
309: fp.add(FetchProfile.Item.ENVELOPE); //contains the headers
310: fp.add(FetchProfile.Item.FLAGS); //contains the flags
311: f.fetch(msgs, fp);
312:
313: return createJwmaMessageInfoListImpl(msgs);
314: } catch (MessagingException mex) {
315: throw new JwmaException("jwma.messagelist.failedcreation");
316: } finally {
317: try {
318: //close the folder
319: if (f.isOpen()) {
320: f.close(false);
321: }
322: } catch (MessagingException mesx) {
323: //don't care, the specs say it IS closed anyway
324: }
325: }
326: }//createJwmaMessageInfoListImpl
327:
328: }//class JwmaMessageInfoListImpl
|