KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > columba > mail > search > MailSearchProvider


1 package org.columba.mail.search;
2
3 import java.net.URI JavaDoc;
4 import java.text.DateFormat JavaDoc;
5 import java.text.MessageFormat JavaDoc;
6 import java.text.SimpleDateFormat JavaDoc;
7 import java.util.Collections JavaDoc;
8 import java.util.Comparator JavaDoc;
9 import java.util.Date JavaDoc;
10 import java.util.Hashtable JavaDoc;
11 import java.util.Iterator JavaDoc;
12 import java.util.List JavaDoc;
13 import java.util.Locale JavaDoc;
14 import java.util.Map JavaDoc;
15 import java.util.ResourceBundle JavaDoc;
16 import java.util.TimeZone JavaDoc;
17 import java.util.Vector JavaDoc;
18 import java.util.logging.Logger JavaDoc;
19
20 import javax.swing.ImageIcon JavaDoc;
21
22 import org.columba.api.gui.frame.IFrameMediator;
23 import org.columba.api.plugin.PluginLoadingFailedException;
24 import org.columba.core.command.CommandProcessor;
25 import org.columba.core.filter.FilterCriteria;
26 import org.columba.core.filter.FilterRule;
27 import org.columba.core.gui.frame.FrameManager;
28 import org.columba.core.gui.search.StringCriteriaRenderer;
29 import org.columba.core.gui.search.api.ICriteriaRenderer;
30 import org.columba.core.gui.search.api.IResultPanel;
31 import org.columba.core.resourceloader.ImageLoader;
32 import org.columba.core.search.SearchCriteria;
33 import org.columba.core.search.api.ISearchCriteria;
34 import org.columba.core.search.api.ISearchProvider;
35 import org.columba.core.search.api.ISearchRequest;
36 import org.columba.core.search.api.ISearchResult;
37 import org.columba.mail.command.MailFolderCommandReference;
38 import org.columba.mail.filter.MailFilterFactory;
39 import org.columba.mail.folder.IMailFolder;
40 import org.columba.mail.folder.virtual.VirtualFolder;
41 import org.columba.mail.folder.virtual.VirtualHeader;
42 import org.columba.mail.gui.frame.TreeViewOwner;
43 import org.columba.mail.gui.search.ComplexResultPanel;
44 import org.columba.mail.gui.search.CriteriaResultPanel;
45 import org.columba.mail.gui.table.command.ViewHeaderListCommand;
46 import org.columba.mail.gui.tree.FolderTreeModel;
47 import org.columba.mail.message.IHeaderList;
48 import org.columba.mail.resourceloader.IconKeys;
49 import org.columba.mail.resourceloader.MailImageLoader;
50 import org.columba.ristretto.message.Address;
51 import org.columba.ristretto.message.Flags;
52
53 /**
54  * Search provider uses virtual folder to search over all existing mail folders.
55  *
56  * @author frd
57  */

