You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by rd...@apache.org on 2008/03/02 21:21:28 UTC

svn commit: r632829 - in /james/server/trunk: core-library/src/main/java/org/apache/james/mailboxmanager/ core-library/src/main/java/org/apache/james/mailboxmanager/mailbox/ imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/proc...

Author: rdonkin
Date: Sun Mar  2 12:21:26 2008
New Revision: 632829

URL: http://svn.apache.org/viewvc?rev=632829&view=rev
Log:
Redesigned search query to reduce work for backend implementors and to increase protocol independence.

Added:
    james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/SearchQuery.java
      - copied, changed from r632730, james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/SearchParameters.java
Removed:
    james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/SearchParameters.java
Modified:
    james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/mailbox/ImapMailbox.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/SearchProcessor.java
    james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/SearchCommand.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMailbox.java

Copied: james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/SearchQuery.java (from r632730, james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/SearchParameters.java)
URL: http://svn.apache.org/viewvc/james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/SearchQuery.java?p2=james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/SearchQuery.java&p1=james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/SearchParameters.java&r1=632730&r2=632829&rev=632829&view=diff
==============================================================================
--- james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/SearchParameters.java (original)
+++ james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/SearchQuery.java Sun Mar  2 12:21:26 2008
@@ -20,74 +20,298 @@
 package org.apache.james.mailboxmanager;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
