All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.james.mailbox.model.SearchQuery Maven / Gradle / Ivy

There is a newer version: 3.8.1
Show newest version
/****************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one   *
 * or more contributor license agreements.  See the NOTICE file *
 * distributed with this work for additional information        *
 * regarding copyright ownership.  The ASF licenses this file   *
 * to you under the Apache License, Version 2.0 (the            *
 * "License"); you may not use this file except in compliance   *
 * with the License.  You may obtain a copy of the License at   *
 *                                                              *
 *   http://www.apache.org/licenses/LICENSE-2.0                 *
 *                                                              *
 * Unless required by applicable law or agreed to in writing,   *
 * software distributed under the License is distributed on an  *
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
 * KIND, either express or implied.  See the License for the    *
 * specific language governing permissions and limitations      *
 * under the License.                                           *
 ****************************************************************/
package org.apache.james.mailbox.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.mail.Flags;
import javax.mail.Flags.Flag;

import org.apache.james.mailbox.MessageUid;

import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;

/**
 * 

* Models a query used to search for messages. A query is the logical * AND of the contained criteria. *

*

* Each Criterion is composed of an Operator * (combining value and operation) together with field information (optional * since the criteria type may imply a particular field). Factory methods are * provided for criteria. *

*/ public class SearchQuery implements Serializable { private static final long serialVersionUID = 1L; private static final String DATE_HEADER_NAME = "Date"; /** * The Resolution which should get used for {@link Date} searches */ public enum DateResolution { Second, Minute, Hour, Day, Month, Year } public enum AddressType { From, To, Cc, Bcc } /** * Allow to sort a {@link SearchQuery} response in different ways. */ public static class Sort implements Serializable { private static final long serialVersionUID = 1L; public enum Order { REVERSE, NATURAL } /** * Specify on what to sort */ public enum SortClause { /** * Internal date and time of the message (internaldate) */ Arrival, /** * addr-mailbox of the first "cc" address. * * This MUST BE converted to uppercase before doing the sort */ MailboxCc, /** * addr-mailbox of the first "from" address. * * This MUST BE converted to uppercase before doing the sort */ MailboxFrom, /** * addr-mailbox of the first "To" address * * This MUST BE converted to uppercase before doing the sort */ MailboxTo, /** * Base subject text. * * This MUST BE converted to uppercase before doing the sort */ BaseSubject, /** * Size of the message in octets. */ Size, /** *

* As used in this document, the term "sent date" refers to the date * and time from the Date: header, adjusted by time zone to * normalize to UTC. For example, "31 Dec 2000 16:01:33 -0800" is * equivalent to the UTC date and time of * "1 Jan 2001 00:01:33 +0000". If the time zone is invalid, the * date and time SHOULD be treated as UTC. If the time is also * invalid, the time SHOULD be treated as 00:00:00. If there is no * valid date or time, the date and time SHOULD be treated as * 00:00:00 on the earliest possible date. * * If the sent date cannot be determined (a Date: header is missing * or cannot be parsed), the INTERNALDATE for that message is used * as the sent date. *

*/ SentDate, /** * addr-name of the first "From" address * * This MUST BE converted to uppercase before doing the sort */ DisplayFrom, /** * addr-name of the first "To" address * * This MUST BE converted to uppercase before doing the sort */ DisplayTo, /** * Uid of the message. This is the DEFAULT if no other is specified */ Uid, /** * Unique Id of the message. */ Id } private final Order order; private final SortClause sortClause; public Sort(SortClause sortClause, Order order) { this.order = order; this.sortClause = sortClause; } /** * Create a new {@link Sort} which is NOT {@link #order} * * @param sortClause */ public Sort(SortClause sortClause) { this(sortClause, Order.NATURAL); } /** * Return true if the sort should be in reverse order * * @return reverse */ public boolean isReverse() { return order == Order.REVERSE; } /** * Return the {@link SortClause} * * @return clause */ public SortClause getSortClause() { return sortClause; } @Override public boolean equals(Object o) { if (o instanceof Sort) { Sort that = (Sort) o; return Objects.equal(this.sortClause, that.sortClause) && Objects.equal(this.order, that.order); } return false; } @Override public int hashCode() { return Objects.hashCode(sortClause, order); } } /** * 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 Criterion, not null */ public static Criterion sizeLessThan(long value) { return new SizeCriterion(new NumericOperator(value, NumericComparator.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 Criterion, not null */ public static Criterion sizeGreaterThan(long value) { return new SizeCriterion(new NumericOperator(value, NumericComparator.GREATER_THAN)); } /** * Creates a filter for message size equal to the given value * * @param value * messages with size equal to this value will be selected by the * returned criterion * @return Criterion, not null */ public static Criterion sizeEquals(long value) { return new SizeCriterion(new NumericOperator(value, NumericComparator.EQUALS)); } /** * Creates a filter for message mod-sequence less than the given value * * @param value * messages with mod-sequence less than this value will be * selected by the returned criterion * @return Criterion, not null */ public static Criterion modSeqLessThan(long value) { return new ModSeqCriterion(new NumericOperator(value, NumericComparator.LESS_THAN)); } /** * Creates a filter for message mod-sequence greater than the given value * * @param value * messages with mod-sequence greater than this value will be * selected by the returned criterion * @return Criterion, not null */ public static Criterion modSeqGreaterThan(long value) { return new ModSeqCriterion(new NumericOperator(value, NumericComparator.GREATER_THAN)); } /** * Creates a filter for message mod-sequence equal to the given value * * @param value * messages with mod-sequence equal to this value will be * selected by the returned criterion * @return Criterion, not null */ public static Criterion modSeqEquals(long value) { return new ModSeqCriterion(new NumericOperator(value, NumericComparator.EQUALS)); } /** * Creates a filter matching messages with internal date after the given * date. * * @param date * given date * @param dateResolution * the date resolution, either {@link DateResolution#Year}, * {@link DateResolution#Month}, {@link DateResolution#Day}, * {@link DateResolution#Hour}, {@link DateResolution#Minute} or * {@link DateResolution#Second} * @return Criterion, not null */ public static Criterion internalDateAfter(Date date, DateResolution dateResolution) { return new InternalDateCriterion(new DateOperator(DateComparator.AFTER, date, dateResolution)); } /** * Creates a filter matching messages with internal date on the given date. * * @param date * given date * @param dateResolution * the date resolution, either {@link DateResolution#Year}, * {@link DateResolution#Month}, {@link DateResolution#Day}, * {@link DateResolution#Hour}, {@link DateResolution#Minute} or * {@link DateResolution#Second} * @return Criterion, not null */ public static Criterion internalDateOn(Date date, DateResolution dateResolution) { return new InternalDateCriterion(new DateOperator(DateComparator.ON, date, dateResolution)); } /** * Creates a filter matching messages with internal date before the given * date. * * @param date * given date * @param dateResolution * the date resolution, either {@link DateResolution#Year}, * {@link DateResolution#Month}, {@link DateResolution#Day}, * {@link DateResolution#Hour}, {@link DateResolution#Minute} or * {@link DateResolution#Second} * @return Criterion, not null */ public static Criterion internalDateBefore(Date date, DateResolution dateResolution) { return new InternalDateCriterion(new DateOperator(DateComparator.BEFORE, date, dateResolution)); } /** * Creates a filter matching messages with sent date after the given * date. * * @param date * given date * @param dateResolution * the date resolution, either {@link DateResolution#Year}, * {@link DateResolution#Month}, {@link DateResolution#Day}, * {@link DateResolution#Hour}, {@link DateResolution#Minute} or * {@link DateResolution#Second} * @return Criterion, not null */ public static Criterion sentDateAfter(Date date, DateResolution dateResolution) { return headerDateAfter(DATE_HEADER_NAME, date, dateResolution); } /** * Creates a filter matching messages with sent date on the given date. * * @param date * given date * @param dateResolution * the date resolution, either {@link DateResolution#Year}, * {@link DateResolution#Month}, {@link DateResolution#Day}, * {@link DateResolution#Hour}, {@link DateResolution#Minute} or * {@link DateResolution#Second} * @return Criterion, not null */ public static Criterion sentDateOn(Date date, DateResolution dateResolution) { return headerDateOn(DATE_HEADER_NAME, date, dateResolution); } /** * Creates a filter matching messages with sent date before the given * date. * * @param date * given date * @param dateResolution * the date resolution, either {@link DateResolution#Year}, * {@link DateResolution#Month}, {@link DateResolution#Day}, * {@link DateResolution#Hour}, {@link DateResolution#Minute} or * {@link DateResolution#Second} * @return Criterion, not null */ public static Criterion sentDateBefore(Date date, DateResolution dateResolution) { return headerDateBefore(DATE_HEADER_NAME, date, dateResolution); } /** * 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 date * given date * @param dateResolution * the date resolution, either {@link DateResolution#Year}, * {@link DateResolution#Month}, {@link DateResolution#Day}, * {@link DateResolution#Hour}, {@link DateResolution#Minute} or * {@link DateResolution#Second} * @return Criterion, not null */ public static Criterion headerDateAfter(String headerName, Date date, DateResolution dateResolution) { return new HeaderCriterion(headerName, new DateOperator(DateComparator.AFTER, date, dateResolution)); } /** * 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 date * given date * @param dateResolution * the date resolution, either {@link DateResolution#Year}, * {@link DateResolution#Month}, {@link DateResolution#Day}, * {@link DateResolution#Hour}, {@link DateResolution#Minute} or * {@link DateResolution#Second} * @return Criterion, not null */ public static Criterion headerDateOn(String headerName, Date date, DateResolution dateResolution) { return new HeaderCriterion(headerName, new DateOperator(DateComparator.ON, date, dateResolution)); } /** * 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 date * given date * @param dateResolution * the date resolution, either {@link DateResolution#Year}, * {@link DateResolution#Month}, {@link DateResolution#Day}, * {@link DateResolution#Hour}, {@link DateResolution#Minute} or * {@link DateResolution#Second} * @return Criterion, not null */ public static Criterion headerDateBefore(String headerName, Date date, DateResolution dateResolution) { return new HeaderCriterion(headerName, new DateOperator(DateComparator.BEFORE, date, dateResolution)); } /** * Creates a filter matching messages whose Address header contains the * given address. The address header of the message MUST get canonicalized * before try to match it. * * @param type * @param address * @return Criterion */ public static Criterion address(AddressType type, String address) { return new HeaderCriterion(type.name(), new AddressOperator(address)); } /** * Creates a filter matching messages whose header value contains the given * value. * * All to-compared Strings MUST BE converted to uppercase before doing so * (this also include the search 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 Criterion, not null */ public static 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. * * All to-compared Strings MUST BE converted to uppercase before doing so * (this also include the search value) * * @param headerName * name of the header whose value will be compared, not null * @return Criterion, not null */ public static 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. * * All to-compared Strings MUST BE converted to uppercase before doing so * (this also include the search value) * * @param value * search value * @return Criterion, not null */ public static Criterion mailContains(String value) { return new TextCriterion(value, Scope.FULL); } /** * Creates a filter matching messages which contains the given text either * within the headers (From, To, Cc, Bcc & Subject) and text / html bodies. * Implementations may choose to ignore mime parts which cannot be decoded to text. * * All to-compared Strings MUST BE converted to uppercase before doing so * (this also include the search value) * * @param value * search value * @return Criterion, not null */ public static Criterion textContains(String value) { return new TextCriterion(value, Scope.TEXT); } /** * 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. * * All to-compared Strings MUST BE converted to uppercase before doing so * (this also include the search value) * * @param value * search value * @return Criterion, not null */ public static Criterion bodyContains(String value) { return new TextCriterion(value, Scope.BODY); } /** * Creates a filter matching messages which has an attachment containing the given text. * * @param value * search value * @return Criterion, not null */ public static Criterion attachmentContains(String value) { return new TextCriterion(value, Scope.ATTACHMENTS); } /** * Creates a filter matching messages within any of the given ranges. * * @param range * NumericRange's, not null * @return Criterion, not null */ public static Criterion uid(UidRange[] range) { return new UidCriterion(range); } /** * Creates a filter composing the two different criteria. * * @param one * Criterion, not null * @param two * Criterion, not null * @return Criterion, not null */ public static Criterion or(Criterion one, Criterion two) { final List criteria = new ArrayList<>(); criteria.add(one); criteria.add(two); return new ConjunctionCriterion(Conjunction.OR, criteria); } /** * Creates a filter composing the listed criteria. * * @param criteria * List of {@link Criterion} * @return Criterion, not null */ public static Criterion or(List criteria) { return new ConjunctionCriterion(Conjunction.OR, criteria); } /** * Creates a filter composing the two different criteria. * * @param one * Criterion, not null * @param two * Criterion, not null * @return Criterion, not null */ public static Criterion and(Criterion one, Criterion two) { final List criteria = new ArrayList<>(); criteria.add(one); criteria.add(two); return new ConjunctionCriterion(Conjunction.AND, criteria); } /** * Creates a filter composing the listed criteria. * * @param criteria * List of {@link Criterion} * @return Criterion, not null */ public static Criterion and(List criteria) { return new ConjunctionCriterion(Conjunction.AND, criteria); } /** * Creates a filter inverting the given criteria. * * @param criterion * Criterion, not null * @return Criterion, not null */ public static Criterion not(Criterion criterion) { final List criteria = new ArrayList<>(); criteria.add(criterion); return new ConjunctionCriterion(Conjunction.NOR, criteria); } /** * Creates a filter composing the listed criteria. * * @param criteria * List of {@link Criterion} * @return Criterion, not null */ public static Criterion not(List criteria) { return new ConjunctionCriterion(Conjunction.NOR, criteria); } /** * Creates a filter on the given flag. * * @param flag * Flag, not null * @param isSet * true if the messages with the flag set should be matched, * false otherwise * @return Criterion, not null */ public static Criterion flagSet(Flag flag, boolean isSet) { final Criterion result; if (isSet) { result = flagIsSet(flag); } else { result = flagIsUnSet(flag); } return result; } public static Criterion hasAttachment(boolean value) { if (value) { return new AttachmentCriterion(BooleanOperator.set()); } else { return new AttachmentCriterion(BooleanOperator.unset()); } } public static Criterion attachmentFileName(String fileName) { return new TextCriterion(fileName, Scope.ATTACHMENT_FILE_NAME); } public static Criterion hasAttachment() { return hasAttachment(true); } public static Criterion hasNoAttachment() { return hasAttachment(false); } /** * Creates a filter on the given flag selecting messages where the given * flag is selected. * * @param flag * Flag, not null * @return Criterion, not null */ public static Criterion flagIsSet(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 * Flag, not null * @return Criterion, not null */ public static Criterion flagIsUnSet(Flag flag) { return new FlagCriterion(flag, BooleanOperator.unset()); } public static Criterion flag(Flag flag, boolean isSet) { return new FlagCriterion(flag, new BooleanOperator(isSet)); } /** * Creates a filter on the given flag. * * @param flag * Flag, not null * @param isSet * true if the messages with the flag set should be matched, * false otherwise * @return Criterion, not null */ public static Criterion flagSet(String flag, 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 * Flag, not null * @return Criterion, not null */ public static Criterion flagIsSet(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 * Flag, not null * @return Criterion, not null */ public static Criterion flagIsUnSet(String flag) { return new CustomFlagCriterion(flag, BooleanOperator.unset()); } /** * Creates a filter matching all messages. * * @return Criterion, not null */ public static Criterion all() { return AllCriterion.all(); } public static Criterion mimeMessageID(String messageId) { return new MimeMessageIDCriterion(messageId); } private final Set recentMessageUids = new HashSet<>(); private final List criterias; private List sorts = Collections.singletonList(new Sort(Sort.SortClause.Uid, Sort.Order.NATURAL)); public SearchQuery(Criterion... criterias) { this(new ArrayList<>(Arrays.asList(criterias))); } public SearchQuery() { this(new ArrayList<>()); } private SearchQuery(List criterias) { this.criterias = criterias; } public void andCriteria(Criterion crit) { criterias.add(crit); } public List getCriterias() { return criterias; } /** * Set the {@link Sort}'s to use * * @param sorts */ public void setSorts(List sorts) { if (sorts == null || sorts.isEmpty()) { throw new IllegalArgumentException("There must be at least one Sort"); } this.sorts = sorts; } /** * Return the {@link Sort}'s which should get used for sorting the result. * They get "executed" in a chain, if the first does not give an result the * second will get executed etc. * * If not set via {@link #setSorts(List)} it will sort via * {@link Sort.SortClause#Uid} * * @return sorts */ public List getSorts() { return sorts; } /** * Gets the UIDS of messages which are recent for this client session. The * list of recent mail is maintained in the protocol layer since the * mechanics are protocol specific. * * @return mutable Set of MessageUid UIDS */ public Set getRecentMessageUids() { return recentMessageUids; } /** * Adds all the uids to the collection of recents. * * @param uids * not null */ public void addRecentMessageUids(Collection uids) { recentMessageUids.addAll(uids); } @Override public String toString() { return "Search:" + criterias.toString(); } @Override public final int hashCode() { return Objects.hashCode(criterias); } @Override public final boolean equals(Object obj) { if (obj instanceof SearchQuery) { SearchQuery that = (SearchQuery) obj; return Objects.equal(this.criterias, that.criterias); } return false; } /** * 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 class NumericRange implements Serializable { private static final long serialVersionUID = 1L; private final long lowValue; private final long highValue; public NumericRange(long value) { super(); this.lowValue = value; this.highValue = value; } public NumericRange(long lowValue, long highValue) { super(); this.lowValue = lowValue; this.highValue = highValue; } public long getHighValue() { return highValue; } public long getLowValue() { return lowValue; } /** * Is the given value in this range? * * @param value * value to be tested * @return true if the value is in range, false otherwise */ public boolean isIn(long value) { if (lowValue == Long.MAX_VALUE) { return highValue >= value; } return lowValue <= value && highValue >= value; } @Override public int hashCode() { return Objects.hashCode(lowValue, highValue); } @Override public boolean equals(Object obj) { if (obj instanceof NumericRange) { NumericRange that = (NumericRange) obj; return Objects.equal(this.lowValue, that.lowValue) && Objects.equal(this.highValue, that.highValue); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("lowValue", lowValue) .add("highValue", highValue) .toString(); } } /** * 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 class UidRange implements Serializable { private final MessageUid lowValue; private final MessageUid highValue; public UidRange(MessageUid value) { super(); this.lowValue = value; this.highValue = value; } public UidRange(MessageUid lowValue, MessageUid highValue) { super(); this.lowValue = lowValue; this.highValue = highValue; } public MessageUid getHighValue() { return highValue; } public MessageUid getLowValue() { return lowValue; } /** * Is the given value in this range? * * @param value * value to be tested * @return true if the value is in range, false otherwise */ public boolean isIn(MessageUid value) { return lowValue.compareTo(value) <= 0 && highValue.compareTo(value) >= 0; } @Override public int hashCode() { return Objects.hashCode(lowValue, highValue); } @Override public boolean equals(Object obj) { if (obj instanceof UidRange) { UidRange that = (UidRange) obj; return Objects.equal(this.lowValue, that.lowValue) && Objects.equal(this.highValue, that.highValue); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("lowValue", lowValue) .add("highValue", highValue) .toString(); } } /** * Marker superclass for criteria. */ public abstract static class Criterion implements Serializable { private static final long serialVersionUID = 1L; } public enum Conjunction { AND, OR, NOR } /** * Conjunction applying to the contained criteria. {@link #getType} * indicates how the conjoined criteria should be related. */ public static class ConjunctionCriterion extends Criterion { private static final long serialVersionUID = 1L; private final Conjunction type; private final List criteria; public ConjunctionCriterion(Conjunction type, List criteria) { super(); this.type = type; this.criteria = criteria; } /** * Gets the criteria related through this conjunction. * * @return List of {@link Criterion} */ public List getCriteria() { return criteria; } /** * Gets the type of conjunction. * * @return not null */ public Conjunction getType() { return type; } @Override public int hashCode() { return Objects.hashCode(criteria); } @Override public boolean equals(Object obj) { if (obj instanceof ConjunctionCriterion) { ConjunctionCriterion that = (ConjunctionCriterion) obj; return Objects.equal(this.criteria, that.criteria); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("criteria", criteria) .add("type", type) .toString(); } } /** * Any message. */ public static class AllCriterion extends Criterion { private static final long serialVersionUID = 1L; private static final AllCriterion ALL = new AllCriterion(); private static Criterion all() { return ALL; } @Override public boolean equals(Object obj) { return obj instanceof AllCriterion; } @Override public int hashCode() { return 1729; } @Override public String toString() { return "AllCriterion"; } } public enum Scope { /** Only message body content */ BODY, /** Headers: From, To, Cc, Bcc & Subjects * plus text/plain & text/html part */ TEXT, /** Full message content including headers and attachments */ FULL, /** Attachment content */ ATTACHMENTS, /** Attachment file name, specified on Content-Disposition * header of mime body parts */ ATTACHMENT_FILE_NAME } /** * Message text. */ public static class TextCriterion extends Criterion { private static final long serialVersionUID = 1L; private final Scope type; private final ContainsOperator operator; private TextCriterion(String value, Scope type) { super(); this.operator = new ContainsOperator(value); this.type = type; } /** * Gets the type of text to be searched. * * @return not null */ public Scope getType() { return type; } /** * Gets the search operation and value to be evaluated. * * @return the Operator, not null */ public ContainsOperator getOperator() { return operator; } @Override public int hashCode() { return Objects.hashCode(operator); } @Override public boolean equals(Object obj) { if (obj instanceof TextCriterion) { TextCriterion that = (TextCriterion) obj; return Objects.equal(this.operator, that.operator); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("operator", operator) .toString(); } } public static class MimeMessageIDCriterion extends Criterion { private final String messageID; public MimeMessageIDCriterion(String messageID) { this.messageID = messageID; } public String getMessageID() { return messageID; } public HeaderCriterion asHeaderCriterion() { return new HeaderCriterion("Message-ID", new ContainsOperator(messageID)); } @Override public final boolean equals(Object o) { if (o instanceof MimeMessageIDCriterion) { MimeMessageIDCriterion that = (MimeMessageIDCriterion) o; return java.util.Objects.equals(this.messageID, that.messageID); } return false; } @Override public final int hashCode() { return java.util.Objects.hash(messageID); } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("messageID", messageID) .toString(); } } /** * Header value content search. */ public static class HeaderCriterion extends Criterion { private static final long serialVersionUID = 1L; private final HeaderOperator operator; private final String headerName; private HeaderCriterion(String headerName, 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 String getHeaderName() { return headerName; } /** * Gets the search operation and value to be evaluated. * * @return the Operator, not null */ public HeaderOperator getOperator() { return operator; } @Override public int hashCode() { return Objects.hashCode(headerName, operator); } @Override public boolean equals(Object obj) { if (obj instanceof HeaderCriterion) { HeaderCriterion that = (HeaderCriterion) obj; return Objects.equal(this.operator, that.operator) && Objects.equal(this.headerName, that.headerName); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("operator", operator) .add("headerName", headerName) .toString(); } } /** * Filters on the internal date. */ public static class InternalDateCriterion extends Criterion { private static final long serialVersionUID = 1L; private final DateOperator operator; public InternalDateCriterion(DateOperator operator) { super(); this.operator = operator; } /** * Gets the search operation and value to be evaluated. * * @return the Operator, not null */ public DateOperator getOperator() { return operator; } @Override public int hashCode() { return Objects.hashCode(operator); } @Override public boolean equals(Object obj) { if (obj instanceof InternalDateCriterion) { InternalDateCriterion that = (InternalDateCriterion) obj; return Objects.equal(this.operator, that.operator); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("operator", operator) .toString(); } } /** * Filters on the mod-sequence of the messages. */ public static class ModSeqCriterion extends Criterion { private static final long serialVersionUID = 1L; private final NumericOperator operator; private ModSeqCriterion(NumericOperator operator) { super(); this.operator = operator; } /** * Gets the search operation and value to be evaluated. * * @return the NumericOperator, not null */ public NumericOperator getOperator() { return operator; } @Override public int hashCode() { return Objects.hashCode(operator); } @Override public boolean equals(Object obj) { if (obj instanceof ModSeqCriterion) { ModSeqCriterion that = (ModSeqCriterion) obj; return Objects.equal(this.operator, that.operator); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("operator", operator) .toString(); } } public static class SizeCriterion extends Criterion { private static final long serialVersionUID = 1L; private final NumericOperator operator; private SizeCriterion(NumericOperator operator) { super(); this.operator = operator; } /** * Gets the search operation and value to be evaluated. * * @return the NumericOperator, not null */ public NumericOperator getOperator() { return operator; } @Override public int hashCode() { return Objects.hashCode(operator); } @Override public boolean equals(Object obj) { if (obj instanceof SizeCriterion) { SizeCriterion that = (SizeCriterion) obj; return Objects.equal(this.operator, that.operator); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("operator", operator) .toString(); } } /** * Filters on a custom flag valuation. */ public static class CustomFlagCriterion extends Criterion { private static final long serialVersionUID = 1L; private final String flag; private final BooleanOperator operator; private CustomFlagCriterion(String flag, BooleanOperator operator) { super(); this.flag = flag; this.operator = operator; } /** * Gets the custom flag to be search. * * @return the flag name, not null */ public String getFlag() { return flag; } /** * Gets the value to be tested. * * @return the BooleanOperator, not null */ public BooleanOperator getOperator() { return operator; } @Override public int hashCode() { return Objects.hashCode(flag, operator); } @Override public boolean equals(Object obj) { if (obj instanceof CustomFlagCriterion) { CustomFlagCriterion that = (CustomFlagCriterion) obj; return Objects.equal(this.operator, that.operator) && Objects.equal(this.flag, that.flag); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("operator", operator) .add("flag", flag) .toString(); } } /*** * Filter on attachment presence */ public static class AttachmentCriterion extends Criterion { private final BooleanOperator operator; private AttachmentCriterion(BooleanOperator operator) { this.operator = operator; } /** * Gets the test to be preformed. * * @return the BooleanOperator, not null */ public BooleanOperator getOperator() { return operator; } @Override public int hashCode() { return Objects.hashCode(operator); } @Override public boolean equals(Object obj) { if (obj instanceof AttachmentCriterion) { AttachmentCriterion that = (AttachmentCriterion) obj; return Objects.equal(this.operator, that.operator); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("operator", operator) .toString(); } } /** * Filters on a standard flag. */ public static class FlagCriterion extends Criterion { private static final long serialVersionUID = 1L; // Flags not Flag because Flags are serializable and Flag is not private final Flags flag; private final BooleanOperator operator; private FlagCriterion(Flag flag, BooleanOperator operator) { super(); this.flag = new Flags(flag); this.operator = operator; } /** * Gets the flag filtered on. * * @return the flag, not null */ public Flag getFlag() { // safe because the Flags(Flag) does system flags, // and James code also constructs FlagCriterion only with system flags return flag.getSystemFlags()[0]; } /** * Gets the test to be preformed. * * @return the BooleanOperator, not null */ public BooleanOperator getOperator() { return operator; } @Override public int hashCode() { return Objects.hashCode(flag, operator); } @Override public boolean equals(Object obj) { if (obj instanceof FlagCriterion) { FlagCriterion that = (FlagCriterion) obj; return Objects.equal(this.operator, that.operator) && Objects.equal(this.flag, that.flag); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("operator", operator) .add("flag", flag) .toString(); } } /** * Filters on message identity. */ public static class UidCriterion extends Criterion { private static final long serialVersionUID = 1L; private final UidInOperator operator; public UidCriterion(UidRange[] ranges) { super(); this.operator = new UidInOperator(ranges); } /** * Gets the filtering operation. */ public UidInOperator getOperator() { return operator; } @Override public int hashCode() { return Objects.hashCode(operator); } @Override public boolean equals(Object obj) { if (obj instanceof UidCriterion) { UidCriterion that = (UidCriterion) obj; return Objects.equal(this.operator, that.operator); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("operator", operator) .toString(); } } /** * Search operator. */ public interface Operator extends Serializable { } /** * Marks operator as suitable for header value searching. */ public interface HeaderOperator extends Operator { } public static class AddressOperator implements HeaderOperator { private static final long serialVersionUID = 1L; private final String address; public AddressOperator(String address) { super(); this.address = address; } /** * Gets the value to be searched for. * * @return the value */ public String getAddress() { return address; } @Override public int hashCode() { return Objects.hashCode(address); } @Override public boolean equals(Object obj) { if (obj instanceof AddressOperator) { AddressOperator that = (AddressOperator) obj; return Objects.equal(this.address, that.address); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("address", address) .toString(); } } /** * Contained value search. */ public static class ContainsOperator implements HeaderOperator { private static final long serialVersionUID = 1L; private final String value; public ContainsOperator(String value) { super(); this.value = value; } /** * Gets the value to be searched for. * * @return the value */ public String getValue() { return value; } @Override public int hashCode() { return Objects.hashCode(value); } @Override public boolean equals(Object obj) { if (obj instanceof ContainsOperator) { ContainsOperator that = (ContainsOperator) obj; return Objects.equal(this.value, that.value); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("value", value) .toString(); } } /** * Existance search. */ public static class ExistsOperator implements HeaderOperator { private static final long serialVersionUID = 1L; private static final ExistsOperator EXISTS = new ExistsOperator(); public static ExistsOperator exists() { return EXISTS; } @Override public boolean equals(Object obj) { return obj instanceof ExistsOperator; } @Override public int hashCode() { return 42; } @Override public String toString() { return "ExistsCriterion"; } } /** * Boolean value search. */ public static class BooleanOperator implements Operator { private static final long serialVersionUID = 1L; private static final BooleanOperator SET = new BooleanOperator(true); private static final BooleanOperator UNSET = new BooleanOperator(false); public static BooleanOperator set() { return SET; } public static BooleanOperator unset() { return UNSET; } private final boolean set; private BooleanOperator(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 boolean isSet() { return set; } @Override public int hashCode() { return Objects.hashCode(set); } @Override public boolean equals(Object obj) { if (obj instanceof BooleanOperator) { BooleanOperator that = (BooleanOperator) obj; return Objects.equal(this.set, that.set); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("set", set) .toString(); } } public enum NumericComparator { EQUALS, LESS_THAN, GREATER_THAN } /** * Searches numeric values. */ public static class NumericOperator implements Operator { private static final long serialVersionUID = 1L; private final long value; private final NumericComparator type; private NumericOperator(long value, NumericComparator type) { super(); this.value = value; this.type = type; } /** * Gets the operation type * * @return not null */ public NumericComparator getType() { return type; } /** * Gets the value to be compared. * * @return the value */ public long getValue() { return value; } @Override public int hashCode() { return Objects.hashCode(value, type); } @Override public boolean equals(Object obj) { if (obj instanceof NumericOperator) { NumericOperator that = (NumericOperator) obj; return Objects.equal(this.value, that.value) && Objects.equal(this.type, that.type); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("value", value) .add("type", type) .toString(); } } public enum DateComparator { BEFORE, AFTER, ON } /** * Operates on a date. */ public static class DateOperator implements HeaderOperator { private static final long serialVersionUID = 1L; public static final int BEFORE = 1; public static final int AFTER = 2; public static final int ON = 3; private final DateComparator type; private final Date date; private final DateResolution dateResolution; public DateOperator(DateComparator type, Date date, DateResolution dateResolution) { Preconditions.checkNotNull(date); Preconditions.checkNotNull(dateResolution); this.type = type; this.date = date; this.dateResolution = dateResolution; } public Date getDate() { return date; } public DateResolution getDateResultion() { return dateResolution; } /** * Gets the operator type. * * @return the type, either {@link DateComparator#BEFORE}, * {@link DateComparator#AFTER} or {@link DateComparator#ON} */ public DateComparator getType() { return type; } @Override public int hashCode() { return Objects.hashCode(dateResolution, type); } @Override public boolean equals(Object obj) { if (obj instanceof DateOperator) { DateOperator that = (DateOperator) obj; return Objects.equal(this.dateResolution, that.dateResolution) && Objects.equal(this.type, that.type); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("date", date) .add("dateResolution", dateResolution) .add("type", type) .toString(); } } /** * Search for numbers within set of ranges. */ public static class InOperator implements Operator { private static final long serialVersionUID = 1L; private final NumericRange[] range; public InOperator(NumericRange[] range) { super(); this.range = range; } /** * Gets the filtering ranges. Values falling within these ranges will be * selected. * * @return the NumericRange's search on, not null */ public NumericRange[] getRange() { return range; } @Override public int hashCode() { return range.length; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final InOperator other = (InOperator) obj; if (!Arrays.equals(range, other.range)) { return false; } return true; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("range", Arrays.toString(range)) .toString(); } } /** * Search for uids within set of ranges. */ public static class UidInOperator implements Operator { private static final long serialVersionUID = 1L; private final UidRange[] ranges; public UidInOperator(UidRange[] ranges) { super(); this.ranges = ranges; } /** * Gets the filtering ranges. Values falling within these ranges will be * selected. * * @return the UidRange's search on, not null */ public UidRange[] getRange() { return ranges; } @Override public int hashCode() { return Arrays.hashCode(ranges); } @Override public boolean equals(Object obj) { if (obj instanceof UidInOperator) { UidInOperator other = (UidInOperator) obj; return Arrays.equals(this.ranges, other.ranges); } return false; } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("ranges", Arrays.toString(ranges)) .toString(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy