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 dtw.webmail.util.StringUtil;
011: import org.apache.log4j.Logger;
012:
013: import javax.mail.Folder;
014: import javax.mail.MessagingException;
015: import java.util.*;
016:
017: /**
018: * Class implementing a list for <tt>JwmaFolder</tt>
019: * instances.
020: * It has caching functionality, which reduces the need to
021: * reconstruct the list after moving and deleting folders.
022: *
023: * @author Dieter Wimberger
024: * @version 0.9.7 07/02/2003
025: */
026: class JwmaFolderList {
027:
028: //logging
029: private static Logger log = Logger.getLogger(JwmaFolderList.class);
030:
031: //class attributes
032: public static boolean c_SubscribedOnly = true;
033:
034: //instance attributes
035: private Folder m_Folder;
036: private List m_Folders;
037: private boolean m_Recursive;
038: private boolean m_SubscribedOnly = c_SubscribedOnly;
039: private String m_Pattern;
040:
041: /**
042: * Constructs a new <tt>JwmaFolderList</tt> instance.
043: *
044: * @param f the folder to be listed as <tt>javax.mail.Folder</tt>.
045: * @param recurse flags if the list should be build recursive.
046: */
047: private JwmaFolderList(Folder f, boolean recurse) {
048: m_Recursive = recurse;
049: if (recurse) {
050: m_Pattern = "*";
051: } else {
052: m_Pattern = "%";
053: }
054: m_Folder = f;
055: }//JwmaFolderList
056:
057: /**
058: * Tests if this <tt>JwmaFolderList</tt> will work
059: * only with subscribed folders.
060: *
061: * @return true if subscribed only, false otherwise.
062: */
063: public boolean isSubscribedOnly() {
064: return m_SubscribedOnly;
065: }//isSubscribedOnly
066:
067: /**
068: * Sets or resets the flag for working only with
069: * subscribed folders.
070: */
071: public void setSubscribedOnly(boolean subscribedOnly) {
072: m_SubscribedOnly = subscribedOnly;
073: }//setSubscribedOnly
074:
075: /**
076: * Sets the pattern used for listing folders.
077: *
078: * @return the pattern as <tt>String</tt>.
079: */
080: public String getPattern() {
081: return m_Pattern;
082: }//getPattern
083:
084: /**
085: * Returns the pattern for listing folders.
086: *
087: * @param pattern the pattern as <tt>String</tt>.
088: */
089: public void setPattern(String pattern) {
090: m_Pattern = pattern;
091: }//setPattern
092:
093: /**
094: * Returns an Iterator over the <tt>JwmaFolder</tt> instances
095: * contained within this list.
096: *
097: * @return the <tt>Iterator</tt> over the items in this list.
098: */
099: public Iterator iterator() {
100: return m_Folders.listIterator();
101: }//iterator
102:
103: /**
104: * Returns the size of this list.
105: *
106: * @return the size of this list.
107: */
108: public int size() {
109: return m_Folders.size();
110: }//getSize
111:
112: /**
113: * Returns a sublist of this list, that contains only
114: * the folders of the given type.
115: *
116: * @param type the requested folder type as <tt>int</tt>.
117: *
118: * @return the list containing all folders of the given type as
119: * <tt>List</tt>.
120: */
121: public List sublist(int type) {
122:
123: if (type == JwmaFolder.TYPE_ALL) {
124: return m_Folders;
125: } else {
126: List folders = new ArrayList();
127: for (Iterator iter = m_Folders.listIterator(); iter
128: .hasNext();) {
129: JwmaFolderImpl f = (JwmaFolderImpl) iter.next();
130: switch (type) {
131: case JwmaFolder.TYPE_MESSAGE_CONTAINER:
132: if (f.isType(JwmaFolder.TYPE_MAILBOX)
133: || f.isType(JwmaFolder.TYPE_MIXED)) {
134: folders.add(f);
135: }
136: break;
137: case JwmaFolder.TYPE_FOLDER_CONTAINER:
138: if (f.isType(JwmaFolder.TYPE_FOLDER)
139: || f.isType(JwmaFolder.TYPE_MIXED)) {
140: folders.add(f);
141: }
142: break;
143: default:
144: if (f.isType(type)) {
145: folders.add(f);
146: }
147: }
148: }
149: //force sort
150: Collections.sort(folders, LEXOGRAPHICAL);
151: return folders;
152: }
153: }//sublist
154:
155: /**
156: * Returns a sublist of this list, that contains only
157: * the folders of the given type.
158: *
159: * @param type the requested folder type as <tt>int</tt>.
160: *
161: * @return the list containing all folders of the given type as
162: * <tt>List</tt>.
163: */
164: public List sublist(int type, boolean subscribed) {
165:
166: if (type == JwmaFolder.TYPE_ALL) {
167: return m_Folders;
168: } else {
169: List folders = new ArrayList();
170: for (Iterator iter = m_Folders.listIterator(); iter
171: .hasNext();) {
172: JwmaFolderImpl f = (JwmaFolderImpl) iter.next();
173: switch (type) {
174: case JwmaFolder.TYPE_MESSAGE_CONTAINER:
175: if (f.isType(JwmaFolder.TYPE_MAILBOX)
176: || f.isType(JwmaFolder.TYPE_MIXED)) {
177: if (subscribed) {
178: if (f.isSubscribed()) {
179: folders.add(f);
180: }
181: } else {
182: folders.add(f);
183: }
184: }
185: break;
186: case JwmaFolder.TYPE_FOLDER_CONTAINER:
187: if (f.isType(JwmaFolder.TYPE_FOLDER)
188: || f.isType(JwmaFolder.TYPE_MIXED)) {
189: if (subscribed) {
190: if (f.isSubscribed()) {
191: folders.add(f);
192: }
193: } else {
194: folders.add(f);
195: }
196: }
197: break;
198: default:
199: if (f.isType(type)) {
200: if (subscribed) {
201: if (f.isSubscribed()) {
202: folders.add(f);
203: }
204: } else {
205: folders.add(f);
206: }
207: }
208: }
209: }
210: //force sort
211: Collections.sort(folders, LEXOGRAPHICAL);
212: return folders;
213: }
214: }//sublist
215:
216: /**
217: * Returns a sublist of this list, that contains only
218: * the folders of the given type, filtering the given
219: * folder.
220: * This method can be used to obtain targets for moving
221: * messages or other folders.
222: *
223: * @param type the requested folder type as <tt>int</tt>.
224: * @param folder the <tt>JwmaFolderImpl</tt> instance to be filtered
225: * from the list.
226: *
227: * @return the list containing all folders of the given type as
228: * <tt>List</tt>.
229: */
230: public List sublist(int type, JwmaFolderImpl folder) {
231:
232: List folders = new ArrayList();
233: for (Iterator iter = m_Folders.listIterator(); iter.hasNext();) {
234: JwmaFolderImpl f = (JwmaFolderImpl) iter.next();
235: if (f.equals(folder)) {
236: //filter this one
237: continue;
238: }
239: switch (type) {
240: case JwmaFolder.TYPE_ALL:
241: folders.add(f);
242: break;
243: case JwmaFolder.TYPE_MESSAGE_CONTAINER:
244: if (f.isType(JwmaFolder.TYPE_MAILBOX)
245: || f.isType(JwmaFolder.TYPE_MIXED)) {
246: folders.add(f);
247: }
248: break;
249: case JwmaFolder.TYPE_FOLDER_CONTAINER:
250: if (f.isType(JwmaFolder.TYPE_FOLDER)
251: || f.isType(JwmaFolder.TYPE_MIXED)) {
252: folders.add(f);
253: }
254: break;
255: default:
256: if (f.isType(type)) {
257: folders.add(f);
258: }
259: }
260: }
261: //force sort
262: Collections.sort(folders, LEXOGRAPHICAL);
263: return folders;
264: }//sublist
265:
266: /**
267: * Returns a sublist of this list, that contains only
268: * the folders of the given type, filtering the given
269: * folder.
270: * This method can be used to obtain targets for moving
271: * messages or other folders.
272: *
273: * @param type the requested folder type as <tt>int</tt>.
274: * @param folder the <tt>JwmaFolderImpl</tt> instance to be filtered
275: * from the list.
276: *
277: * @return the list containing all folders of the given type as
278: * <tt>List</tt>.
279: */
280: public List sublist(int type, JwmaFolderImpl folder,
281: boolean subscribed) {
282:
283: List folders = new ArrayList();
284: for (Iterator iter = m_Folders.listIterator(); iter.hasNext();) {
285: JwmaFolderImpl f = (JwmaFolderImpl) iter.next();
286: if (f.equals(folder)) {
287: //filter this one
288: continue;
289: }
290: switch (type) {
291: case JwmaFolder.TYPE_ALL:
292: if (subscribed) {
293: if (f.isSubscribed()) {
294: folders.add(f);
295: }
296: } else {
297: folders.add(f);
298: }
299: break;
300: case JwmaFolder.TYPE_MESSAGE_CONTAINER:
301: if (f.isType(JwmaFolder.TYPE_MAILBOX)
302: || f.isType(JwmaFolder.TYPE_MIXED)) {
303: if (subscribed) {
304: if (f.isSubscribed()) {
305: folders.add(f);
306: }
307: } else {
308: folders.add(f);
309: }
310: }
311: break;
312: case JwmaFolder.TYPE_FOLDER_CONTAINER:
313: if (f.isType(JwmaFolder.TYPE_FOLDER)
314: || f.isType(JwmaFolder.TYPE_MIXED)) {
315: if (subscribed) {
316: if (f.isSubscribed()) {
317: folders.add(f);
318: }
319: } else {
320: folders.add(f);
321: }
322: }
323: break;
324: default:
325: if (f.isType(type)) {
326: if (subscribed) {
327: if (f.isSubscribed()) {
328: folders.add(f);
329: }
330: } else {
331: folders.add(f);
332: }
333: }
334: }
335: }
336: //force sort
337: Collections.sort(folders, LEXOGRAPHICAL);
338: return folders;
339: }//sublist
340:
341: /**
342: * Returns a sublist of this list, that contains only
343: * the folders of the given type, filtering the given
344: * folders.
345: * This method should be used to obtain a list of subscribed
346: * or unsubscribed folders, pasing in the special folders (trash,
347: * draft etc.)
348: *
349: * @param type the requested folder type as <tt>int</tt>.
350: * @param exfolders the folders (by path) to be filtered
351: * from the list as <tt>String[]</tt>.
352: *
353: * @return the list containing all folders of the given type as
354: * <tt>List</tt>.
355: */
356: public List sublist(int type, String[] exfolders, boolean subscribed) {
357: List folders = new ArrayList();
358: for (Iterator iter = m_Folders.listIterator(); iter.hasNext();) {
359: JwmaFolderImpl f = (JwmaFolderImpl) iter.next();
360:
361: if (StringUtil.contains(exfolders, f.getPath())) {
362: continue;
363: } else {
364: switch (type) {
365: case JwmaFolder.TYPE_ALL:
366: if (subscribed) {
367: if (f.isSubscribed()) {
368: folders.add(f);
369: }
370: } else {
371: folders.add(f);
372: }
373: break;
374: case JwmaFolder.TYPE_MESSAGE_CONTAINER:
375: if (f.isType(JwmaFolder.TYPE_MAILBOX)
376: || f.isType(JwmaFolder.TYPE_MIXED)) {
377: if (subscribed) {
378: if (f.isSubscribed()) {
379: folders.add(f);
380: }
381: } else {
382: folders.add(f);
383: }
384: }
385: break;
386: case JwmaFolder.TYPE_FOLDER_CONTAINER:
387: if (f.isType(JwmaFolder.TYPE_FOLDER)
388: || f.isType(JwmaFolder.TYPE_MIXED)) {
389: if (subscribed) {
390: if (f.isSubscribed()) {
391: folders.add(f);
392: }
393: } else {
394: folders.add(f);
395: }
396: }
397: break;
398: default:
399: if (f.isType(type)) {
400: if (subscribed) {
401: if (f.isSubscribed()) {
402: folders.add(f);
403: }
404: } else {
405: folders.add(f);
406: }
407: }
408: }
409: }
410: }
411: //force sort
412: Collections.sort(folders, LEXOGRAPHICAL);
413: return folders;
414: }//sublist
415:
416: /**
417: * Tests if this list contains a folder with the
418: * given path.
419: *
420: * @param path the path of the folder as <tt>String</tt>.
421: *
422: * @return true if this list contains a folder with the given path,
423: * false otherwise.
424: */
425: public boolean contains(String path) {
426: for (Iterator iter = iterator(); iter.hasNext();) {
427: if (path.equals(((JwmaFolderImpl) iter.next()).getPath())) {
428: return true;
429: }
430: }
431: return false;
432: }//contains
433:
434: /**
435: * Tests if this list contains a given folder.
436: *
437: * @param folder the folder as <tt>JwmaFolder</tt>.
438: *
439: * @return true if this list contains the given folder,
440: * false otherwise.
441: */
442: public boolean contains(JwmaFolder folder) {
443: for (Iterator iter = iterator(); iter.hasNext();) {
444: if (folder.equals(iter.next())) {
445: return true;
446: }
447: }
448: return false;
449: }//contains
450:
451: /**
452: * Creates an array of <tt>JwmaFolder</tt> instances from
453: * the given <tt>List</tt>.
454: * If the list is empty, then the returned array will be
455: * empty, but not null.
456: *
457: * @param folders the <tt>List</tt> of folders.
458: *
459: * @return the newly created array.
460: */
461: public JwmaFolder[] createFolderArray(List folders) {
462: //create array from it
463: JwmaFolder[] list = new JwmaFolder[folders.size()];
464: return (JwmaFolder[]) folders.toArray(list);
465: }//createFolderArray
466:
467: /**
468: * Removes a folder with the given path from this list.
469: *
470: * @param path the path of the folder to be removed as <tt>String</tt>.
471: */
472: public void removeFolderFromList(String path) {
473: for (Iterator iter = m_Folders.iterator(); iter.hasNext();) {
474: if (path.equals(((JwmaFolderImpl) iter.next()).getPath())) {
475: iter.remove();
476: //done
477: break;
478: }
479: }
480: }//removeFolderFromList
481:
482: /**
483: * Adds a given folder to this list.
484: *
485: * @param folder the folder to be added as <tt>JwmaFolder</tt>.
486: */
487: public void addFolderToList(JwmaFolderImpl folder) {
488: m_Folders.add(folder);
489: Collections.sort(m_Folders, LEXOGRAPHICAL);
490: }//addFolderToList
491:
492: /**
493: * Rebuilds this list of folders.
494: */
495: public void rebuild() throws MessagingException, JwmaException {
496: Folder[] folders = m_Folder.list(m_Pattern);
497: //build list
498: m_Folders = new ArrayList(folders.length);
499: buildFolderList(folders);
500: Collections.sort(m_Folders, LEXOGRAPHICAL);
501: }//rebuild
502:
503: /**
504: * Builds this list of folders from the given array of folders.
505: * If recursive, then it will build a flat list of the complete
506: * folder tree.
507: *
508: * @param folders the array of <tt>javax.mail.Folder</tt> instances
509: * in the root folder.
510: */
511: private void buildFolderList(Folder[] folders)
512: throws JwmaException, MessagingException {
513:
514: for (int i = 0; i < folders.length; i++) {
515: //add a lightweight JwmaFolderImpl to the list
516: m_Folders.add(JwmaFolderImpl.createLight(folders[i]));
517: //recurse if necessary
518: //if (m_Recursive) {
519: // buildFolderList(folders[i].list());
520: //}
521: }
522: }//buildFolderList
523:
524: /**
525: * Factory method that creates a flat list of all folders on the store.
526: * The given folder should be the root folder, or the default folder
527: * on the store.
528: *
529: * @param folder the <tt>javax.mail.Folder</tt> instance representing the
530: * root folder.
531: *
532: * @return the newly created <tt>JwmaFolderList</tt> instance.
533: *
534: * @throws JwmaException if it fails to build the folder list.
535: */
536: public static JwmaFolderList createStoreList(Folder folder)
537: throws JwmaException {
538:
539: try {
540: JwmaFolderList flist = new JwmaFolderList(folder, true);
541: flist.rebuild();
542: //DEBUG:flist.dumpList();
543: return flist;
544: } catch (MessagingException mex) {
545: throw new JwmaException(mex.getMessage()).setException(mex);
546: }
547: }//createStoreList
548:
549: /**
550: * Factory method that creates a list of all subfolders of the given
551: * folder.
552: * There is no recursion into subfolders.
553: *
554: * @param folder the <tt>javax.mail.Folder</tt> instance to be listed.
555: *
556: * @return the newly created <tt>JwmaFolderList</tt> instance.
557: *
558: * @throws JwmaException if it fails to build the folder list.
559: */
560: public static JwmaFolderList createSubfolderList(Folder folder)
561: throws JwmaException {
562: try {
563: JwmaFolderList flist = new JwmaFolderList(folder, false);
564: flist.rebuild();
565: return flist;
566: } catch (MessagingException mex) {
567: throw new JwmaException(mex.getMessage()).setException(mex);
568: }
569: }//createSubfolderList
570:
571: /**
572: * Defines a <tt>Comparator</tt> that sorts
573: * the folder instances lexographical.
574: */
575: public static final Comparator LEXOGRAPHICAL = new Comparator() {
576:
577: public int compare(Object o1, Object o2) {
578: JwmaFolder f1 = (JwmaFolder) o1;
579: JwmaFolder f2 = (JwmaFolder) o2;
580: return f1.getName().compareTo(f2.getName());
581: }//compare(Object,Object)
582: };
583:
584: }//class JwmaFolderList
|