001: package net.suberic.pooka;
002:
003: import javax.mail.search.*;
004: import javax.mail.*;
005: import java.util.HashMap;
006: import java.util.Vector;
007: import java.text.DateFormat;
008:
009: /**
010: * This class generates SearchTerms from properties in the Pooka
011: * VariableBundle. It also will give out a list of property labels and
012: * then will translate those labels and/or properties into SearchTerms.
013: *
014: * This class also handles the Filter properties and editors. This might
015: * get moved out of this class eventually.
016: */
017: public class SearchTermManager {
018:
019: HashMap labelToPropertyMap;
020: Vector termLabels;
021: HashMap labelToOperationMap;
022: Vector operationLabels;
023: HashMap typeToLabelMap;
024:
025: DateFormat dateFormat;
026:
027: Class stringTermClass;
028: Class flagTermClass;
029: Class dateTermClass;
030:
031: String sourceProperty;
032:
033: public static String STRING_MATCH = "String";
034: public static String BOOLEAN_MATCH = "Boolean";
035: public static String DATE_MATCH = "Date";
036: public static String HEADER_MATCH = "Header";
037:
038: // filter properties
039:
040: Vector displayFilterLabels;
041: Vector backendFilterLabels;
042: HashMap filterLabelToPropertyMap;
043: HashMap filterClassToPropertyMap;
044:
045: /**
046: * Default constructor. Initializes the labelToPropertyMap and the
047: * termLabels Vector from the Pooka property.
048: */
049: public SearchTermManager(String propertyName) {
050: sourceProperty = propertyName;
051: try {
052: flagTermClass = Class.forName("javax.mail.search.FlagTerm");
053: stringTermClass = Class
054: .forName("javax.mail.search.StringTerm");
055: dateTermClass = Class.forName("javax.mail.search.DateTerm");
056: } catch (Exception e) {
057: }
058: createTermMaps(propertyName + ".searchTerms");
059: createOperationMaps(propertyName + ".operations");
060: createOperationTypeMaps(propertyName);
061:
062: createFilterMaps();
063:
064: dateFormat = new java.text.SimpleDateFormat(Pooka.getProperty(
065: propertyName + ".dateFormat", "MM/dd/yyyy"));
066: }
067:
068: /**
069: * Creates the labelToOperationMap and operationLabels from the given
070: * property, as well as the termLabels Vector.
071: */
072: private void createTermMaps(String propName) {
073: Vector keys = Pooka.getResources().getPropertyAsVector(
074: propName, "");
075: termLabels = new Vector();
076: if (keys != null) {
077: labelToPropertyMap = new HashMap();
078: for (int i = 0; i < keys.size(); i++) {
079: String this Value = propName + "."
080: + (String) keys.elementAt(i);
081: String this Label = Pooka.getProperty(this Value
082: + ".label", (String) keys.elementAt(i));
083: labelToPropertyMap.put(this Label, this Value);
084: termLabels.add(this Label);
085: }
086: }
087: }
088:
089: /**
090: * Creates the labelToOperationMap and operationLabels from the given
091: * propery.
092: */
093: private void createOperationMaps(String propName) {
094: Vector keys = Pooka.getResources().getPropertyAsVector(
095: propName, "");
096: operationLabels = new Vector();
097: if (keys != null) {
098: labelToOperationMap = new HashMap();
099: for (int i = 0; i < keys.size(); i++) {
100: String this Value = propName + "."
101: + (String) keys.elementAt(i);
102: String this Label = Pooka.getProperty(this Value
103: + ".label", (String) keys.elementAt(i));
104: labelToOperationMap.put(this Label, this Value);
105: operationLabels.add(this Label);
106: }
107: }
108: }
109:
110: /**
111: * Creates the typeToLabelMap for the given property.
112: */
113: private void createOperationTypeMaps(String propName) {
114: typeToLabelMap = new HashMap();
115: Vector types = Pooka.getResources().getPropertyAsVector(
116: propName + ".operationTypes", "");
117: for (int i = 0; i < types.size(); i++) {
118: String currentType = (String) types.elementAt(i);
119: Vector currentList = Pooka
120: .getResources()
121: .getPropertyAsVector(
122: propName + ".operationTypes." + currentType,
123: "");
124: Vector labelList = new Vector();
125:
126: for (int j = 0; j < currentList.size(); j++) {
127: labelList
128: .add(Pooka.getProperty(propName
129: + ".operations."
130: + (String) currentList.elementAt(j)
131: + ".label"));
132: }
133:
134: typeToLabelMap.put(currentType, labelList);
135: }
136: }
137:
138: /**
139: * Creates the filter properties.
140: */
141: public void createFilterMaps() {
142: displayFilterLabels = new Vector();
143: backendFilterLabels = new Vector();
144: filterLabelToPropertyMap = new HashMap();
145: filterClassToPropertyMap = new HashMap();
146:
147: Vector filterProperties = Pooka.getResources()
148: .getPropertyAsVector("FolderFilters.display", "");
149: for (int i = 0; i < filterProperties.size(); i++) {
150: String currentProperty = "FolderFilters.display."
151: + (String) filterProperties.elementAt(i);
152: String label = Pooka.getProperty(
153: currentProperty + ".label",
154: (String) filterProperties.elementAt(i));
155: String className = Pooka.getProperty(currentProperty
156: + ".class", "");
157: displayFilterLabels.add(label);
158: filterLabelToPropertyMap.put(label, currentProperty);
159: filterClassToPropertyMap.put(className, currentProperty);
160: }
161:
162: filterProperties = Pooka.getResources().getPropertyAsVector(
163: "FolderFilters.backend", "");
164: for (int i = 0; i < filterProperties.size(); i++) {
165: String currentProperty = "FolderFilters.backend."
166: + (String) filterProperties.elementAt(i);
167: String label = Pooka.getProperty(
168: currentProperty + ".label",
169: (String) filterProperties.elementAt(i));
170: String className = Pooka.getProperty(currentProperty
171: + ".class", "");
172: backendFilterLabels.add(label);
173: filterLabelToPropertyMap.put(label, currentProperty);
174: filterClassToPropertyMap.put(className, currentProperty);
175: }
176: }
177:
178: /**
179: * Generates a compound SearchTerm.
180: */
181: public SearchTerm generateCompoundSearchTerm(String[] properties,
182: String operation) throws java.text.ParseException {
183: SearchTerm[] terms = new SearchTerm[properties.length];
184: for (int i = 0; i < properties.length; i++)
185: terms[i] = generateSearchTermFromProperty(properties[i]);
186:
187: if (operation.equalsIgnoreCase("and"))
188: return new AndTerm(terms);
189: else if (operation.equalsIgnoreCase("or"))
190: return new OrTerm(terms);
191: else
192: return null;
193: }
194:
195: /**
196: * Generates a SearchTerm from a single property root. This method
197: * expects the following sub-properties to be set on the given
198: * property:
199: *
200: * property.type should be set either to 'compound' or 'single'
201: *
202: * for 'single' types:
203: * property.searchTerm
204: * property.operation (optional)
205: * property.pattern (optional)
206: *
207: * for 'compound' types:
208: * property.subTerms
209: * property.operation (should be 'or' or 'and')
210: */
211: public SearchTerm generateSearchTermFromProperty(String property)
212: throws java.text.ParseException {
213: //System.out.println("generating search term for " + property);
214: String type = Pooka.getProperty(property + ".type", "single");
215: if (type.equalsIgnoreCase("single")) {
216: String searchProperty = Pooka.getProperty(property
217: + ".searchTerm", "");
218: String operationProperty = Pooka.getProperty(property
219: + ".operation", "");
220: String pattern = Pooka.getProperty(property + ".pattern",
221: "");
222: String header = Pooka.getProperty(property + ".header", "");
223: return generateSearchTerm(searchProperty,
224: operationProperty, pattern, header);
225: } else if (type.equalsIgnoreCase("compound")) {
226: Vector subTermList = Pooka.getResources()
227: .getPropertyAsVector(property + ".subTerms", "");
228: String[] subTerms = new String[subTermList.size()];
229: for (int i = 0; i < subTerms.length; i++)
230: subTerms[i] = (String) subTermList.elementAt(i);
231: String operation = Pooka.getProperty(property
232: + ".operation", "");
233:
234: return generateCompoundSearchTerm(subTerms, operation);
235: } else
236: return null;
237: }
238:
239: /**
240: * Generates a SearchTerm from the given property and pattern.
241: *
242: * This method used the .class subproperty of the given searchProperty
243: * String to determine what type of SearchTerm to create. If the
244: * .class is an instance of FlagTerm, the .flag subproperty is used
245: * to determine which flag to test. If the .class is an instance
246: * of StringTerm, then .ignoreCase is checked to see whether or not
247: * to ignore case (default to false).
248: *
249: * This also uses the operationProperty to determine whether to make
250: * this a positive or negative search (is or is not), or, in the case
251: * of comparison searches, a greater than or less than search.
252: *
253: */
254: public SearchTerm generateSearchTerm(String searchProperty,
255: String operationProperty, String pattern)
256: throws java.text.ParseException {
257: return generateSearchTerm(searchProperty, operationProperty,
258: pattern, "");
259: }
260:
261: /**
262: * Generates a SearchTerm from the given property and pattern.
263: *
264: * This method used the .class subproperty of the given searchProperty
265: * String to determine what type of SearchTerm to create. If the
266: * .class is an instance of FlagTerm, the .flag subproperty is used
267: * to determine which flag to test. If the .class is an instance
268: * of StringTerm, then .ignoreCase is checked to see whether or not
269: * to ignore case (default to false).
270: *
271: * This also uses the operationProperty to determine whether to make
272: * this a positive or negative search (is or is not), or, in the case
273: * of comparison searches, a greater than or less than search.
274: *
275: */
276: public SearchTerm generateSearchTerm(String searchProperty,
277: String operationProperty, String pattern, String header)
278: throws java.text.ParseException {
279: SearchTerm term = null;
280: try {
281: String className = Pooka.getProperty(searchProperty
282: + ".class", "");
283: Class stClass = Class.forName(className);
284:
285: // ****** Create a StringTerm.
286: if (stringTermClass.isAssignableFrom(stClass)) {
287: boolean ignoreCase = Pooka.getProperty(
288: searchProperty + ".ignoreCase", "false")
289: .equals("true");
290:
291: // check for the special cases.
292: if (className
293: .equals("javax.mail.search.RecipientStringTerm")) {
294: String recipientType = Pooka.getProperty(
295: searchProperty + ".recipientType", "to");
296: if (recipientType.equalsIgnoreCase("to"))
297: term = new RecipientStringTerm(
298: javax.mail.Message.RecipientType.TO,
299: pattern);
300: else if (recipientType.equalsIgnoreCase("cc"))
301: term = new RecipientStringTerm(
302: javax.mail.Message.RecipientType.CC,
303: pattern);
304: else if (recipientType.equalsIgnoreCase("toorcc"))
305: term = new OrTerm(new RecipientStringTerm(
306: javax.mail.Message.RecipientType.CC,
307: pattern), new RecipientStringTerm(
308: javax.mail.Message.RecipientType.TO,
309: pattern));
310:
311: } else if (className
312: .equals("javax.mail.search.HeaderTerm")) {
313: term = new HeaderTerm(header, pattern);
314: } else {
315: // default case for StringTerms
316:
317: java.lang.reflect.Constructor termConst = stClass
318: .getConstructor(new Class[] { Class
319: .forName("java.lang.String") });
320: term = (SearchTerm) termConst
321: .newInstance(new Object[] { pattern });
322:
323: }
324: }
325:
326: // ********** Create a FlagTerm
327:
328: else if (flagTermClass.isAssignableFrom(stClass)) {
329: term = new FlagTerm(getFlags(Pooka.getProperty(
330: searchProperty + ".flag", "")), Pooka
331: .getProperty(searchProperty + ".value", "true")
332: .equalsIgnoreCase("true"));
333: }
334:
335: // ********** Create a DateTerm
336:
337: else if (dateTermClass.isAssignableFrom(stClass)) {
338:
339: java.util.Date compareDate = dateFormat.parse(pattern);
340:
341: int comparison = 0;
342:
343: String operationPropertyType = Pooka.getProperty(
344: operationProperty, "");
345: if (operationPropertyType.equalsIgnoreCase("equals")
346: || operationPropertyType
347: .equalsIgnoreCase("notEquals"))
348: comparison = DateTerm.EQ;
349: else if (operationPropertyType
350: .equalsIgnoreCase("before"))
351: comparison = DateTerm.LT;
352: else if (operationPropertyType
353: .equalsIgnoreCase("after"))
354: comparison = DateTerm.GT;
355:
356: java.lang.reflect.Constructor termConst = stClass
357: .getConstructor(new Class[] { Integer.TYPE,
358: Class.forName("java.util.Date") });
359: term = (SearchTerm) termConst.newInstance(new Object[] {
360: new Integer(comparison), compareDate });
361: }
362:
363: // ********** Default Case, no term known.
364:
365: else {
366: // default case for any term.
367: term = (SearchTerm) stClass.newInstance();
368: }
369:
370: // *********** Handles not cases.
371:
372: String operationPropertyValue = Pooka.getProperty(
373: operationProperty, "");
374: if (operationPropertyValue.equalsIgnoreCase("not")
375: || operationPropertyValue
376: .equalsIgnoreCase("notEquals"))
377: term = new NotTerm(term);
378: } catch (ClassNotFoundException cnfe) {
379: showError(Pooka.getProperty(
380: "error.search.generatingSearchTerm",
381: "Error generating SearchTerm: "), cnfe);
382: } catch (NoSuchMethodException nsme) {
383: showError(Pooka.getProperty(
384: "error.search.generatingSearchTerm",
385: "Error generating SearchTerm: "), nsme);
386: } catch (InstantiationException ie) {
387: showError(Pooka.getProperty(
388: "error.search.generatingSearchTerm",
389: "Error generating SearchTerm: "), ie);
390: } catch (IllegalAccessException iae) {
391: showError(Pooka.getProperty(
392: "error.search.generatingSearchTerm",
393: "Error generating SearchTerm: "), iae);
394: } catch (java.lang.reflect.InvocationTargetException ite) {
395: showError(Pooka.getProperty(
396: "error.search.generatingSearchTerm",
397: "Error generating SearchTerm: "), ite);
398: }
399:
400: return term;
401: }
402:
403: /**
404: * This creates a javax.mail.Flags object containing the flag indicated
405: * by flagName.
406: */
407: public Flags getFlags(String flagName) {
408: if (flagName.equalsIgnoreCase("answered"))
409: return new Flags(Flags.Flag.ANSWERED);
410: else if (flagName.equalsIgnoreCase("deleted"))
411: return new Flags(Flags.Flag.DELETED);
412: else if (flagName.equalsIgnoreCase("draft"))
413: return new Flags(Flags.Flag.DRAFT);
414: else if (flagName.equalsIgnoreCase("flagged"))
415: return new Flags(Flags.Flag.FLAGGED);
416: else if (flagName.equalsIgnoreCase("recent"))
417: return new Flags(Flags.Flag.RECENT);
418: else if (flagName.equalsIgnoreCase("seen"))
419: return new Flags(Flags.Flag.SEEN);
420:
421: return new Flags(flagName);
422: }
423:
424: /**
425: * Returns the available flag labels.
426: */
427: public Vector getFlagLabels() {
428: // FIXME this isn't customizable or internationalized at all.
429: Vector v = new Vector();
430: v.add("flagged");
431: v.add("seen");
432: v.add("answered");
433: v.add("deleted");
434: v.add("draft");
435: v.add("recent");
436: return v;
437: }
438:
439: /**
440: * Returns the display filter labels.
441: */
442: public Vector getDisplayFilterLabels() {
443: return displayFilterLabels;
444: }
445:
446: /**
447: * Returns the backend filter labels.
448: */
449: public Vector getBackendFilterLabels() {
450: return backendFilterLabels;
451: }
452:
453: /**
454: * creates an editor for a given filter label.
455: */
456: public net.suberic.pooka.gui.filter.FilterEditor getEditorForFilterLabel(
457: String label) {
458:
459: String property = (String) filterLabelToPropertyMap.get(label);
460: String className = Pooka.getProperty(property + ".editorClass",
461: "");
462: if (className.equals(""))
463: return null;
464: else {
465: try {
466: Class editorClass = Class.forName(className);
467: net.suberic.pooka.gui.filter.FilterEditor editor = (net.suberic.pooka.gui.filter.FilterEditor) editorClass
468: .newInstance();
469: return editor;
470: } catch (Exception e) {
471: e.printStackTrace();
472: return null;
473: }
474: }
475: }
476:
477: /**
478: * Returns the appropriate label for the given filter class.
479: */
480: public String getLabelForFilterClass(String className) {
481: String property = (String) filterClassToPropertyMap
482: .get(className);
483: String label = Pooka.getProperty(property + ".label", "");
484: return label;
485: }
486:
487: /**
488: * Shows an error message.
489: */
490: public void showError(String message, Exception e) {
491: if (Pooka.getUIFactory() != null)
492: Pooka.getUIFactory().showError(message, e);
493: else {
494: System.err.println(message + e.getMessage());
495: e.printStackTrace();
496: }
497: }
498:
499: // accessor methods
500:
501: public HashMap getLabelToPropertyMap() {
502: return labelToPropertyMap;
503: }
504:
505: public Vector getTermLabels() {
506: return termLabels;
507: }
508:
509: public HashMap getLabelToOperationMap() {
510: return labelToOperationMap;
511: }
512:
513: public Vector getOperationLabels() {
514: return operationLabels;
515: }
516:
517: public Vector getOperationLabels(String operationType) {
518: return (Vector) typeToLabelMap.get(operationType);
519: }
520: }
|