58 public class MailSearchProvider implements ISearchProvider {
59     private static final String JavaDoc CRITERIA_BODY_CONTAINS = "body_contains";
60
61     public static final String JavaDoc CRITERIA_FROM_CONTAINS = "from_contains";
62
63     private static final String JavaDoc CRITERIA_SIZE_GREATER_THAN = "size_greater_than";
64
65     private static final String JavaDoc CRITERIA_SIZE_SMALLER_THAN = "size_smaller_than";
66
67     private static final String JavaDoc CRITERIA_SUBJECT_CONTAINS = "subject_contains";
68
69     private static final Logger JavaDoc LOG = Logger
70             .getLogger("org.columba.mail.search.MailSearchProvider");
71
72     private Vector JavaDoc<SearchIndex> indizes = new Vector JavaDoc<SearchIndex>();
73
74     private Map JavaDoc<String JavaDoc, VirtualFolder> searchFolders = new Hashtable JavaDoc<String JavaDoc, VirtualFolder>();
75     private VirtualFolder lastSearchFolder;
76
77     private int totalResultCount = 0;
78
79     private ResourceBundle JavaDoc bundle;
80
81     /**
82      * check if a single criteria search was done. False, if a multiple criteria search was done.
83      */

84     private boolean singleCriteriaSearch = false;
85
86     public MailSearchProvider() {
87         bundle = ResourceBundle.getBundle("org.columba.mail.i18n.search");
88
89     }
90
91     public String JavaDoc getTechnicalName() {
92         return "MailSearchProvider";
93     }
94
95     public String JavaDoc getName() {
96         return bundle.getString("provider_title");
97     }
98
99     public String JavaDoc getDescription() {
100         return bundle.getString("provider_description");
101     }
102
103     public ImageIcon JavaDoc getIcon() {
104         return MailImageLoader.getSmallIcon(IconKeys.MESSAGE_READ);
105     }
106
107     public List JavaDoc<ISearchCriteria> getAllCriteria(String JavaDoc searchTerm) {
108         List JavaDoc<ISearchCriteria> list = new Vector JavaDoc<ISearchCriteria>();
109
110         // check if string is a number
111
boolean numberFormat = false;
112         try {
113             int searchTermInt = Integer.parseInt(searchTerm);
114             numberFormat = true;
115         } catch (NumberFormatException JavaDoc e) {
116         }
117
118         if (searchTerm.equals(""))
119             numberFormat = true;
120
121
122         list.add(getCriteria(MailSearchProvider.CRITERIA_SUBJECT_CONTAINS,
123                 searchTerm));
124         list.add(getCriteria(MailSearchProvider.CRITERIA_FROM_CONTAINS,
125                 searchTerm));
126         list.add(getCriteria(MailSearchProvider.CRITERIA_BODY_CONTAINS,
127                 searchTerm));
128
129         if (numberFormat)
130             list.add(getCriteria(MailSearchProvider.CRITERIA_SIZE_GREATER_THAN,
131                     searchTerm));
132         if (numberFormat)
133             list.add(getCriteria(MailSearchProvider.CRITERIA_SIZE_SMALLER_THAN,
134                     searchTerm));
135
136         return list;
137     }
138
139     public IResultPanel getResultPanel(String JavaDoc searchCriteriaTechnicalName) {
140         return new CriteriaResultPanel(getTechnicalName(),
141                 searchCriteriaTechnicalName);
142     }
143
144     public IResultPanel getComplexResultPanel() {
145         return new ComplexResultPanel(getTechnicalName());
146     }
147
148     public ICriteriaRenderer getCriteriaRenderer(
149             String JavaDoc searchCriteriaTechnicalName) {
150         if (searchCriteriaTechnicalName
151                 .equals(MailSearchProvider.CRITERIA_BODY_CONTAINS))
152             return new StringCriteriaRenderer(getCriteria(
153                     MailSearchProvider.CRITERIA_BODY_CONTAINS, ""), this);
154         else if (searchCriteriaTechnicalName
155                 .equals(MailSearchProvider.CRITERIA_SUBJECT_CONTAINS))
156             return new StringCriteriaRenderer(getCriteria(
157                     MailSearchProvider.CRITERIA_SUBJECT_CONTAINS, ""), this);
158         else if (searchCriteriaTechnicalName
159                 .equals(MailSearchProvider.CRITERIA_FROM_CONTAINS))
160             return new StringCriteriaRenderer(getCriteria(
161                     MailSearchProvider.CRITERIA_FROM_CONTAINS, ""), this);
162         else if (searchCriteriaTechnicalName
163                 .equals(MailSearchProvider.CRITERIA_SIZE_GREATER_THAN))
164             return new StringCriteriaRenderer(getCriteria(
165                     MailSearchProvider.CRITERIA_SIZE_GREATER_THAN, ""), this);
166         else if (searchCriteriaTechnicalName
167                 .equals(MailSearchProvider.CRITERIA_SIZE_SMALLER_THAN))
168             return new StringCriteriaRenderer(getCriteria(
169                     MailSearchProvider.CRITERIA_SIZE_SMALLER_THAN, ""), this);
170
171         else
172             throw new IllegalArgumentException JavaDoc("no renderer available for <"
173                     + searchCriteriaTechnicalName + ">");
174     }
175
176     public ISearchCriteria getCriteria(String JavaDoc technicalName, String JavaDoc searchTerm) {
177
178         String JavaDoc title = MessageFormat.format(bundle.getString(technicalName
179                 + "_title"), new Object JavaDoc[] { searchTerm });
180         String JavaDoc name = bundle.getString(technicalName + "_name");
181         String JavaDoc description = MessageFormat.format(bundle
182                 .getString(technicalName + "_description"),
183                 new Object JavaDoc[] { searchTerm });
184
185         return new SearchCriteria(technicalName, name, title, description);
186     }
187
188     public List JavaDoc<ISearchResult> query(String JavaDoc searchTerm,
189             String JavaDoc searchCriteriaTechnicalName, boolean searchInside,
190             int startIndex, int resultCount) {
191
192         LOG.info("searchTerm=" + searchTerm);
193         LOG.info("criteriaName=" + searchCriteriaTechnicalName);
194         LOG.info("searchInside=" + searchInside);
195
196         List JavaDoc<ISearchResult> result = new Vector JavaDoc<ISearchResult>();
197
198         indizes = new Vector JavaDoc<SearchIndex>();
199
200         // create search criteria
201

202         FilterCriteria criteria = createFilterCriteria(searchTerm,
203                 searchCriteriaTechnicalName);
204
205         // remember request id for "search in results"
206
String JavaDoc searchRequestId = searchCriteriaTechnicalName;
207
208         // remove memorized search folders
209
if (!searchInside) {
210             lastSearchFolder = null;
211             //searchFolders.remove(searchRequestId);
212
}
213
214         // return empty result, in case the criteria doesn't match the search
215
// term
216
if (criteria == null)
217             return result;
218         try {
219
220 // Iterator<String> it3 = searchFolders.keySet().iterator();
221
// while (it3.hasNext()) {
222
// String key = it3.next();
223
// VirtualFolder f = searchFolders.get(key);
224
// LOG.info("current cache id=" + key + ":" + f.getId());
225
// }
226

227             VirtualFolder folder = null;
228
229             // create virtual folder for criteria
230
if (searchInside) {
231                 if (lastSearchFolder != null) {
232                     LOG.info("reuse existing virtual folder");
233
234                     // get first one
235
VirtualFolder vFolder = lastSearchFolder;
236                     // create new search folder, but re-use old search folder
237
folder = SearchFolderFactory.prepareSearchFolder(criteria,
238                             vFolder);
239                 } else {
240                     totalResultCount = 0;
241                     return result;
242                 }
243             } else {
244                 LOG.info("create new virtual folder");
245                 IMailFolder rootFolder = (IMailFolder) FolderTreeModel
246                         .getInstance().getRoot();
247                 folder = SearchFolderFactory.createSearchFolder(criteria,
248                         rootFolder);
249             }
250
251             // do the search
252
IHeaderList headerList = folder.getHeaderList();
253
254             Object JavaDoc[] uids = headerList.getUids();
255             LOG.info("result count=" + uids.length);
256
257             for (int i = 0; i < uids.length; i++) {
258                 SearchIndex idx = new SearchIndex(folder, uids[i]);
259
260 // System.out.println("--> idx.folder="+idx.folder.getId());
261
// System.out.println("--> idx.message="+idx.messageId);
262

263                 indizes.add(idx);
264             }
265
266             // retrieve the actual search result data
267
List JavaDoc<ISearchResult> l = retrieveResultData(indizes, startIndex,
268                     resultCount);
269             result.addAll(l);
270
271             // sort all the results
272
Collections.sort(result, new MyComparator());
273
274             // remember search folder for "show total results" action
275
searchFolders.put(searchRequestId, folder);
276             lastSearchFolder = folder;
277
278             LOG.info("cache search folder=" + searchRequestId);
279
280         } catch (Exception JavaDoc e) {
281             throw new RuntimeException JavaDoc(e);
282         }
283
284         // memorize total result count
285
totalResultCount = indizes.size();
286
287         singleCriteriaSearch = true;
288
289         return result;
290     }
291
292     private FilterCriteria createFilterCriteria(String JavaDoc searchTerm,
293             String JavaDoc searchCriteriaTechnicalName) {
294         FilterCriteria criteria = null;
295         if (searchCriteriaTechnicalName
296                 .equals(MailSearchProvider.CRITERIA_BODY_CONTAINS)) {
297             criteria = MailFilterFactory.createBodyContains(searchTerm);
298         } else if (searchCriteriaTechnicalName
299                 .equals(MailSearchProvider.CRITERIA_SUBJECT_CONTAINS)) {
300             criteria = MailFilterFactory.createSubjectContains(searchTerm);
301         } else if (searchCriteriaTechnicalName
302                 .equals(MailSearchProvider.CRITERIA_FROM_CONTAINS)) {
303             criteria = MailFilterFactory.createFromContains(searchTerm);
304         } else if (searchCriteriaTechnicalName
305                 .equals(MailSearchProvider.CRITERIA_SIZE_GREATER_THAN)) {
306             criteria = MailFilterFactory.createSizeIsBigger(Integer
307                     .parseInt(searchTerm));
308         } else if (searchCriteriaTechnicalName
309                 .equals(MailSearchProvider.CRITERIA_SIZE_SMALLER_THAN)) {
310             criteria = MailFilterFactory.createSizeIsSmaller(Integer
311                     .parseInt(searchTerm));
312         } else
313             throw new IllegalArgumentException JavaDoc("no criteria <"
314                     + searchCriteriaTechnicalName + "> found");
315         return criteria;
316     }
317
318     public List JavaDoc<ISearchResult> query(List JavaDoc<ISearchRequest> list,
319             boolean matchAll, boolean searchInside, int startIndex,
320             int resultCount) {
321         List JavaDoc<ISearchResult> result = new Vector JavaDoc<ISearchResult>();
322
323         indizes = new Vector JavaDoc<SearchIndex>();
324
325         // remove all memorized search folders
326
if (!searchInside) {
327             lastSearchFolder = null;
328         }
329
330         // create search criteria
331
FilterRule rule = new FilterRule();
332         if (matchAll)
333             rule.setCondition(FilterRule.MATCH_ALL);
334         else
335             rule.setCondition(FilterRule.MATCH_ANY);
336
337         Iterator JavaDoc<ISearchRequest> it = list.iterator();
338         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
339         while (it.hasNext()) {
340             ISearchRequest r = it.next();
341             String JavaDoc searchCriteriaTechnicalName = r.getCriteria();
342             buf.append(searchCriteriaTechnicalName);
343
344             String JavaDoc searchTerm = r.getSearchTerm();
345
346             FilterCriteria criteria = createFilterCriteria(searchTerm,
347                     searchCriteriaTechnicalName);
348             rule.add(criteria);
349         }
350
351         // remember request id for "search in results"
352
String JavaDoc searchRequestId = buf.toString();
353
354         try {
355
356             VirtualFolder folder = null;
357             // create virtual folder for each criteria
358
IMailFolder rootFolder = (IMailFolder) FolderTreeModel
359                     .getInstance().getRoot();
360
361             if (searchInside && (lastSearchFolder != null) ) {
362                 folder = lastSearchFolder;
363
364                 SearchFolderFactory.prepareSearchFolder(rule, folder);
365             } else {
366                 folder = SearchFolderFactory.createSearchFolder(rule,
367                         rootFolder);
368             }
369
370             // do the search
371
IHeaderList headerList = folder.getHeaderList();
372
373             Object JavaDoc[] uids = headerList.getUids();
374
375             for (int i = 0; i < uids.length; i++) {
376                 SearchIndex idx = new SearchIndex(folder, uids[i]);
377 // System.out.println("--> idx.folder="+idx.folder.getId());
378
// System.out.println("--> idx.message="+idx.messageId);
379

380                 indizes.add(idx);
381             }
382
383             // retrieve the actual search result data
384
List JavaDoc<ISearchResult> l = retrieveResultData(indizes, startIndex,
385                     resultCount);
386             result.addAll(l);
387
388             // sort all the results
389
Collections.sort(result, new MyComparator());
390
391             // remember search folder for "show total results" action
392
searchFolders.put(searchRequestId, folder);
393             lastSearchFolder = folder;
394
395         } catch (Exception JavaDoc e) {
396             throw new RuntimeException JavaDoc(e);
397         }
398
399         // memorize total result count
400
totalResultCount = indizes.size();
401
402         singleCriteriaSearch = false;
403
404         return result;
405     }
406
407     private List JavaDoc<ISearchResult> retrieveResultData(Vector JavaDoc<SearchIndex> indizes,
408             int startIndex, int resultCount) throws Exception JavaDoc {
409         // ensure we are in existing result range
410
int count = (startIndex + resultCount <= indizes.size()) ? resultCount
411                 : indizes.size();
412         List JavaDoc<ISearchResult> result = new Vector JavaDoc<ISearchResult>();
413         // gather result results
414
for (int i = startIndex; i < count; i++) {
415             SearchIndex idx = indizes.get(i);
416             VirtualFolder folder = idx.folder;
417             Object JavaDoc messageId = idx.messageId;
418
419             // TODO @author fdietz: ensure that we don't fetch individual
420
// headers
421
// to reduce client/server roundtrips
422

423             String JavaDoc title = (String JavaDoc) folder.getAttribute(messageId,
424                     "columba.subject");
425             Address from = (Address) folder.getAttribute(messageId,
426                     "columba.from");
427             Date JavaDoc date = (Date JavaDoc) folder.getAttribute(messageId, "columba.date");
428             String JavaDoc description = from.toString() + " " + date;
429
430             VirtualHeader h = (VirtualHeader) folder.getHeaderList().get(messageId);
431             URI JavaDoc uri = SearchResultBuilder.createURI(h.getSrcFolder().getId(), h.getSrcUid());
432             System.out.println("uri="+uri.toString());
433             ImageIcon JavaDoc statusIcon = null;
434             Flags flags = folder.getFlags(messageId);
435             if (flags.getDeleted()) {
436                 statusIcon = ImageLoader.getSmallIcon("user-trash.png");
437
438             } else if (flags.getAnswered()) {
439                 statusIcon = MailImageLoader
440                         .getSmallIcon("message-mail-replied.png");
441             } else if (flags.getDraft()) {
442                 statusIcon = MailImageLoader.getSmallIcon("edit.png");
443             } else if (!flags.getSeen()) {
444                 statusIcon = MailImageLoader
445                         .getSmallIcon("message-mail-unread.png");
446             } else if (flags.getSeen()) {
447                 statusIcon = MailImageLoader
448                         .getSmallIcon("message-mail-read.png");
449             }
450
451             String JavaDoc dateString = new DateHelper().format(date);
452
453             result.add(new MailSearchResult(title, description, uri,
454                     dateString, date, from, statusIcon, flags.getFlagged()));
455         }
456         return result;
457     }
458
459     class DateHelper {
460         SimpleDateFormat JavaDoc dfWeek = new SimpleDateFormat JavaDoc("EEE HH:mm", Locale
461                 .getDefault());
462
463         // use local date settings
464
DateFormat JavaDoc dfCommon = DateFormat.getDateInstance();
465
466         static final long OneDay = 24 * 60 * 60 * 1000;
467
468         TimeZone JavaDoc localTimeZone = TimeZone.getDefault();
469
470         private int getLocalDaysDiff(long t) {
471             return (int) (((System.currentTimeMillis() + localTimeZone
472                     .getRawOffset()) - (((t + localTimeZone.getRawOffset()) / OneDay) * OneDay)) / OneDay);
473         }
474
475         public String JavaDoc format(Date JavaDoc date) {
476             String JavaDoc dateString = null;
477
478             int diff = getLocalDaysDiff(date.getTime());
479
480             // if ( today
481
if ((diff >= 0) && (diff < 7)) {
482                 dateString = dfWeek.format(date);
483             } else {
484                 dateString = dfCommon.format(date);
485             }
486             return dateString;
487         }
488
489     }
490
491     class SearchIndex {
492         VirtualFolder folder;
493
494         Object JavaDoc messageId;
495
496         SearchIndex(VirtualFolder folder, Object JavaDoc messageId) {
497             this.folder = folder;
498             this.messageId = messageId;
499         }
500     }
501
502     public int getTotalResultCount() {
503         return totalResultCount;
504     }
505
506     public void showAllResults(IFrameMediator mediator, String JavaDoc searchTerm,
507             String JavaDoc searchCriteriaTechnicalName) {
508
509         VirtualFolder vFolder = lastSearchFolder;
510         // if complex use the last search folder
511
if (searchCriteriaTechnicalName == null) {
512             vFolder = searchFolders.values().iterator().next();
513         } else
514             vFolder = searchFolders.get(searchCriteriaTechnicalName);
515
516         if (vFolder == null)
517             throw new IllegalArgumentException JavaDoc("vFolder for search critera <"
518                     + searchCriteriaTechnicalName + "> not found");
519
520         // ensure that we are currently in the mail component
521
IFrameMediator newMediator = null;
522         try {
523             newMediator = FrameManager.getInstance().switchView(
524                     mediator.getContainer(), "ThreePaneMail");
525         } catch (PluginLoadingFailedException e) {
526             e.printStackTrace();
527         }
528
529         // select invisible virtual folder
530
((TreeViewOwner) newMediator).getTreeController().setSelected(vFolder);
531
532         // update message list
533
CommandProcessor.getInstance().addOp(
534                 new ViewHeaderListCommand(newMediator,
535                         new MailFolderCommandReference(vFolder)));
536     }
537
538     /**
539      * Comparator for message result. Sortes results by Date. More recent
540      * results are shown first.
541      *
542      * @author frd
543      */

544     class MyComparator implements Comparator JavaDoc {
545         MyComparator() {
546         }
547
548         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
549             MailSearchResult result = (MailSearchResult) o1;
550             MailSearchResult result2 = (MailSearchResult) o2;
551
552             Date JavaDoc date = result.getDate();
553             Date JavaDoc date2 = result2.getDate();
554
555             if (date == null && date2 == null)
556                 return 0;
557             if (date != null && date2 == null)
558                 return -1;
559             if (date == null && date2 != null)
560                 return 1;
561
562             return -date.compareTo(date2);
563         }
564
565     }
566
567     public ISearchCriteria getDefaultCriteria(String JavaDoc searchTerm) {
568         return getCriteria(MailSearchProvider.CRITERIA_SUBJECT_CONTAINS, searchTerm);
569     }
570
571     public boolean hasSingleCriteriaSearchResult() {
572         return singleCriteriaSearch && lastSearchFolder != null;
573     }
574
575 }
576
Popular Tags