-public class SearchParameters {
+import javax.mail.Flags.Flag;
 
-	public static final String HEADER = "HEADER";
-    public static final String UID = "UID";
-    public static final String NOT = "NOT";
-    public static final String OR = "OR";
-    public static final String SMALLER = "SMALLER";
-    public static final String LARGER = "LARGER";
-    public static final String SINCE = "SINCE";
-    public static final String SENTSINCE = "SENTSINCE";
-    public static final String SENTON = "SENTON";
-    public static final String SENTBEFORE = "SENTBEFORE";
-    public static final String ON = "ON";
-    public static final String BEFORE = "BEFORE";
-    public static final String UNKEYWORD = "UNKEYWORD";
-    public static final String TO = "TO";
-    public static final String TEXT = "TEXT";
-    public static final String SUBJECT = "SUBJECT";
-    public static final String KEYWORD = "KEYWORD";
-    public static final String FROM = "FROM";
-    public static final String CC = "CC";
-    public static final String BODY = "BODY";
-    public static final String BCC = "BCC";
-    public static final String UNSEEN = "UNSEEN";
-    public static final String UNFLAGGED = "UNFLAGGED";
-    public static final String UNDRAFT = "UNDRAFT";
-    public static final String UNDELETED = "UNDELETED";
-    public static final String UNANSWERED = "UNANSWERED";
-    public static final String SEEN = "SEEN";
-    public static final String RECENT = "RECENT";
-    public static final String OLD = "OLD";
-    public static final String NEW = "NEW";
-    public static final String FLAGGED = "FLAGGED";
-    public static final String DRAFT = "DRAFT";
-    public static final String DELETED = "DELETED";
-    public static final String ANSWERED = "ANSWERED";
-    public static final String ALL = "ALL";
-    
-    public final static Set BASE_SEARCH_TERMS = Collections.unmodifiableSet(new HashSet(Arrays.asList(new String[] {
-        	ALL, ANSWERED, DELETED, DRAFT, FLAGGED, NEW, OLD, RECENT, SEEN,
-        	UNANSWERED, UNDELETED, UNDRAFT, UNFLAGGED, UNSEEN
-        })));
-    
-    public final static Set STRING_SEARCH_TERMS = Collections.unmodifiableSet(new HashSet(Arrays.asList(new String[] {
-        	BCC, BODY, CC, FROM, KEYWORD, SUBJECT, TEXT, TO, UNKEYWORD
-        })));
-    public final static Set DATE_SEARCH_TERMS = Collections.unmodifiableSet(new HashSet(Arrays.asList(new String[] {
-        	BEFORE, ON, SENTBEFORE, SENTON, SENTSINCE , SINCE
-        })));
-    public final static Set NUMBER_SEARCH_TERMS = Collections.unmodifiableSet(new HashSet(Arrays.asList(new String[] {
-        	LARGER, SMALLER
-        })));
-
-	public final static Set SPECIAL_SEARCH_TERMS = new HashSet(Arrays.asList(new String[] {
-        	OR, NOT,UID, HEADER
-    }));
+/**
+ * <p>Models a query used to search for messages.
+ * A query is the logical <code>AND</code> of the contained criteria.
+ * </p><p>
+ * Each <code>Criterion</code> is composed of an <code>Operator</code>
+ * (combining value and operation) together with field
+ * information (optional since the criteria type may imply a particular
+ * field).
+ * Factory methods are provided for criteria.
+ * </p> 
+ */
+public class SearchQuery {
+
+    /**
+     * Creates a filter for message size less than the given value
+     * @param value messages with size less than this value will be selected
+     * by the returned criterion
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion sizeLessThan(long value) {
+        return new SizeCriterion(new NumericOperator(value, NumericOperator.LESS_THAN));
+    }
+
+    /**
+     * Creates a filter for message size greater than the given value
+     * @param value messages with size greater than this value will be selected
+     * by the returned criterion
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion sizeGreaterThan(long value) {
+        return new SizeCriterion(new NumericOperator(value, NumericOperator.GREATER_THAN));
+    }
+    
+    /**
+     * Creates a filter matching messages with internal date after the given date.
+     * @param day one based day of the month
+     * @param month one based month of the year
+     * @param year year
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion internalDateAfter(int day, int month, int year) {
+        return new InternalDateCriterion(new DateOperator(DateOperator.AFTER, day, month, year));
+    }
+
+    /**
+     * Creates a filter matching messages with internal date on the given date.
+     * @param day one based day of the month
+     * @param month one based month of the year
+     * @param year year
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion internalDateOn(int day, int month, int year) {
+        return new InternalDateCriterion(new DateOperator(DateOperator.ON, day, month, year));
+    }
+    
+
+    /**
+     * Creates a filter matching messages with internal date before the given date.
+     * @param day one based day of the month
+     * @param month one based month of the year
+     * @param year year
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion internalDateBefore(int day, int month, int year) {
+        return new InternalDateCriterion(new DateOperator(DateOperator.BEFORE, day, month, year));
+    }
+    
 
-		
-	List criterias = new ArrayList();
+    /**
+     * Creates a filter matching messages with the date of the given header
+     * after the given date. If the header's value is not a date then it will
+     * not be included.
+     * @param headerName name of the header whose value will be compared, not null
+     * @param day one based day of the month
+     * @param month one based month of the year
+     * @param year year
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion headerDateAfter(String headerName, int day, int month, int year) {
+        return new HeaderCriterion(headerName, new DateOperator(DateOperator.AFTER, day, month, year));
+    }
+    
+    /**
+     * Creates a filter matching messages with the date of the given header
+     * on the given date. If the header's value is not a date then it will
+     * not be included.
+     * @param headerName name of the header whose value will be compared, not null
+     * @param day one based day of the month
+     * @param month one based month of the year
+     * @param year year
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion headerDateOn(String headerName, int day, int month, int year) {
+        return new HeaderCriterion(headerName, new DateOperator(DateOperator.ON, day, month, year));
+    }
+    
+    /**
+     * Creates a filter matching messages with the date of the given header
+     * before the given date. If the header's value is not a date then it will
+     * not be included.
+     * @param headerName name of the header whose value will be compared, not null
+     * @param day one based day of the month
+     * @param month one based month of the year
+     * @param year year
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion headerDateBefore(String headerName, int day, int month, int year) {
+        return new HeaderCriterion(headerName, new DateOperator(DateOperator.BEFORE, day, month, year));
+    }
+    
+    /**
+     * Creates a filter matching messages whose header value contains the given value.
+     * @param headerName name of the header whose value will be compared, not null
+     * @param value when null or empty the existance of the header will be checked, 
+     * otherwise contained value 
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion headerContains(String headerName, String value) {
+        if (value == null || value.length() == 0) {
+            return headerExists(headerName);
+        } else {
+            return new HeaderCriterion(headerName, new ContainsOperator(value));
+        }
+    }
+    
+    /**
+     * Creates a filter matching messages with a header matching the given name.
+     * @param headerName name of the header whose value will be compared, not null
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion headerExists(String headerName) {
+        return new HeaderCriterion(headerName, ExistsOperator.exists());
+    }
+    
+    /**
+     * Creates a filter matching messages which contains the given text
+     * either within the body or in the headers. Implementations may choose
+     * to ignore mime parts which cannot be decoded to text.
+     * @param value search value 
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion mailContains(String value) {
+        return new TextCriterion(value, TextCriterion.FULL_MESSAGE);
+    }
+    
+    /**
+     * Creates a filter matching messages which contains the given text
+     * within the body. Implementations may choose
+     * to ignore mime parts which cannot be decoded to text.
+     * @param value search value 
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion bodyContains(String value) {
+        return new TextCriterion(value, TextCriterion.BODY);
+    }
+    
+    /**
+     * Creates a filter matching messages within any of the given ranges.
+     * @param range <code>NumericRange</code>'s, not null
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion uid(NumericRange[] range) {
+        return new UidCriterion(range);
+    }
+    
+    /**
+     * Creates a filter composing the two different criteria.
+     * @param one <code>Criterion</code>, not null
+     * @param two <code>Criterion</code>, not null
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion or(Criterion one, Criterion two) {
+        final List criteria = new ArrayList();
+        criteria.add(one);
+        criteria.add(two);
+        return new ConjunctionCriterion(ConjunctionCriterion.OR, criteria);
+    }
+    
+    /**
+     * Creates a filter composing the two different criteria.
+     * @param one <code>Criterion</code>, not null
+     * @param two <code>Criterion</code>, not null
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion and(Criterion one, Criterion two) {
+        final List criteria = new ArrayList();
+        criteria.add(one);
+        criteria.add(two);
+        return new ConjunctionCriterion(ConjunctionCriterion.AND, criteria);
+    }
+    
+    /**
+     * Creates a filter inverting the given criteria.
+     * @param criterion <code>Criterion</code>, not null
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion not(Criterion criterion) {
+        final List criteria = new ArrayList();
+        criteria.add(criterion);
+        return new ConjunctionCriterion(ConjunctionCriterion.NOR, criteria);
+    }
+    
+    /**
+     * Creates a filter on the given flag.
+     * @param flag <code>Flag</code>, not null
+     * @param isSet true if the messages with the flag set should be matched,
+     * false otherwise 
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion flagSet(final Flag flag, final boolean isSet) {
+        final Criterion result;
+        if (isSet) {
+            result = flagIsSet(flag);
+        } else {
+            result = flagIsUnSet(flag);
+        }
+        return result;
+    }
+    
+    /**
+     * Creates a filter on the given flag selecting messages where the given
+     * flag is selected.
+     * @param flag <code>Flag</code>, not null
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion flagIsSet(final Flag flag) {
+        return new FlagCriterion(flag, BooleanOperator.set());
+    }
+    
+    /**
+     * Creates a filter on the given flag selecting messages where the given
+     * flag is not selected.
+     * @param flag <code>Flag</code>, not null
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion flagIsUnSet(final Flag flag) {
+        return new FlagCriterion(flag, BooleanOperator.unset());
+    }
+    
+    /**
+     * Creates a filter on the given flag.
+     * @param flag <code>Flag</code>, not null
+     * @param isSet true if the messages with the flag set should be matched,
+     * false otherwise 
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion flagSet(final String flag, final boolean isSet) {
+        final Criterion result;
+        if (isSet) {
+            result = flagIsSet(flag);
+        } else {
+            result = flagIsUnSet(flag);
+        }
+        return result;
+    }
+    
+    /**
+     * Creates a filter on the given flag selecting messages where the given
+     * flag is selected.
+     * @param flag <code>Flag</code>, not null
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion flagIsSet(final String flag) {
+        return new CustomFlagCriterion(flag, BooleanOperator.set());
+    }
+    
+    /**
+     * Creates a filter on the given flag selecting messages where the given
+     * flag is not selected.
+     * @param flag <code>Flag</code>, not null
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion flagIsUnSet(final String flag) {
+        return new CustomFlagCriterion(flag, BooleanOperator.unset());
+    }
+    
+    /**
+     * Creates a filter matching all messages.
+     * @return <code>Criterion</code>, not null
+     */
+    public static final Criterion all() {
+        return AllCriterion.all();
+    }
+    
+    
+    List criterias = new ArrayList();
 	
-	public void addCriteria(SearchCriteria crit) {
+	public void andCriteria(Criterion crit) {
 		criterias.add(crit);
 	}
 	
@@ -99,191 +323,13 @@
 	public String toString() {
 		return "Search:"+criterias.toString();
 	}
-	
-	public static class SearchCriteria {
-		
-		
-		public String getName() {
-			return "search-criteria";
-		}
-		
-		// @Override
-		public String toString() {
-			return "['"+getName()+"']";
-		}
-	}
-
-	public static class NamedSearchCriteria extends SearchCriteria {
-		String name;
-		
-		public NamedSearchCriteria(String name) {
-			this.name = name;
-		}
-		
-		public String getName() {
-			return name;
-		}
-		
-		// @Override
-		public String toString() {
-			return "['"+name+"']";
-		}
-	}
-
-	public static class StringSearchCriteria extends NamedSearchCriteria {
-		String value;
-
-		public StringSearchCriteria(String name, String value) {
-			super(name);
-			this.value = value;
-		}
-		
-		public String getValue() {
-			return value;
-		}
-		public String toString() {
-			return "['"+name+"':'"+value+"']";
-		}
-	}
-	
-	public static class NumberSearchCriteria extends NamedSearchCriteria {
-		long value;
-
-		public NumberSearchCriteria(String name, long value) {
-			super(name);
-			this.value = value;
-		}
-		
-		public long getValue() {
-			return value;
-		}
-		public String toString() {
-			return "['"+name+"':'"+value+"']";
-		}
-	}
-	
-	
-
-	public static class DateSearchCriteria extends NamedSearchCriteria {
-		Date value;
-
-		public DateSearchCriteria(String name, Date value) {
-			super(name);
-			this.value = value;
-		}
-		
-		public Date getValue() {
-			return value;
-		}
-		public String toString() {
-			return "['"+name+"':'"+value+"']";
-		}
-		
-	}
-
-	public static class HeaderSearchCriteria extends SearchCriteria {
-		String fieldName;
-		String value;
-		
-		public HeaderSearchCriteria(String fieldName, String value) {
-			this.fieldName = fieldName;
-			this.value = value;
-		}
-		public String getName() {
-			return HEADER;
-		}
-
-		public String getFieldName() {
-			return fieldName;
-		}
-		
-		public String getValue() {
-			return value;
-		}
-		
-		public String toString() {
-			return "[header:'"+fieldName+"':'"+value+"']";
-		}
-
-	}
-	
-	public static class UIDSearchCriteria extends SearchCriteria {
-        NumericRange[] idRanges;
-
-		public UIDSearchCriteria(NumericRange[] idRanges) {
-			this.idRanges = idRanges;
-		}
-		public String getName() {
-			return UID;
-		}
-		
-		public NumericRange[] getIdRanges() {
-			return idRanges;
-		}
-	}
-	
-	public static class NotSearchCriteria extends SearchCriteria {
-		final List criteria;
-		
-		public NotSearchCriteria(SearchCriteria inverse) {
-			this();
-            add(inverse);
-		}
-        
-        public NotSearchCriteria() {
-            this.criteria = new ArrayList();
-        }
-        
-        public void add(SearchCriteria criterion) {
-            criteria.add(criterion);
-        }
-		
-		public String getName() {
-			return NOT;
-		}
-
-		public List getCriteria() {
-			return criteria;
-		}
-		
-		public String toString() {
-			return "[NOT "+ criteria +"]";
-		}
-		
-	}
-	public static class OrSearchCriteria extends SearchCriteria {
-		final List criteria;
-		
-		public OrSearchCriteria (SearchCriteria a, SearchCriteria b) {
-			this();
-			add(a);
-            add(b);
-		}
-        
-        public OrSearchCriteria() {
-            criteria = new ArrayList();
-        }
-        
-        public void add(SearchCriteria criterion) {
-            criteria.add(criterion);
-        }
-		
-		public String getName() {
-			return OR;
-		}
-
-
-		public List getCriteria() {
-			return criteria;
-		}
-
-		public String toString() {
-			return "[OR "+ criteria +"]";
-		}
-		
-	}
-
-	
+    
+    /**
+     * Numbers within a particular range.
+     * Range includes both high and low boundaries.
+     * May be a single value.
+     * {@link Long#MAX_VALUE} represents unlimited in either direction.
+     */
 	public static final class NumericRange {
 	    private final long lowValue;
         private final long highValue;
@@ -310,6 +356,437 @@
         
         public String toString() {
             return "[" + lowValue + "->" + highValue + "]";
+        }
+    }
+    
+    /**
+     * Marker superclass for criteria.
+     */
+    public static abstract class Criterion {}
+    
+    /**
+     * Conjuction applying to the contained criteria.
+     * {@link #getType} indicates how the conjoined criteria
+     * should be related.
+     */
+    public static final class ConjunctionCriterion extends Criterion {
+        /** Logical <code>AND</code> */
+        public static final int AND = 1;
+        /** Logical <code>OR</code> */
+        public static final int OR = 2;
+        /** Logical <code>NOT</code> */
+        public static final int NOR = 3;
+        
+        private final int type;
+        private final List criteria;
+        
+        public ConjunctionCriterion(final int type, final List criteria) {
+            super();
+            this.type = type;
+            this.criteria = criteria;
+        }
+        
+        /**
+         * Gets the criteria related through this conjuction.
+         * @return <code>List</code> of {@link Criterion}
+         */
+        public final List getCriteria() {
+            return criteria;
+        }
+        
+        /**
+         * Gets the type of conjunction.
+         * @return the type, either {@link #AND}, {@link #OR} or {@link NOR}
+         */
+        public final int getType() {
+            return type;
+        }
+        
+        
+    }
+    
+    /**
+     * Any message.
+     */
+    public static final class AllCriterion extends Criterion {
+        private static final AllCriterion ALL = new AllCriterion();
+        
+        private static final Criterion all() {
+            return ALL;
+        }
+    }
+    
+    /**
+     * Message text.
+     */
+    public static final class TextCriterion extends Criterion {
+        /**
+         * Only the message body content.
+         */
+        public static final int BODY = 1;
+        /**
+         * The full message content including headers.
+         */
+        public static final int FULL_MESSAGE = 2;
+        
+        private final int type;
+        private final ContainsOperator operator;
+
+        private TextCriterion(final String value, final int type) {
+            super();
+            this.operator = new ContainsOperator(value);
+            this.type = type;
+        }
+        
+        /**
+         * Gets the type of text to be searched.
+         * @return the type, either {@link #BODY} or {@link #FULL_MESSAGE}
+         */
+        public final int getType() {
+            return type;
+        }
+
+        /**
+         * Gets the search operation and value to be evaluated.
+         * @return the <code>Operator</code>, not null
+         */
+        public final ContainsOperator getOperator() {
+            return operator;
+        }
+    }
+    
+    /**
+     * Header value content search.
+     */
+    public static final class HeaderCriterion extends Criterion {
+        private final HeaderOperator operator;
+        private final String headerName;
+
+        private HeaderCriterion(final String headerName, final HeaderOperator operator) {
+            super();
+            this.operator = operator;
+            this.headerName = headerName;
+        }
+
+        /**
+         * Gets the name of the header whose value is to be searched.
+         * @return the headerName
+         */
+        public final String getHeaderName() {
+            return headerName;
+        }
+
+        /**
+         * Gets the search operation and value to be evaluated.
+         * @return the <code>Operator</code>, not null
+         */
+        public final HeaderOperator getOperator() {
+            return operator;
+        }
+    }
+    
+    /**
+     * Filters on the internal date.
+     */
+    public static final class InternalDateCriterion extends Criterion {
+        private final DateOperator operator;
+
+        public InternalDateCriterion(final DateOperator operator) {
+            super();
+            this.operator = operator;
+        }
+
+        /**
+         * Gets the search operation and value to be evaluated.
+         * @return the <code>Operator</code>, not null
+         */
+        public final DateOperator getOperator() {
+            return operator;
+        }
+    }
+    
+    /**
+     * Filters on the size of the message in octets.
+     */
+    public static final class SizeCriterion extends Criterion {
+        private final NumericOperator operator;
+        private SizeCriterion(final NumericOperator operator) {
+            super();
+            this.operator = operator;
+        }
+        
+        /**
+         * Gets the search operation and value to be evaluated.
+         * @return the <code>NumericOperator</code>, not null
+         */
+        public final NumericOperator getOperator() {
+            return operator;
+        }
+    }
+    
+    /**
+     * Filters on a custom flag valuation.
+     */
+    public static final class CustomFlagCriterion extends Criterion {
+        private final String flag;
+        private final BooleanOperator operator;
+        
+        private CustomFlagCriterion(final String flag, final BooleanOperator operator) {
+            super();
+            this.flag = flag;
+            this.operator = operator;
+        }
+        
+        /**
+         * Gets the custom flag to be search.
+         * @return the flag name, not null
+         */
+        public final String getFlag() {
+            return flag;
+        }
+        
+        /**
+         * Gets the value to be tested.
+         * @return the <code>BooleanOperator</code>, not null
+         */
+        public final BooleanOperator getOperator() {
+            return operator;
+        }
+        
+        
+    }
+    
+    /**
+     * Filters on a standard flag.
+     */
+    public static final class FlagCriterion extends Criterion {
+        private final Flag flag;
+        private final BooleanOperator operator;
+        
+        private FlagCriterion(final Flag flag, final BooleanOperator operator) {
+            super();
+            this.flag = flag;
+            this.operator = operator;
+        }
+
+        /**
+         * Gets the flag filtered on.
+         * @return the flag, not null
+         */
+        public final Flag getFlag() {
+            return flag;
+        }
+
+        /**
+         * Gets the test to be preformed.
+         * @return the <code>BooleanOperator</code>, not null
+         */
+        public final BooleanOperator getOperator() {
+            return operator;
+        }
+    }
+    
+    /**
+     * Filters on message identity.
+     */
+    public static final class UidCriterion extends Criterion {
+        private final InOperator operator;
+
+        public UidCriterion(final NumericRange[] ranges) {
+            super();
+            this.operator = new InOperator(ranges);
+        }
+
+        /**
+         * Gets the filtering operation.
+         * @return the <code>InOperator</code>
+         */
+        public final InOperator getOperator() {
+            return operator;
+        }
+    }
+    
+    /**
+     * Search operator.
+     */
+    public static abstract class Operator {}
+    
+    /**
+     * Marks operator as suitable for header value searching.
+     */
+    public interface HeaderOperator {}
+    
+    /**
+     * Contained value search.
+     */
+    public static final class ContainsOperator extends Operator implements HeaderOperator {
+        private final String value;
+
+        public ContainsOperator(final String value) {
+            super();
+            this.value = value;
+        }
+
+        /**
+         * Gets the value to be searched for.
+         * @return the value
+         */
+        public final String getValue() {
+            return value;
+        }
+    }
+    
+    /**
+     * Existance search.
+     */
+    public static final class ExistsOperator extends Operator implements HeaderOperator  {
+        private static final ExistsOperator EXISTS = new ExistsOperator();
+        
+        public static final ExistsOperator exists() {
+            return EXISTS;
+        }
+    }
+        
+    /**
+     * Boolean value search.
+     */
+    public static final class BooleanOperator extends Operator {
+        
+        private static final BooleanOperator SET = new BooleanOperator(true);
+        private static final BooleanOperator UNSET = new BooleanOperator(false);
+        
+        public static final BooleanOperator set() {
+            return SET;
+        }
+        
+        public static final BooleanOperator unset() {
+            return UNSET;
+        }
+        
+        private final boolean set;
+
+        private BooleanOperator(final boolean set) {
+            super();
+            this.set = set;
+        }
+
+        /**
+         * Is the search for set?
+         * @return true indicates that set values 
+         * should be selected, false indicates
+         * that unset values should be selected
+         */
+        public final boolean isSet() {
+            return set;
+        }
+    }
+    
+    /**
+     * Searches numberic values.
+     */
+    public static final class NumericOperator extends Operator {
+        public static final int EQUALS = 1;
+        public static final int LESS_THAN = 2;
+        public static final int GREATER_THAN = 3;
+        
+        private final long value;
+        private final int type;
+        
+        private NumericOperator(final long value, final int type) {
+            super();
+            this.value = value;
+            this.type = type;
+        }
+
+        /**
+         * Gets the operation type
+         * @return the type either {@link #EQUALS}, {@link #LESS_THAN} or {@link #GREATER_THAN}
+         */
+        public final int getType() {
+            return type;
+        }
+
+        /**
+         * Gets the value to be compared.
+         * @return the value
+         */
+        public final long getValue() {
+            return value;
+        }
+    }
+    
+    /**
+     * Operates on a date.
+     */
+    public static final class DateOperator extends Operator implements HeaderOperator  {
+        public static final int BEFORE = 1;
+        public static final int AFTER = 2;
+        public static final int ON = 3;
+        
+        private final int type;
+        private final int day;
+        private final int month;
+        private final int year;
+        
+        public DateOperator(final int type, final int day, final int month, final int year) {
+            super();
+            this.type = type;
+            this.day = day;
+            this.month = month;
+            this.year = year;
+        }
+        
+        /**
+         * Gets the day-of-the-month.
+         * @return the day, one based
+         */
+        public final int getDay() {
+            return day;
+        }
+        
+        /**
+         * Gets the month-of-the-year.
+         * @return the month, one based
+         */
+        public final int getMonth() {
+            return month;
+        }
+        
+        /**
+         * Gets the operator type.
+         * @return the type, either {@link #BEFORE}, {@link #AFTER} or {@link ON}
+         */
+        public final int getType() {
+            return type;
+        }
+        
+        /**
+         * Gets the year.
+         * @return the year
+         */
+        public final int getYear() {
+            return year;
+        }
+    }
+    
+    /**
+     * Search for numbers within set of ranges.
+     */
+    public static final class InOperator extends Operator {
+        private final NumericRange[] range;
+
+        public InOperator(final NumericRange[] range) {
+            super();
+            this.range = range;
+        }
+
+        /**
+         * Gets the filtering ranges.
+         * Values falling within these ranges will be selected. 
+         * @return the <code>NumericRange</code>'s search on, not null
+         */
+        public final NumericRange[] getRange() {
+            return range;
         }
     }
 }

Modified: james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/mailbox/ImapMailbox.java
URL: http://svn.apache.org/viewvc/james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/mailbox/ImapMailbox.java?rev=632829&r1=632828&r2=632829&view=diff
==============================================================================
--- james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/mailbox/ImapMailbox.java (original)
+++ james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/mailbox/ImapMailbox.java Sun Mar  2 12:21:26 2008
@@ -29,7 +29,7 @@
 import org.apache.james.mailboxmanager.MailboxManagerException;
 import org.apache.james.mailboxmanager.MailboxSession;
 import org.apache.james.mailboxmanager.MessageResult;
-import org.apache.james.mailboxmanager.SearchParameters;
+import org.apache.james.mailboxmanager.SearchQuery;
 import org.apache.james.mailboxmanager.MessageResult.FetchGroup;
 
 
@@ -56,8 +56,7 @@
      * @throws UnsupportedCriteriaException when any of the search parameters are 
      * not supported by this mailbox
      */
-    Iterator search(GeneralMessageSet set, SearchParameters searchTerm, FetchGroup fetchGroup, 
-            MailboxSession mailboxSession) throws MailboxManagerException;
+    Iterator search(SearchQuery searchQuery, FetchGroup fetchGroup, MailboxSession mailboxSession) throws MailboxManagerException;
     
     
     long getUidValidity(MailboxSession mailboxSession) throws MailboxManagerException;

Modified: james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/SearchProcessor.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/SearchProcessor.java?rev=632829&r1=632828&r2=632829&view=diff
==============================================================================
--- james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/SearchProcessor.java (original)
+++ james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/SearchProcessor.java Sun Mar  2 12:21:26 2008
@@ -41,10 +41,9 @@
 import org.apache.james.imapserver.store.MailboxException;
 import org.apache.james.mailboxmanager.MailboxManagerException;
 import org.apache.james.mailboxmanager.MessageResult;
-import org.apache.james.mailboxmanager.SearchParameters;
+import org.apache.james.mailboxmanager.SearchQuery;
 import org.apache.james.mailboxmanager.MessageResult.FetchGroup;
 import org.apache.james.mailboxmanager.impl.FetchGroupImpl;
-import org.apache.james.mailboxmanager.impl.GeneralMessageSetImpl;
 import org.apache.james.mailboxmanager.mailbox.ImapMailbox;
 
 public class SearchProcessor extends AbstractImapRequestProcessor {
@@ -76,8 +75,8 @@
         final Iterator it;
         try {
             // TODO: implementation
-            it = mailbox.search(GeneralMessageSetImpl.all(),
-                    new SearchParameters(), resultCode, ImapSessionUtils.getMailboxSession(session));
+            it = mailbox.search(new SearchQuery(),
+                    resultCode, ImapSessionUtils.getMailboxSession(session));
         } catch (MailboxManagerException e) {
             throw new MailboxException(e);
         }

Modified: james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/SearchCommand.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/SearchCommand.java?rev=632829&r1=632828&r2=632829&view=diff
==============================================================================
--- james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/SearchCommand.java (original)
+++ james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/SearchCommand.java Sun Mar  2 12:21:26 2008
@@ -19,7 +19,15 @@
 
 package org.apache.james.imapserver.commands;
 
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Set;
+
+import javax.mail.Flags.Flag;
 
 import org.apache.james.imapserver.ImapRequestLineReader;
 import org.apache.james.imapserver.ImapResponse;
@@ -29,13 +37,13 @@
 import org.apache.james.imapserver.store.MailboxException;
 import org.apache.james.mailboxmanager.MailboxManagerException;
 import org.apache.james.mailboxmanager.MessageResult;
-import org.apache.james.mailboxmanager.SearchParameters;
+import org.apache.james.mailboxmanager.SearchQuery;
 import org.apache.james.mailboxmanager.MessageResult.FetchGroup;
-import org.apache.james.mailboxmanager.SearchParameters.NumericRange;
-import org.apache.james.mailboxmanager.SearchParameters.SearchCriteria;
+import org.apache.james.mailboxmanager.SearchQuery.Criterion;
+import org.apache.james.mailboxmanager.SearchQuery.NumericRange;
 import org.apache.james.mailboxmanager.impl.FetchGroupImpl;
-import org.apache.james.mailboxmanager.impl.GeneralMessageSetImpl;
 import org.apache.james.mailboxmanager.mailbox.ImapMailbox;
+import org.apache.mailet.RFC2822Headers;
 
 /**
  * Handles processeing for the SEARCH imap command.
@@ -44,11 +52,65 @@
  */
 class SearchCommand extends SelectedStateCommand implements UidEnabledCommand
 {
+    public static final String HEADER = "HEADER";
+    public static final String UID = "UID";
+    public static final String NOT = "NOT";
+    public static final String OR = "OR";
+    public static final String SMALLER = "SMALLER";
+    public static final String LARGER = "LARGER";
+    public static final String SINCE = "SINCE";
+    public static final String SENTSINCE = "SENTSINCE";
+    public static final String SENTON = "SENTON";
+    public static final String SENTBEFORE = "SENTBEFORE";
+    public static final String ON = "ON";
+    public static final String BEFORE = "BEFORE";
+    public static final String UNKEYWORD = "UNKEYWORD";
+    public static final String TO = "TO";
+    public static final String TEXT = "TEXT";
+    public static final String SUBJECT = "SUBJECT";
+    public static final String KEYWORD = "KEYWORD";
+    public static final String FROM = "FROM";
+    public static final String CC = "CC";
+    public static final String BODY = "BODY";
+    public static final String BCC = "BCC";
+    public static final String UNSEEN = "UNSEEN";
+    public static final String UNFLAGGED = "UNFLAGGED";
+    public static final String UNDRAFT = "UNDRAFT";
+    public static final String UNDELETED = "UNDELETED";
+    public static final String UNANSWERED = "UNANSWERED";
+    public static final String SEEN = "SEEN";
+    public static final String RECENT = "RECENT";
+    public static final String OLD = "OLD";
+    public static final String NEW = "NEW";
+    public static final String FLAGGED = "FLAGGED";
+    public static final String DRAFT = "DRAFT";
+    public static final String DELETED = "DELETED";
+    public static final String ANSWERED = "ANSWERED";
+    public static final String ALL = "ALL";
+    
+    public final static Set BASE_SEARCH_TERMS = Collections.unmodifiableSet(new HashSet(Arrays.asList(new String[] {
+            ALL, ANSWERED, DELETED, DRAFT, FLAGGED, OLD, RECENT, SEEN,
+            UNANSWERED, UNDELETED, UNDRAFT, UNFLAGGED, UNSEEN
+    })));
+    public final static Set STRING_SEARCH_TERMS = Collections.unmodifiableSet(new HashSet(Arrays.asList(new String[] {
+            BCC, BODY, CC, FROM, SUBJECT, TO
+    })));
+    public final static Set DATE_SEARCH_TERMS = Collections.unmodifiableSet(new HashSet(Arrays.asList(new String[] {
+            BEFORE, ON, SENTBEFORE, SENTON, SENTSINCE , SINCE
+    })));
+    public final static Set SPECIAL_SEARCH_TERMS = new HashSet(Arrays.asList(new String[] {
+            OR, NOT, UID, HEADER
+    }));
+    public final static Set NUMBER_SEARCH_TERMS = Collections.unmodifiableSet(new HashSet(Arrays.asList(new String[] {
+            LARGER, SMALLER
+    })));
+
     public static final String NAME = "SEARCH";
     public static final String ARGS = "<search term>";
 
     private SearchCommandParser parser = new SearchCommandParser();
 
+
     /** @see CommandTemplate#doProcess */
     protected void doProcess( ImapRequestLineReader request,
                               ImapResponse response,
@@ -65,7 +127,7 @@
             throws ProtocolException, MailboxException
     {
         // Parse the search term from the request
-        SearchParameters searchTerm = parser.searchTerm( request );
+        SearchQuery searchTerm = parser.searchTerm( request );
         parser.endLine( request );
 
         final SelectedMailboxSession selected = session.getSelected();
@@ -73,7 +135,7 @@
         final FetchGroup result = FetchGroupImpl.MINIMAL;
         final Iterator it;
         try {
-            it = mailbox.search(GeneralMessageSetImpl.all(),searchTerm, result, session.getMailboxSession());
+            it = mailbox.search(searchTerm,result, session.getMailboxSession());
         } catch (MailboxManagerException e) {
           throw new MailboxException(e);
         }
@@ -120,16 +182,16 @@
         /**
          * Parses the request argument into a valid search term.
          */
-        public SearchParameters searchTerm( ImapRequestLineReader request )
+        public SearchQuery searchTerm( ImapRequestLineReader request )
                 throws ProtocolException
         {
-        	SearchParameters search = new SearchParameters();
+        	SearchQuery search = new SearchQuery();
 
         	char next = request.nextChar();
             while ( next != '\n' && next != '\r') {
                 
-            	SearchParameters.SearchCriteria crit = parseCriteria(request);
-            	search.addCriteria(crit);
+            	SearchQuery.Criterion crit = parseCriteria(request);
+            	search.andCriteria(crit);
                 next = request.nextChar();
                 while ( next == ' ' ) {
                 	request.consume();
@@ -140,29 +202,148 @@
             return search;
         }
 
-		private SearchCriteria parseCriteria(ImapRequestLineReader request) throws ProtocolException {
+		private Criterion parseCriteria(ImapRequestLineReader request) throws ProtocolException {
             String term = atom(request).toUpperCase();
-
-			if (SearchParameters.BASE_SEARCH_TERMS.contains(term)) {
-				return new SearchParameters.NamedSearchCriteria(term);
-			} else if (SearchParameters.STRING_SEARCH_TERMS.contains(term)) {
-				return new SearchParameters.StringSearchCriteria(term, astring(request));
-			} else if (SearchParameters.NUMBER_SEARCH_TERMS.contains(term)) {
-				return new SearchParameters.NumberSearchCriteria(term, number(request));
-			} else if (SearchParameters.DATE_SEARCH_TERMS.contains(term)) {
-				return new SearchParameters.DateSearchCriteria(term, date(request));
+            if (ALL.equals(term)) {
+                return SearchQuery.all();
+            } else if (NEW.equals(term)) {
+                return SearchQuery.and(flag(RECENT), flag(UNSEEN));
+            } else if (KEYWORD.equals(term)) {
+                return keyword(true, request);
+            } else if (UNKEYWORD.equals(term)) {
+                return keyword(false, request);
+            } else if (TEXT.equals(term)) {
+                return SearchQuery.mailContains(astring(request));
+            } else if (BODY.equals(term)) {
+                return SearchQuery.bodyContains(astring(request));
+            } else if (SearchCommand.BASE_SEARCH_TERMS.contains(term)) {
+				return flag(term);
+			} else if (SearchCommand.STRING_SEARCH_TERMS.contains(term)) {
+				return header(term, astring(request));
+			} else if (SearchCommand.NUMBER_SEARCH_TERMS.contains(term)) {
+				return numeric(request, term);
+			} else if (SearchCommand.DATE_SEARCH_TERMS.contains(term)) {
+				return date(request, term);
 			} else if ("HEADER".equals(term)) {
-				return new SearchParameters.HeaderSearchCriteria(astring(request), astring(request));
+				return SearchQuery.headerContains(astring(request), astring(request));
 			} else if ("UID".equals(term)) {
-				return new SearchParameters.UIDSearchCriteria(toNumericRange(parseIdRange(request)));
+				return SearchQuery.uid(toNumericRange(parseIdRange(request)));
 			} else if ("OR".equals(term)) {
-				return new SearchParameters.OrSearchCriteria(parseCriteria(request), parseCriteria(request));
+				return SearchQuery.or(parseCriteria(request), parseCriteria(request));
 			} else if ("NOT".equals(term)) {
-				return new SearchParameters.NotSearchCriteria(parseCriteria(request));
+				return SearchQuery.not(parseCriteria(request));
 			} else {
 				throw new ProtocolException("Term '"+term+"' not supported in the current search implementation!");
 			}
 		}
+        
+        private Criterion header(String term, String value) throws ProtocolException {
+            final String headerName;
+            if ( BCC.equals(term)) {
+                headerName = RFC2822Headers.BCC;
+            } else if (CC.equals(term)) {
+                headerName = RFC2822Headers.CC;
+            } else if (FROM.equals(term)) {
+                headerName = RFC2822Headers.FROM;
+            } else if (SUBJECT.equals(term)) {
+                headerName = RFC2822Headers.SUBJECT;
+            } else if (TO.equals(term)) { 
+                headerName = RFC2822Headers.TO;
+            } else {
+                throw new ProtocolException("Unknown search key");
+            }
+            return SearchQuery.headerContains(headerName, value);
+        }
+
+        private Criterion keyword(boolean isSet, ImapRequestLineReader request) throws ProtocolException {
+            final String keyword = astring(request);
+            return SearchQuery.flagSet(keyword, isSet);
+        }
+
+        private Criterion flag(String term) throws ProtocolException {
+            final Flag flag;
+            final boolean value;
+            if (ANSWERED.equals(term)) {
+                flag = Flag.ANSWERED;
+                value = true;
+            } else if (DELETED.equals(term)) {
+                flag = Flag.DELETED;
+                value = true;                
+            } else if (DRAFT.equals(term)) {
+                flag = Flag.DRAFT;
+                value = true;
+            } else if (FLAGGED.equals(term)) {
+                flag = Flag.FLAGGED;
+                value = true;
+            } else if (OLD.equals(term)) {
+                flag = Flag.RECENT;
+                value = false;
+            } else if (RECENT.equals(term)) {
+                flag = Flag.RECENT;
+                value = true;
+            } else if (SEEN.equals(term)) {
+                flag = Flag.SEEN;
+                value = true;
+            } else if (UNANSWERED.equals(term)) {
+                flag = Flag.ANSWERED;
+                value = false;
+            } else if (UNDELETED.equals(term)) {
+                flag = Flag.DELETED;
+                value = false;
+            } else if (UNDRAFT.equals(term)) {
+                flag = Flag.DRAFT;
+                value = false;
+            } else if (UNFLAGGED.equals(term)) {
+                flag = Flag.FLAGGED;
+                value = false;
+            } else if (UNSEEN.equals(term)) {
+                flag = Flag.SEEN;
+                value = false;
+            } else {
+                throw new ProtocolException("Unknown search key");
+            }
+            final Criterion result = SearchQuery.flagSet(flag, value);
+            return result;
+        }
+
+        private Criterion date(ImapRequestLineReader request, String term) throws ProtocolException {
+            final Date date = date(request);
+            final Calendar calendar = Calendar.getInstance();
+            calendar.setTime(date);
+            final int day =  calendar.get(Calendar.DAY_OF_MONTH);
+            final int month = calendar.get(Calendar.MONTH) + 1;
+            final int year = calendar.get(Calendar.YEAR);
+            final Criterion result;
+            if (BEFORE.equals(term)) {
+                result = SearchQuery.internalDateBefore(day, month, year);
+            } else if (ON.equals(term)) {
+                result = SearchQuery.internalDateOn(day, month, year);
+            } else if (SENTBEFORE.equals(term)) {
+                result = SearchQuery.headerDateBefore(RFC2822Headers.DATE, day, month, year);
+            } else if (SENTON.equals(term)) {
+                result = SearchQuery.headerDateBefore(RFC2822Headers.DATE, day, month, year);
+            } else if (SENTSINCE.equals(term)) {
+                result = SearchQuery.headerDateBefore(RFC2822Headers.DATE, day, month, year);
+            } else if (SINCE.equals(term)) {
+                result = SearchQuery.internalDateAfter(day, month, year);
+            } else {
+                throw new ProtocolException("Unknown search key");
+            }
+            return result;
+        }
+
+        private Criterion numeric(ImapRequestLineReader request, String term) throws ProtocolException {
+            final long value = number(request);
+            final Criterion result;
+            if (LARGER.equals(term)) {
+                result = SearchQuery.sizeGreaterThan(value);
+            } else if (SMALLER.equals(term)) {
+                result = SearchQuery.sizeLessThan(value);
+            } else {
+                throw new ProtocolException("Unknown search key");
+            }
+            return result;
+        }
 
         private NumericRange[] toNumericRange(final IdRange[] ranges) {
             final NumericRange[] result;

Modified: james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMailbox.java
URL: http://svn.apache.org/viewvc/james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMailbox.java?rev=632829&r1=632828&r2=632829&view=diff
==============================================================================
--- james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMailbox.java (original)
+++ james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMailbox.java Sun Mar  2 12:21:26 2008
@@ -41,8 +41,7 @@
 import org.apache.james.mailboxmanager.MailboxManagerException;
 import org.apache.james.mailboxmanager.MailboxSession;
 import org.apache.james.mailboxmanager.MessageResult;
-import org.apache.james.mailboxmanager.SearchParameters;
-import org.apache.james.mailboxmanager.UnsupportedCriteriaException;
+import org.apache.james.mailboxmanager.SearchQuery;
 import org.apache.james.mailboxmanager.MessageResult.FetchGroup;
 import org.apache.james.mailboxmanager.impl.FetchGroupImpl;
 import org.apache.james.mailboxmanager.impl.GeneralMessageSetImpl;
@@ -60,7 +59,6 @@
 import org.apache.james.mailboxmanager.tracking.UidRange;
 import org.apache.james.mailboxmanager.util.UidToKeyConverter;
 import org.apache.james.mailboxmanager.util.UidToKeyConverterImpl;
-import org.apache.mailet.RFC2822Headers;
 import org.apache.torque.NoRowsException;
 import org.apache.torque.TooManyRowsException;
 import org.apache.torque.TorqueException;
@@ -607,109 +605,14 @@
         this.mailboxRow = mailboxRow;
     }
 
-    public Iterator search(GeneralMessageSet set, SearchParameters parameters,
-            FetchGroup fetchGroup, MailboxSession mailboxSession) throws MailboxManagerException {
+    public Iterator search(SearchQuery parameters, FetchGroup fetchGroup,
+            MailboxSession mailboxSession) throws MailboxManagerException {
         try {
             lock.readLock().acquire();
             try {
                 checkAccess();
-                set=toUidSet(set);
-                if (!set.isValid() || set.getType()==GeneralMessageSet.TYPE_NOTHING) {
-                    return IteratorUtils.EMPTY_ITERATOR;
-                }
                 
                 TorqueCriteriaBuilder builder = new TorqueCriteriaBuilder();
-                
-                final List searchCriteria = parameters.getCriterias();
-                for (Iterator it=searchCriteria.iterator();it.hasNext();) {
-                    SearchParameters.SearchCriteria criterion = (SearchParameters.SearchCriteria) it.next();
-                    final String name = criterion.getName();
-                    if (SearchParameters.ALL.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.ANSWERED.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.ANSWERED, true);
-                    } else if (SearchParameters.BCC.equals(name)) {
-                        SearchParameters.StringSearchCriteria stringSearchCriteria = (SearchParameters.StringSearchCriteria) criterion;
-                        final String value = stringSearchCriteria.getValue();
-                        builder.andHeaderContains(RFC2822Headers.BCC, value);
-                    } else if (SearchParameters.BEFORE.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.BODY.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.CC.equals(name)) {
-                        SearchParameters.StringSearchCriteria stringSearchCriteria = (SearchParameters.StringSearchCriteria) criterion;
-                        final String value = stringSearchCriteria.getValue();
-                        builder.andHeaderContains(RFC2822Headers.CC, value);
-                    } else if (SearchParameters.DELETED.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.DELETED, true);
-                    } else if (SearchParameters.DRAFT.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.DRAFT, true);
-                    } else if (SearchParameters.FLAGGED.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.FLAGGED, true);
-                    } else if (SearchParameters.FROM.equals(name)) {
-                        SearchParameters.StringSearchCriteria stringSearchCriteria = (SearchParameters.StringSearchCriteria) criterion;
-                        final String value = stringSearchCriteria.getValue();
-                        builder.andHeaderContains(RFC2822Headers.FROM, value);
-                    } else if (SearchParameters.HEADER.equals(name)) {
-                        SearchParameters.HeaderSearchCriteria headerSearchCriteria = (SearchParameters.HeaderSearchCriteria) criterion;
-                        final String value = headerSearchCriteria.getValue();
-                        final String fieldName = headerSearchCriteria.getFieldName();
-                        builder.andHeaderContains(fieldName, value);
-                    } else if (SearchParameters.KEYWORD.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.LARGER.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.NEW.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.RECENT, true);
-                        builder.andFlag(javax.mail.Flags.Flag.RECENT, false);
-                    } else if (SearchParameters.NOT.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.OLD.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.ON.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.OR.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.RECENT.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.RECENT, true);
-                    } else if (SearchParameters.SEEN.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.SEEN, true);
-                    } else if (SearchParameters.SENTBEFORE.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.SENTON.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.SENTSINCE.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.SINCE.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.SMALLER.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.SUBJECT.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.TEXT.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.TO.equals(name)) {
-                        SearchParameters.StringSearchCriteria stringSearchCriteria = (SearchParameters.StringSearchCriteria) criterion;
-                        final String value = stringSearchCriteria.getValue();
-                        builder.andHeaderContains(RFC2822Headers.TO, value);
-                    } else if (SearchParameters.UID.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.UNANSWERED.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.ANSWERED, false);
-                    } else if (SearchParameters.UNDELETED.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.DELETED, false);
-                    } else if (SearchParameters.UNDRAFT.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.DRAFT, false);
-                    } else if (SearchParameters.UNFLAGGED.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.FLAGGED, false);
-                    } else if (SearchParameters.UNKEYWORD.equals(name)) {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    } else if (SearchParameters.UNSEEN.equals(name)) {
-                        builder.andFlag(javax.mail.Flags.Flag.SEEN, false);
-                    } else {
-                        throw new UnsupportedCriteriaException("Search criterion '" + name + "' is not supported");
-                    }
-                }
                 
                 final Iterator results = getMessages(fetchGroup, new UidRange(1, -1), builder.getCriteria());
                 return results;



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org