JAMES-1825 use a MessageUid strong type instead of long in the whole code base
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/34242a5b Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/34242a5b Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/34242a5b Branch: refs/heads/master Commit: 34242a5b3b6520ce9481002fd5af28ee3194d7eb Parents: df506d9 Author: Matthieu Baechler <[email protected]> Authored: Wed Sep 7 09:16:10 2016 +0200 Committer: Matthieu Baechler <[email protected]> Committed: Mon Oct 10 11:12:04 2016 +0200 ---------------------------------------------------------------------- .../apache/james/mailbox/MailboxListener.java | 8 +- .../apache/james/mailbox/MailboxManager.java | 2 +- .../apache/james/mailbox/MessageManager.java | 14 +- .../org/apache/james/mailbox/MessageUid.java | 93 +++++++ .../james/mailbox/model/MessageMetaData.java | 23 +- .../james/mailbox/model/MessageRange.java | 155 ++++------- .../apache/james/mailbox/model/SearchQuery.java | 146 +++++++++- .../james/mailbox/model/UpdatedFlags.java | 18 +- .../james/mailbox/MailboxManagerStressTest.java | 8 +- .../apache/james/mailbox/MessageUidTest.java | 57 ++++ .../mailbox/manager/ManagerTestResources.java | 3 +- .../james/mailbox/model/MessageRangeTest.java | 112 ++++++-- .../mailbox/caching/CachingMessageMapper.java | 11 +- .../mailbox/caching/MailboxMetadataCache.java | 17 +- .../guava/GuavaMailboxMetadataCache.java | 42 +-- mailbox/cassandra/pom.xml | 5 + .../cassandra/mail/CassandraMessageMapper.java | 41 +-- .../cassandra/mail/CassandraUidProvider.java | 74 ++--- ...essageDeletedDuringFlagsUpdateException.java | 3 +- .../mail/CassandraUidProviderTest.java | 22 +- ...lasticSearchListeningMessageSearchIndex.java | 9 +- .../elasticsearch/json/IndexableMessage.java | 5 +- .../elasticsearch/query/CriterionConverter.java | 6 +- .../search/ElasticSearchSearcher.java | 9 +- ...hListeningMailboxMessageSearchIndexTest.java | 25 +- .../MailboxMessageToElasticSearchJsonTest.java | 5 +- .../apache/james/mailbox/hbase/HBaseUtils.java | 30 +- .../mailbox/hbase/mail/HBaseMailboxMessage.java | 49 ++-- .../mailbox/hbase/mail/HBaseMessageMapper.java | 110 ++++---- .../mailbox/hbase/mail/HBaseUidProvider.java | 17 +- .../james/mailbox/hbase/HBaseUtilsTest.java | 2 + .../mail/HBaseMailboxMessageMapperTest.java | 11 +- .../mail/HBaseUidAndModSeqProviderTest.java | 42 +-- .../mailbox/jcr/mail/JCRMessageMapper.java | 61 ++-- .../james/mailbox/jcr/mail/JCRUidProvider.java | 21 +- .../jcr/mail/model/JCRMailboxMessage.java | 22 +- .../mailbox/jpa/mail/JPAMessageMapper.java | 86 +++--- .../james/mailbox/jpa/mail/JPAUidProvider.java | 14 +- .../openjpa/AbstractJPAMailboxMessage.java | 277 +++++++------------ .../openjpa/JPAEncryptedMailboxMessage.java | 3 +- .../mail/model/openjpa/JPAMailboxMessage.java | 3 +- .../openjpa/JPAStreamingMailboxMessage.java | 3 +- .../lucene/search/LuceneMessageSearchIndex.java | 74 +++-- .../LuceneMailboxMessageSearchIndexTest.java | 237 ++++++++-------- .../james/mailbox/maildir/MaildirFolder.java | 158 ++++++----- .../james/mailbox/maildir/MaildirStore.java | 18 +- .../maildir/mail/MaildirMessageMapper.java | 81 ++---- .../mail/model/MaildirMailboxMessage.java | 11 +- .../inmemory/mail/InMemoryMessageMapper.java | 117 +++----- .../inmemory/mail/InMemoryUidProvider.java | 36 ++- .../james/mailbox/store/MailboxMetaData.java | 29 +- .../james/mailbox/store/MessageResultImpl.java | 39 +-- .../mailbox/store/SimpleMessageMetaData.java | 36 +-- .../mailbox/store/StoreMailboxManager.java | 3 +- .../mailbox/store/StoreMessageManager.java | 94 +++---- .../store/StoreMessageResultIterator.java | 32 +-- .../james/mailbox/store/event/EventFactory.java | 31 ++- .../store/event/MailboxEventDispatcher.java | 7 +- .../store/json/JacksonEventSerializer.java | 59 ++++ .../mailbox/store/json/JsonEventSerializer.java | 3 +- .../store/json/MessagePackEventSerializer.java | 3 +- .../store/json/event/EventConverter.java | 17 +- .../json/event/dto/EventDataTransferObject.java | 22 +- .../dto/MessageMetaDataDataTransferObject.java | 8 +- .../dto/UpdatedFlagsDataTransferObject.java | 5 +- .../store/mail/AbstractLockingUidProvider.java | 14 +- .../store/mail/AbstractMessageMapper.java | 44 +-- .../james/mailbox/store/mail/MessageMapper.java | 29 +- .../james/mailbox/store/mail/UidProvider.java | 17 +- .../store/mail/model/DefaultMessageId.java | 7 +- .../mail/model/DelegatingMailboxMessage.java | 5 +- .../store/mail/model/MailboxMessage.java | 9 +- .../mail/model/impl/MessageUidComparator.java | 31 --- .../mail/model/impl/SimpleMailboxMessage.java | 28 +- .../quota/ListeningCurrentQuotaUpdater.java | 9 +- .../store/search/LazyMessageSearchIndex.java | 7 +- .../search/ListeningMessageSearchIndex.java | 5 +- .../store/search/MessageSearchIndex.java | 5 +- .../mailbox/store/search/MessageSearches.java | 39 +-- .../store/search/SimpleMessageSearchIndex.java | 19 +- .../store/search/comparator/UidComparator.java | 2 +- .../store/MailboxEventDispatcherTest.java | 3 +- .../store/MailboxMessageResultImplTest.java | 9 +- .../james/mailbox/store/MessageBatcherTest.java | 11 +- .../james/mailbox/store/MessageBuilder.java | 5 +- .../store/SearchUtilsMultipartMixedTest.java | 5 +- .../mailbox/store/SearchUtilsRFC822Test.java | 5 +- .../james/mailbox/store/SearchUtilsTest.java | 67 ++--- .../mailbox/store/SimpleMailboxMembership.java | 38 ++- .../StoreMailboxMessageResultIteratorTest.java | 36 +-- ...elegatingMailboxListenerIntegrationTest.java | 7 +- .../mailbox/store/json/EventSerializerTest.java | 7 +- .../MailboxMessagePackEventSerializerTest.java | 35 --- .../json/MessagePackEventSerializerTest.java | 35 +++ .../mail/model/DefaultMailboxMessageIdTest.java | 5 +- .../model/DelegatingMailboxMessageTest.java | 3 +- .../mail/model/MailboxMessageAssertTest.java | 3 +- .../store/mail/model/MessageMapperTest.java | 30 +- .../store/mail/model/MessageMoveTest.java | 2 +- .../store/mail/model/MetadataMapAssert.java | 9 +- .../store/mail/model/MetadataMapAssertTest.java | 19 +- .../quota/ListeningCurrentQuotaUpdaterTest.java | 125 ++------- .../search/AbstractMessageSearchIndexTest.java | 211 +++++++------- .../src/test/resources/eml/nonTextual.json | 2 +- .../store/src/test/resources/eml/spamMail.json | 2 +- .../indexer/events/FlagsMessageEvent.java | 8 +- .../indexer/events/ImpactingMessageEvent.java | 4 +- .../indexer/events/MessageDeletedEvent.java | 8 +- .../registrations/MailboxRegistration.java | 9 +- .../mailbox/indexer/ReIndexerImplTest.java | 3 +- .../registrations/MailboxRegistrationTest.java | 7 +- .../mailbox/store/mail/ZooUidProvider.java | 14 +- .../mailbox/store/mail/ZooUidProviderTest.java | 24 +- protocols/imap/pom.xml | 11 + .../apache/james/imap/api/message/UidRange.java | 148 ++++++++++ .../imap/api/message/request/SearchKey.java | 101 +++---- .../api/message/response/StatusResponse.java | 30 +- .../james/imap/api/process/SelectedMailbox.java | 51 ++-- .../imap/decode/ImapRequestLineReader.java | 75 +++++ .../parser/AbstractSelectionCommandParser.java | 74 +++-- .../decode/parser/ExamineCommandParser.java | 3 +- .../imap/decode/parser/SearchCommandParser.java | 3 +- .../imap/decode/parser/SelectCommandParser.java | 3 +- .../imap/encode/ESearchResponseEncoder.java | 13 +- .../james/imap/encode/FetchResponseEncoder.java | 5 +- .../james/imap/encode/ImapResponseComposer.java | 12 +- .../encode/MailboxStatusResponseEncoder.java | 5 +- .../encode/base/ImapResponseComposerImpl.java | 17 +- .../AbstractMailboxSelectionRequest.java | 15 +- .../imap/message/request/ExamineRequest.java | 3 +- .../imap/message/request/SelectRequest.java | 3 +- .../imap/message/response/ESearchResponse.java | 9 +- .../imap/message/response/FetchResponse.java | 7 +- .../message/response/MailboxStatusResponse.java | 7 +- .../imap/message/response/VanishedResponse.java | 14 +- .../processor/AbstractMailboxProcessor.java | 190 +++++++------ .../AbstractMessageRangeProcessor.java | 2 +- .../processor/AbstractSelectionProcessor.java | 55 ++-- .../james/imap/processor/AppendProcessor.java | 7 +- .../james/imap/processor/ExpungeProcessor.java | 5 +- .../james/imap/processor/SearchProcessor.java | 175 ++++++------ .../james/imap/processor/StatusProcessor.java | 7 +- .../james/imap/processor/StoreProcessor.java | 64 +++-- .../processor/base/SelectedMailboxImpl.java | 165 ++++------- .../processor/fetch/FetchResponseBuilder.java | 9 +- .../james/imap/api/message/UidRangeTest.java | 184 ++++++++++++ .../SearchCommandParserAndParenthesesTest.java | 12 +- .../parser/SearchCommandParserNotTest.java | 12 +- .../parser/SearchCommandParserOrTest.java | 12 +- ...chCommandParserSearchKeySequenceSetTest.java | 63 ++++- .../SearchCommandParserSearchKeyTest.java | 4 +- .../SearchCommandParserTopLevelAndTest.java | 12 +- .../FetchResponseEncoderNoExtensionsTest.java | 7 +- .../imap/encode/FetchResponseEncoderTest.java | 5 +- .../MailboxStatusResponseEncoderTest.java | 3 +- .../james/imap/processor/CopyProcessorTest.java | 22 +- .../james/imap/processor/MoveProcessorTest.java | 25 +- .../imap/processor/SearchProcessorTest.java | 49 ++-- .../base/FakeMailboxListenerAdded.java | 22 +- .../base/FakeMailboxListenerFlagsUpdate.java | 11 +- .../base/MailboxEventAnalyserTest.java | 50 ++-- protocols/pom.xml | 5 + .../jmap/methods/GetMessageListMethod.java | 9 +- .../methods/SetMessagesCreationProcessor.java | 3 +- .../apache/james/jmap/model/MessageFactory.java | 13 +- .../org/apache/james/jmap/model/MessageId.java | 13 +- .../FirstUserConnectionFilterThreadTest.java | 3 +- .../jmap/methods/GetMessagesMethodTest.java | 26 +- .../SetMessagesCreationProcessorTest.java | 2 + .../james/jmap/model/MessageFactoryTest.java | 15 +- .../apache/james/jmap/model/MessageIdTest.java | 7 +- .../apache/james/jmap/send/MailFactoryTest.java | 3 +- .../jmap/send/PostDequeueDecoratorTest.java | 7 +- .../utils/SortToComparatorConvertorTest.java | 7 +- .../pop3server/mailbox/MailboxAdapter.java | 13 +- 175 files changed, 3197 insertions(+), 2515 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxListener.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxListener.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxListener.java index 7c93361..32afb9c 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxListener.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxListener.java @@ -177,7 +177,7 @@ public interface MailboxListener { * * @return message uids */ - public abstract List<Long> getUids(); + public abstract List<MessageUid> getUids(); } abstract class MetaDataHoldingEvent extends MessageEvent { @@ -191,7 +191,7 @@ public interface MailboxListener { * * @return flags */ - public abstract MessageMetaData getMetaData(long uid); + public abstract MessageMetaData getMetaData(MessageUid uid); } @@ -211,7 +211,7 @@ public interface MailboxListener { * * @return flags */ - public abstract MessageMetaData getMetaData(long uid); + public abstract MessageMetaData getMetaData(MessageUid uid); } /** @@ -250,7 +250,7 @@ public interface MailboxListener { * * @return flags */ - public abstract MessageMetaData getMetaData(long uid); + public abstract MessageMetaData getMetaData(MessageUid uid); } http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java index 450c4fa..1b7afcd 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java @@ -235,7 +235,7 @@ public interface MailboxManager extends RequestAware, MailboxListenerSupport { * the context for this call, not null * @throws MailboxException */ - Map<MailboxId, Collection<Long>> search(MultimailboxesSearchQuery expression, MailboxSession session) throws MailboxException; + Map<MailboxId, Collection<MessageUid>> search(MultimailboxesSearchQuery expression, MailboxSession session) throws MailboxException; /** * Does the given mailbox exist? http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java index 92f3cae..888c071 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java @@ -99,7 +99,7 @@ public interface MessageManager { * @throws MailboxException * when search fails for other reasons */ - Iterator<Long> search(SearchQuery searchQuery, MailboxSession mailboxSession) throws MailboxException; + Iterator<MessageUid> search(SearchQuery searchQuery, MailboxSession mailboxSession) throws MailboxException; /** * Expunges messages in the given range from this mailbox. @@ -112,7 +112,7 @@ public interface MessageManager { * @throws MailboxException * if anything went wrong */ - Iterator<Long> expunge(MessageRange set, MailboxSession mailboxSession) throws MailboxException; + Iterator<MessageUid> expunge(MessageRange set, MailboxSession mailboxSession) throws MailboxException; /** * Sets flags on messages within the given range. The new flags are returned @@ -125,7 +125,7 @@ public interface MessageManager { * @return new flags indexed by UID * @throws MailboxException */ - Map<Long, Flags> setFlags(Flags flags, FlagsUpdateMode flagsUpdateMode, MessageRange set, MailboxSession mailboxSession) throws MailboxException; + Map<MessageUid, Flags> setFlags(Flags flags, FlagsUpdateMode flagsUpdateMode, MessageRange set, MailboxSession mailboxSession) throws MailboxException; /** * Appends a message to this mailbox. This method must return a higher UID @@ -146,7 +146,7 @@ public interface MessageManager { * @throws MailboxException * when message cannot be appended */ - long appendMessage(InputStream msgIn, Date internalDate, MailboxSession mailboxSession, boolean isRecent, Flags flags) throws MailboxException; + MessageUid appendMessage(InputStream msgIn, Date internalDate, MailboxSession mailboxSession, boolean isRecent, Flags flags) throws MailboxException; /** * Gets messages in the given range. The messages may get fetched under @@ -234,7 +234,7 @@ public interface MessageManager { * * @return the uids flagged RECENT in this mailbox, */ - List<Long> getRecent(); + List<MessageUid> getRecent(); /** * Gets the number of recent messages. @@ -264,7 +264,7 @@ public interface MessageManager { * * @return the uid that will be assigned to the next appended message */ - long getUidNext(); + MessageUid getUidNext(); /** * Return the highest mod-sequence for the mailbox. If this value has @@ -303,7 +303,7 @@ public interface MessageManager { * unseen messages * @see FetchGroup#FIRST_UNSEEN */ - Long getFirstUnseen(); + MessageUid getFirstUnseen(); /** * Is this mailbox writable? http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageUid.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageUid.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageUid.java new file mode 100644 index 0000000..44a8919 --- /dev/null +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageUid.java @@ -0,0 +1,93 @@ +/**************************************************************** + * 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; + +import org.apache.james.mailbox.model.MessageRange; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; + +public class MessageUid implements Comparable<MessageUid> { + + public static final MessageUid MAX_VALUE = of(Long.MAX_VALUE); + public static final MessageUid MIN_VALUE = of(1L); + + public static MessageUid of(long uid) { + return new MessageUid(uid); + } + + private final long uid; + + private MessageUid(long uid) { + this.uid = uid; + } + + public MessageRange toRange() { + return MessageRange.one(this); + } + + @Override + public int compareTo(MessageUid o) { + return Long.valueOf(uid).compareTo(Long.valueOf(o.uid)); + } + + public long asLong() { + return uid; + } + + @Override + public int hashCode() { + return Objects.hashCode(uid); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MessageUid) { + MessageUid other = (MessageUid) obj; + return other.uid == this.uid; + } + return false; + } + + @Override + public String toString() { + return "MessageUid{uid=" + uid + "}"; + } + + public MessageUid next() { + return new MessageUid(uid + 1); + } + + public boolean isFirst() { + return this.equals(MIN_VALUE); + } + + public MessageUid previous() { + if (this.compareTo(MIN_VALUE) > 0) { + return new MessageUid(uid - 1); + } + return MIN_VALUE; + } + + public long distance(MessageUid other) { + Preconditions.checkNotNull(other); + return other.uid - this.uid; + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageMetaData.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageMetaData.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageMetaData.java index 504ef16..ae214ed 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageMetaData.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageMetaData.java @@ -22,40 +22,23 @@ import java.util.Date; import javax.mail.Flags; -/** - * Represent the {@link MessageMetaData} for a message - * - * - */ +import org.apache.james.mailbox.MessageUid; + public interface MessageMetaData { - /** - * Return the uid of the message which the MessageResult belongs to - * - * @return uid - */ - long getUid(); + MessageUid getUid(); /** * Return the modify-sequence number of the message. This is kind of optional and the mailbox * implementation may not support this. If so it will return -1 - * - * @return modSeq */ long getModSeq(); - /** - * Return the {@link Flags} - * - * @return flags - */ Flags getFlags(); /** * Return the size in bytes - * - * @return size */ long getSize(); http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageRange.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageRange.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageRange.java index 8f9e2b7..c1c285a 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageRange.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MessageRange.java @@ -26,11 +26,15 @@ import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; +import org.apache.james.mailbox.MessageUid; + +import com.google.common.base.Objects; + /** * Used to define a range of messages by uid.<br> * The type of the set should be defined by using an appropriate constructor. */ -public class MessageRange implements Iterable<Long>{ +public class MessageRange implements Iterable<MessageUid>{ public enum Type { /** All messages */ @@ -39,32 +43,25 @@ public class MessageRange implements Iterable<Long>{ ONE, /** All messages with a uid equal or higher than */ FROM, - /** All messagse within the given range of uids (inclusive) */ + /** All messages within the given range of uids (inclusive) */ RANGE } - public static final long NOT_A_UID = -1; - - public static final long MAX_UID = Long.MAX_VALUE; - /** * Constructs a range consisting of a single message only. * * @param uid * UID of the message - * @return not null */ - public static MessageRange one(long uid) { + public static MessageRange one(MessageUid uid) { return new MessageRange(Type.ONE, uid, uid); } /** * Constructs a range consisting of all messages. - * - * @return not null */ public static MessageRange all() { - return new MessageRange(Type.ALL, NOT_A_UID, MAX_UID); + return new MessageRange(Type.ALL, MessageUid.MIN_VALUE, MessageUid.MAX_VALUE); } /** @@ -75,20 +72,16 @@ public class MessageRange implements Iterable<Long>{ * first message UID * @param to * last message UID - * @return not null */ - public static MessageRange range(long from, long to) { - final MessageRange result; - if (to == Long.MAX_VALUE || to < from) { - to = NOT_A_UID; - result = from(from); - } else if (from == to) { + public static MessageRange range(MessageUid from, MessageUid to) { + if (to.equals(MessageUid.MAX_VALUE) || to.compareTo(from) < 0) { + return from(from); + } else if (from.equals(to)) { // from and to is the same so no need to construct a real range - result = one(from); + return one(from); } else { - result = new MessageRange(Type.RANGE, from, to); + return new MessageRange(Type.RANGE, from, to); } - return result; } @@ -97,59 +90,54 @@ public class MessageRange implements Iterable<Long>{ * * @param from * first message UID in range - * @return not null */ - public static MessageRange from(long from) { - return new MessageRange(Type.FROM, from, MAX_UID); + public static MessageRange from(MessageUid from) { + return new MessageRange(Type.FROM, from, MessageUid.MAX_VALUE); } private final Type type; + private final MessageUid uidFrom; + private final MessageUid uidTo; - private final long uidFrom; - - private final long uidTo; - - protected MessageRange(Type type, long uidFrom, long uidTo) { + protected MessageRange(Type type, MessageUid minValue, MessageUid maxValue) { super(); this.type = type; - this.uidFrom = uidFrom; - this.uidTo = uidTo; + this.uidFrom = minValue; + this.uidTo = maxValue; } public Type getType() { return type; } - public long getUidFrom() { + public MessageUid getUidFrom() { return uidFrom; } - public long getUidTo() { + public MessageUid getUidTo() { return uidTo; } /** * Return true if the uid is within the range - * - * @param uid - * @return withinRange */ - public boolean includes(long uid) { + public boolean includes(MessageUid uid) { switch (type) { case ALL: return true; case FROM: - if (uid > getUidFrom()) { + if (getUidFrom().compareTo(uid) <= 0) { return true; } case RANGE: - if (uid >= getUidFrom() && uid <= getUidTo()) { + if (getUidFrom().compareTo(uid) <= 0 && + getUidTo().compareTo(uid) >= 0) { return true; } case ONE: - if (getUidFrom() == uid) { + if (getUidFrom().equals(uid)) { return true; } default: @@ -169,35 +157,35 @@ public class MessageRange implements Iterable<Long>{ * collection of uids to convert * @return ranges */ - public static List<MessageRange> toRanges(Collection<Long> uidsCol) { + public static List<MessageRange> toRanges(Collection<MessageUid> uidsCol) { List<MessageRange> ranges = new ArrayList<MessageRange>(); - List<Long> uids = new ArrayList<Long>(uidsCol); + List<MessageUid> uids = new ArrayList<MessageUid>(uidsCol); Collections.sort(uids); long firstUid = 0; int a = 0; for (int i = 0; i < uids.size(); i++) { - long u = uids.get(i); + long u = uids.get(i).asLong(); if (i == 0) { firstUid = u; if (uids.size() == 1) { - ranges.add(MessageRange.one(firstUid)); + ranges.add(MessageUid.of(firstUid).toRange()); } } else { if ((firstUid + a +1) != u) { - ranges.add(MessageRange.range(firstUid, firstUid + a)); + ranges.add(MessageRange.range(MessageUid.of(firstUid), MessageUid.of(firstUid + a))); // set the next first uid and reset the counter firstUid = u; a = 0; if (uids.size() <= i +1) { - ranges.add(MessageRange.one(firstUid)); + ranges.add(MessageUid.of(firstUid).toRange()); } } else { a++; // Handle uids which are in sequence. See MAILBOX-56 if (uids.size() <= i +1) { - ranges.add(MessageRange.range(firstUid, firstUid +a)); + ranges.add(MessageRange.range(MessageUid.of(firstUid), MessageUid.of(firstUid + a))); break; } } @@ -208,35 +196,21 @@ public class MessageRange implements Iterable<Long>{ /** - * Return a read-only {@link Iterator} which contains all uid which fail in the specified range. - * - * @return rangeIt + * Return a read-only {@link Iterator} which contains all uid which fall in the specified range. */ @Override - public Iterator<Long> iterator() { - long from = getUidFrom(); - if (from == NOT_A_UID) { - from = 1; - } - long to = getUidTo(); - if (to == NOT_A_UID) { - to = Long.MAX_VALUE; - } - return new RangeIterator(from, to); + public Iterator<MessageUid> iterator() { + return new RangeIterator(getUidFrom(), getUidTo()); } - /** - * {@link Iterator} of a range of msn/uid - * - */ - private final class RangeIterator implements Iterator<Long> { + private final class RangeIterator implements Iterator<MessageUid> { private final long to; private long current; - public RangeIterator(long from, long to) { - this.to = to; - this.current = from; + public RangeIterator(MessageUid from, MessageUid to) { + this.to = to.asLong(); + this.current = from.asLong(); } @Override @@ -245,9 +219,9 @@ public class MessageRange implements Iterable<Long>{ } @Override - public Long next() { + public MessageUid next() { if (hasNext()) { - return current++; + return MessageUid.of(current++); } else { throw new NoSuchElementException("Max uid of " + to + " was reached before"); } @@ -265,15 +239,12 @@ public class MessageRange implements Iterable<Long>{ * Tries to split the given {@link MessageRange} to a {@link List} of {@link MessageRange}'s which * select only a max amount of items. This only work for {@link MessageRange}'s with {@link Type} of * {@link Type#RANGE}. - * - * @param maxItems - * @return ranges */ - public List<MessageRange> split( int maxItems) { + public List<MessageRange> split(int maxItems) { List<MessageRange> ranges = new ArrayList<MessageRange>(); if (getType() == Type.RANGE) { - long from = getUidFrom(); - long to = getUidTo(); + long from = getUidFrom().asLong(); + long to = getUidTo().asLong(); long realTo = to; while(from <= realTo) { if (from + maxItems -1 < realTo) { @@ -282,9 +253,9 @@ public class MessageRange implements Iterable<Long>{ to = realTo; } if (from == to) { - ranges.add(MessageRange.one(from)); + ranges.add(MessageUid.of(from).toRange()); } else { - ranges.add(MessageRange.range(from, to)); + ranges.add(MessageRange.range(MessageUid.of(from), MessageUid.of(to))); } from = to + 1; @@ -297,29 +268,17 @@ public class MessageRange implements Iterable<Long>{ @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((type == null) ? 0 : type.hashCode()); - result = prime * result + (int) (uidFrom ^ (uidFrom >>> 32)); - result = prime * result + (int) (uidTo ^ (uidTo >>> 32)); - return result; + return Objects.hashCode(type, uidFrom, uidTo); } @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - MessageRange other = (MessageRange) obj; - if (type != other.type) - return false; - if (uidFrom != other.uidFrom) - return false; - if (uidTo != other.uidTo) - return false; - return true; + if (obj instanceof MessageRange) { + MessageRange other = (MessageRange) obj; + return Objects.equal(this.type, other.type) && + Objects.equal(this.uidFrom, other.uidFrom) && + Objects.equal(this.uidTo, other.uidTo); + } + return false; } } http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java index 490a365..46a96a3 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java @@ -30,6 +30,10 @@ import java.util.Set; import javax.mail.Flags; import javax.mail.Flags.Flag; +import org.apache.james.mailbox.MessageUid; + +import com.google.common.base.Objects; + /** * <p> * Models a query used to search for messages. A query is the logical @@ -466,7 +470,7 @@ public class SearchQuery implements Serializable { * <code>NumericRange</code>'s, not null * @return <code>Criterion</code>, not null */ - public static final Criterion uid(NumericRange[] range) { + public static final Criterion uid(UidRange[] range) { return new UidCriterion(range); } @@ -645,7 +649,7 @@ public class SearchQuery implements Serializable { return AllCriterion.all(); } - private final Set<Long> recentMessageUids = new HashSet<Long>(); + private final Set<MessageUid> recentMessageUids = new HashSet<MessageUid>(); private final List<Criterion> criterias = new ArrayList<Criterion>(); @@ -689,9 +693,9 @@ public class SearchQuery implements Serializable { * list of recent mail is maintained in the protocol layer since the * mechanics are protocol specific. * - * @return mutable <code>Set</code> of <code>Long</code> UIDS + * @return mutable <code>Set</code> of <code>MessageUid</code> UIDS */ - public Set<Long> getRecentMessageUids() { + public Set<MessageUid> getRecentMessageUids() { return recentMessageUids; } @@ -701,7 +705,7 @@ public class SearchQuery implements Serializable { * @param uids * not null */ - public void addRecentMessageUids(Collection<Long> uids) { + public void addRecentMessageUids(Collection<MessageUid> uids) { recentMessageUids.addAll(uids); } @@ -831,6 +835,68 @@ public class SearchQuery implements Serializable { } /** + * 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 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 other = (UidRange) obj; + return Objects.equal(this.lowValue, other.lowValue) + && Objects.equal(this.highValue, other.highValue); + } + return false; + } + + public String toString() { + return new StringBuffer().append(this.lowValue).append("->").append(this.highValue).toString(); + } + + } + + /** * Marker superclass for criteria. */ public static abstract class Criterion implements Serializable { @@ -1545,25 +1611,20 @@ public class SearchQuery implements Serializable { public static final class UidCriterion extends Criterion { private static final long serialVersionUID = 1L; - private final InOperator operator; + private final UidInOperator operator; - public UidCriterion(NumericRange[] ranges) { + public UidCriterion(UidRange[] ranges) { super(); - this.operator = new InOperator(ranges); + this.operator = new UidInOperator(ranges); } /** * Gets the filtering operation. - * - * @return the <code>InOperator</code> */ - public InOperator getOperator() { + public UidInOperator getOperator() { return operator; } - /** - * @see java.lang.Object#hashCode() - */ @Override public int hashCode() { final int PRIME = 31; @@ -2130,4 +2191,61 @@ public class SearchQuery implements Serializable { } } + + /** + * Search for uids within set of ranges. + */ + public static final 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 <code>UidRange</code>'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; + } + + /** + * Constructs a <code>String</code> with all attributes in name = value + * format. + * + * @return a <code>String</code> representation of this object. + */ + public String toString() { + final String TAB = " "; + + StringBuffer retValue = new StringBuffer(); + + retValue.append("UidInOperator ( ").append("range = ").append(Arrays.toString(this.ranges)).append(TAB) + .append(" )"); + + return retValue.toString(); + } + + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/main/java/org/apache/james/mailbox/model/UpdatedFlags.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/UpdatedFlags.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/UpdatedFlags.java index 7f56b70..a05a9ba 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/UpdatedFlags.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/UpdatedFlags.java @@ -24,6 +24,10 @@ import java.util.Iterator; import javax.mail.Flags; +import org.apache.james.mailbox.MessageUid; + +import com.google.common.base.Objects; + /** * Represent a Flag update for a message * @@ -31,13 +35,13 @@ import javax.mail.Flags; */ public class UpdatedFlags { - private final long uid; + private final MessageUid uid; private final Flags oldFlags; private final Flags newFlags; private final Flags modifiedFlags; private final long modSeq; - public UpdatedFlags(long uid, long modSeq, Flags oldFlags, Flags newFlags) { + public UpdatedFlags(MessageUid uid, long modSeq, Flags oldFlags, Flags newFlags) { this.uid = uid; this.modSeq = modSeq; this.oldFlags = oldFlags; @@ -114,7 +118,7 @@ public class UpdatedFlags { * * @return uid */ - public long getUid() { + public MessageUid getUid() { return uid; } @@ -179,7 +183,7 @@ public class UpdatedFlags { UpdatedFlags that = (UpdatedFlags) other; - if (uid != that.uid) { + if (!uid.equals(that.uid)) { return false; } if (modSeq != that.modSeq) { @@ -194,10 +198,6 @@ public class UpdatedFlags { @Override public int hashCode() { - int result = (int) (uid ^ (uid >>> 32)); - result = 31 * result + (oldFlags != null ? oldFlags.hashCode() : 0); - result = 31 * result + (newFlags != null ? newFlags.hashCode() : 0); - result = 31 * result + (int) (modSeq ^ (modSeq >>> 32)); - return result; + return Objects.hashCode(uid, oldFlags, newFlags, modSeq); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressTest.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressTest.java index 649255e..8c13ad8 100644 --- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressTest.java +++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressTest.java @@ -68,7 +68,7 @@ public class MailboxManagerStressTest<T extends MailboxManager> { final CountDownLatch latch = new CountDownLatch(APPEND_OPERATIONS); final ExecutorService pool = Executors.newFixedThreadPool(APPEND_OPERATIONS / 2); - final List<Long> uList = new ArrayList<Long>(); + final List<MessageUid> uList = new ArrayList<MessageUid>(); final String username = "username"; MailboxSession session = mailboxManager.createSystemSession(username, LoggerFactory.getLogger("Test")); mailboxManager.startProcessingRequest(session); @@ -88,7 +88,7 @@ public class MailboxManagerStressTest<T extends MailboxManager> { @Override public void event(Event event) { - long u = ((Added) event).getUids().get(0); + MessageUid u = ((Added) event).getUids().get(0); uList.add(u); } }, session); @@ -96,7 +96,7 @@ public class MailboxManagerStressTest<T extends MailboxManager> { mailboxManager.logout(session, false); final AtomicBoolean fail = new AtomicBoolean(false); - final ConcurrentHashMap<Long, Object> uids = new ConcurrentHashMap<Long, Object>(); + final ConcurrentHashMap<MessageUid, Object> uids = new ConcurrentHashMap<MessageUid, Object>(); // fire of 1000 append operations for (int i = 0; i < APPEND_OPERATIONS; i++) { @@ -114,7 +114,7 @@ public class MailboxManagerStressTest<T extends MailboxManager> { mailboxManager.startProcessingRequest(session); MessageManager m = mailboxManager.getMailbox(path, session); - Long uid = m.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), session, false, new Flags()); + MessageUid uid = m.appendMessage(new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), session, false, new Flags()); System.out.println("Append message with uid=" + uid); if (uids.put(uid, new Object()) != null) { http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/test/java/org/apache/james/mailbox/MessageUidTest.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MessageUidTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MessageUidTest.java new file mode 100644 index 0000000..ee3f42e --- /dev/null +++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MessageUidTest.java @@ -0,0 +1,57 @@ +/**************************************************************** + * 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; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class MessageUidTest { + + @Rule public ExpectedException exception = ExpectedException.none(); + + private static final MessageUid _1 = MessageUid.of(1); + private static final MessageUid _2 = MessageUid.of(2); + private static final MessageUid _3 = MessageUid.of(3); + private static final MessageUid _4 = MessageUid.of(4); + + @Test + public void distanceShouldReturnZeroWhenSameValue() { + assertThat(_1.distance(_1)).isEqualTo(0); + } + + @Test + public void distanceShouldThrowWhenNullArgument() { + exception.expect(NullPointerException.class); + _1.distance(null); + } + + + @Test + public void distanceShouldReturnPositiveDistanceWhenGreaterArgument() { + assertThat(_1.distance(_4)).isEqualTo(3); + } + + @Test + public void distanceShouldReturnNegativeDistanceWhenSmallerArgument() { + assertThat(_3.distance(_2)).isEqualTo(-1); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/test/java/org/apache/james/mailbox/manager/ManagerTestResources.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/manager/ManagerTestResources.java b/mailbox/api/src/test/java/org/apache/james/mailbox/manager/ManagerTestResources.java index cdbf3e1..ad51474 100644 --- a/mailbox/api/src/test/java/org/apache/james/mailbox/manager/ManagerTestResources.java +++ b/mailbox/api/src/test/java/org/apache/james/mailbox/manager/ManagerTestResources.java @@ -24,6 +24,7 @@ import org.apache.james.mailbox.MailboxManager; import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.quota.MaxQuotaManager; import org.apache.james.mailbox.MessageManager; +import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.quota.QuotaManager; import org.apache.james.mailbox.acl.GroupMembershipResolver; import org.apache.james.mailbox.exception.MailboxException; @@ -138,7 +139,7 @@ public class ManagerTestResources { appendMessage(messageManager, session, new FlagsBuilder().add(Flags.Flag.RECENT).build()); } - public long appendMessage(MessageManager messageManager, MailboxSession session, Flags flags) throws MailboxException, UnsupportedEncodingException { + public MessageUid appendMessage(MessageManager messageManager, MailboxSession session, Flags flags) throws MailboxException, UnsupportedEncodingException { return messageManager.appendMessage(new ByteArrayInputStream(MockMail.MAIL_TEXT_PLAIN.getBytes("UTF-8")), Calendar.getInstance().getTime(), session, true, flags); } http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageRangeTest.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageRangeTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageRangeTest.java index 4cbd0a9..58e07d3 100644 --- a/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageRangeTest.java +++ b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageRangeTest.java @@ -23,6 +23,7 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.Arrays; import java.util.List; +import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.model.MessageRange; import org.junit.Test; @@ -30,48 +31,125 @@ public class MessageRangeTest { @Test public void givenSomeNumbersToRangeShouldReturnThreeRanges() { - List<MessageRange> ranges = MessageRange.toRanges(Arrays.asList(1L,2L,3L,5L,6L,9L)); + List<MessageRange> ranges = MessageRange.toRanges( + Arrays.asList( + MessageUid.of(1L), + MessageUid.of(2L), + MessageUid.of(3L), + MessageUid.of(5L), + MessageUid.of(6L), + MessageUid.of(9L))); assertThat(ranges).containsExactly( - MessageRange.range(1, 3), - MessageRange.range(5, 6), - MessageRange.one(9)); + MessageRange.range(MessageUid.of(1), MessageUid.of(3)), + MessageRange.range(MessageUid.of(5), MessageUid.of(6)), + MessageUid.of(9).toRange()); } @Test public void givenASingleNumberToRangeShouldReturnOneRange() { - List<MessageRange> ranges = MessageRange.toRanges(Arrays.asList(1L)); - assertThat(ranges).containsExactly(MessageRange.one(1)); + List<MessageRange> ranges = MessageRange.toRanges(Arrays.asList(MessageUid.of(1L))); + assertThat(ranges).containsExactly(MessageUid.of(1).toRange()); } // Test for MAILBOX-56 @Test public void testTwoSeqUidToRange() { - List<MessageRange> ranges = MessageRange.toRanges(Arrays.asList(1L,2L)); - assertThat(ranges).containsExactly(MessageRange.range(1, 2)); + List<MessageRange> ranges = MessageRange.toRanges(Arrays.asList(MessageUid.of(1L), MessageUid.of(2L))); + assertThat(ranges).containsExactly(MessageRange.range(MessageUid.of(1), MessageUid.of(2))); } @Test public void splitASingletonRangeShouldReturnASingleRange() { - MessageRange one = MessageRange.one(1); + MessageRange one = MessageUid.of(1).toRange(); List<MessageRange> ranges = one.split(2); - assertThat(ranges).containsExactly(MessageRange.one(1)); + assertThat(ranges).containsExactly(MessageUid.of(1).toRange()); } @Test public void splitUnboundedRangeShouldReturnTheSameRange() { - MessageRange from = MessageRange.from(1); + MessageRange from = MessageRange.from(MessageUid.of(1)); List<MessageRange> ranges = from.split(2); - assertThat(ranges).containsExactly(MessageRange.from(1)); + assertThat(ranges).containsExactly(MessageRange.from(MessageUid.of(1))); } @Test public void splitTenElementsRangeShouldReturn4Ranges() { - MessageRange range = MessageRange.range(1,10); + MessageRange range = MessageRange.range(MessageUid.of(1),MessageUid.of(10)); List<MessageRange> ranges = range.split(3); assertThat(ranges).containsExactly( - MessageRange.range(1, 3), - MessageRange.range(4, 6), - MessageRange.range(7, 9), - MessageRange.one(10)); + MessageRange.range(MessageUid.of(1), MessageUid.of(3)), + MessageRange.range(MessageUid.of(4), MessageUid.of(6)), + MessageRange.range(MessageUid.of(7), MessageUid.of(9)), + MessageUid.of(10).toRange()); + } + + @Test + public void includeShouldBeTrueWhenAfterFrom() { + MessageRange range = MessageRange.from(MessageUid.of(3)); + boolean actual = range.includes(MessageUid.of(5)); + assertThat(actual).isTrue(); + } + + @Test + public void includeShouldBeFalseWhenBeforeFrom() { + MessageRange range = MessageRange.from(MessageUid.of(3)); + boolean actual = range.includes(MessageUid.of(1)); + assertThat(actual).isFalse(); + } + + @Test + public void includeShouldBeTrueWhenEqualsFrom() { + MessageRange range = MessageRange.from(MessageUid.of(3)); + boolean actual = range.includes(MessageUid.of(3)); + assertThat(actual).isTrue(); + } + + @Test + public void includeShouldBeFalseWhenDifferentOne() { + MessageRange range = MessageUid.of(3).toRange(); + boolean actual = range.includes(MessageUid.of(1)); + assertThat(actual).isFalse(); + } + + @Test + public void includeShouldBeTrueWhenEqualsOne() { + MessageRange range = MessageUid.of(3).toRange(); + boolean actual = range.includes(MessageUid.of(3)); + assertThat(actual).isTrue(); + } + + @Test + public void includeShouldBeFalseWhenBeforeRange() { + MessageRange range = MessageRange.range(MessageUid.of(3), MessageUid.of(6)); + boolean actual = range.includes(MessageUid.of(1)); + assertThat(actual).isFalse(); + } + + @Test + public void includeShouldBeTrueWhenEqualsFromRange() { + MessageRange range = MessageRange.range(MessageUid.of(3), MessageUid.of(6)); + boolean actual = range.includes(MessageUid.of(3)); + assertThat(actual).isTrue(); + } + + @Test + public void includeShouldBeTrueWhenInRange() { + MessageRange range = MessageRange.range(MessageUid.of(3), MessageUid.of(6)); + boolean actual = range.includes(MessageUid.of(4)); + assertThat(actual).isTrue(); + } + + @Test + public void includeShouldBeTrueWhenEqualsToRange() { + MessageRange range = MessageRange.range(MessageUid.of(3), MessageUid.of(6)); + boolean actual = range.includes(MessageUid.of(6)); + assertThat(actual).isTrue(); + } + + @Test + public void includeShouldBeFalseWhenAfterRange() { + MessageRange range = MessageRange.range(MessageUid.of(3), MessageUid.of(6)); + boolean actual = range.includes(MessageUid.of(7)); + assertThat(actual).isFalse(); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/CachingMessageMapper.java ---------------------------------------------------------------------- diff --git a/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/CachingMessageMapper.java b/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/CachingMessageMapper.java index d27e759..a482a66 100644 --- a/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/CachingMessageMapper.java +++ b/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/CachingMessageMapper.java @@ -3,6 +3,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.MessageMetaData; import org.apache.james.mailbox.model.MessageRange; @@ -12,6 +13,8 @@ import org.apache.james.mailbox.store.mail.MessageMapper; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import com.google.common.base.Optional; + /** * A MessageMapper implementation that uses a MailboxMetadataCache to cache the information * from the underlying MessageMapper @@ -46,7 +49,7 @@ public class CachingMessageMapper implements MessageMapper { } @Override - public Map<Long, MessageMetaData> expungeMarkedForDeletionInMailbox( + public Map<MessageUid, MessageMetaData> expungeMarkedForDeletionInMailbox( Mailbox mailbox, MessageRange set) throws MailboxException { invalidateMetadata(mailbox); return underlying.expungeMarkedForDeletionInMailbox(mailbox, set); @@ -73,13 +76,13 @@ public class CachingMessageMapper implements MessageMapper { } @Override - public Long findFirstUnseenMessageUid(Mailbox mailbox) + public MessageUid findFirstUnseenMessageUid(Mailbox mailbox) throws MailboxException { return cache.findFirstUnseenMessageUid(mailbox, underlying); } @Override - public List<Long> findRecentMessageUidsInMailbox(Mailbox mailbox) + public List<MessageUid> findRecentMessageUidsInMailbox(Mailbox mailbox) throws MailboxException { // TODO can be meaningfully cached? return underlying.findRecentMessageUidsInMailbox(mailbox); @@ -110,7 +113,7 @@ public class CachingMessageMapper implements MessageMapper { } @Override - public long getLastUid(Mailbox mailbox) throws MailboxException { + public Optional<MessageUid> getLastUid(Mailbox mailbox) throws MailboxException { return cache.getLastUid(mailbox, underlying); } http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/MailboxMetadataCache.java ---------------------------------------------------------------------- diff --git a/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/MailboxMetadataCache.java b/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/MailboxMetadataCache.java index bc58ddd..e634ec7 100644 --- a/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/MailboxMetadataCache.java +++ b/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/MailboxMetadataCache.java @@ -1,9 +1,12 @@ package org.apache.james.mailbox.caching; +import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.store.mail.MessageMapper; import org.apache.james.mailbox.store.mail.model.Mailbox; +import com.google.common.base.Optional; + /** * Caches the simple yet possibly expensive to compute metadata info * about a Mailbox like all/unseen messages count and similar @@ -12,19 +15,19 @@ import org.apache.james.mailbox.store.mail.model.Mailbox; public interface MailboxMetadataCache { long countMessagesInMailbox(Mailbox mailbox, - MessageMapper underlying) throws MailboxException; + MessageMapper underlying) throws MailboxException; long countUnseenMessagesInMailbox(Mailbox mailbox, - MessageMapper underlying) throws MailboxException; + MessageMapper underlying) throws MailboxException; - Long findFirstUnseenMessageUid(Mailbox mailbox, - MessageMapper underlying) throws MailboxException; + MessageUid findFirstUnseenMessageUid(Mailbox mailbox, + MessageMapper underlying) throws MailboxException; - long getLastUid(Mailbox mailbox, - MessageMapper underlying) throws MailboxException; + Optional<MessageUid> getLastUid(Mailbox mailbox, + MessageMapper underlying) throws MailboxException; long getHighestModSeq(Mailbox mailbox, - MessageMapper underlying) throws MailboxException; + MessageMapper underlying) throws MailboxException; void invalidate(Mailbox mailbox); http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/guava/GuavaMailboxMetadataCache.java ---------------------------------------------------------------------- diff --git a/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/guava/GuavaMailboxMetadataCache.java b/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/guava/GuavaMailboxMetadataCache.java index 3d539ad..42212c4 100644 --- a/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/guava/GuavaMailboxMetadataCache.java +++ b/mailbox/caching/src/main/java/org/apache/james/mailbox/caching/guava/GuavaMailboxMetadataCache.java @@ -1,11 +1,13 @@ package org.apache.james.mailbox.caching.guava; +import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.caching.MailboxMetadataCache; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.store.mail.MessageMapper; import org.apache.james.mailbox.store.mail.model.Mailbox; +import com.google.common.base.Optional; import com.google.common.cache.Cache; /** * Guava-based implementation of MailboxMetadataCache. @@ -18,15 +20,15 @@ public class GuavaMailboxMetadataCache extends AbstractGuavaCache implements Mai // TODO these can probably be instantiated more elegant way private final Cache<MailboxId, Long> cacheCountMessagesInMailbox = BUILDER.build(); private final Cache<MailboxId, Long> cacheCountUnseenMessagesInMailbox = BUILDER.build(); - private final Cache<MailboxId, Long> cacheFindFirstUnseenMessageUid = BUILDER.build(); - private final Cache<MailboxId, Long> cacheGetLastUid = BUILDER.build(); + private final Cache<MailboxId, MessageUid> cacheFindFirstUnseenMessageUid = BUILDER.build(); + private final Cache<MailboxId, Optional<MessageUid>> cacheGetLastUid = BUILDER.build(); private final Cache<MailboxId, Long> cacheGetHighestModSeq = BUILDER.build(); - private final MetadataCacheWrapper countMessagesInMailboxWrapper = new CountMessagesInMailboxWrapper(cacheCountMessagesInMailbox); - private final MetadataCacheWrapper countUnseenMessagesInMailboxWrapper = new CountUnseenMessagesInMailboxWrapper(cacheCountUnseenMessagesInMailbox); - private final MetadataCacheWrapper findFirstUnseenMessageUid = new FindFirstUnseenMessageUidWrapper(cacheFindFirstUnseenMessageUid); - private final MetadataCacheWrapper highestModSeqWrapper = new HighestModseqCacheWrapper(cacheGetHighestModSeq); - private final MetadataCacheWrapper lastUidWrapper = new LastUidCacheWrapper(cacheGetLastUid); + private final MetadataCacheWrapper<Long> countMessagesInMailboxWrapper = new CountMessagesInMailboxWrapper(cacheCountMessagesInMailbox); + private final MetadataCacheWrapper<Long> countUnseenMessagesInMailboxWrapper = new CountUnseenMessagesInMailboxWrapper(cacheCountUnseenMessagesInMailbox); + private final MetadataCacheWrapper<MessageUid> findFirstUnseenMessageUid = new FindFirstUnseenMessageUidWrapper(cacheFindFirstUnseenMessageUid); + private final MetadataCacheWrapper<Long> highestModSeqWrapper = new HighestModseqCacheWrapper(cacheGetHighestModSeq); + private final MetadataCacheWrapper<Optional<MessageUid>> lastUidWrapper = new LastUidCacheWrapper(cacheGetLastUid); @Override public long countMessagesInMailbox(Mailbox mailbox, MessageMapper underlying) throws MailboxException { @@ -40,13 +42,13 @@ public class GuavaMailboxMetadataCache extends AbstractGuavaCache implements Mai } @Override - public Long findFirstUnseenMessageUid(Mailbox mailbox, MessageMapper underlying) + public MessageUid findFirstUnseenMessageUid(Mailbox mailbox, MessageMapper underlying) throws MailboxException { return findFirstUnseenMessageUid.get(mailbox, underlying); } @Override - public long getLastUid(Mailbox mailbox, MessageMapper underlying) throws MailboxException { + public Optional<MessageUid> getLastUid(Mailbox mailbox, MessageMapper underlying) throws MailboxException { return lastUidWrapper.get(mailbox, underlying); } @@ -66,9 +68,9 @@ public class GuavaMailboxMetadataCache extends AbstractGuavaCache implements Mai } - abstract class MetadataCacheWrapper extends GuavaCacheWrapper<Mailbox, Long, MessageMapper, MailboxId, MailboxException> { + abstract class MetadataCacheWrapper<Value> extends GuavaCacheWrapper<Mailbox, Value, MessageMapper, MailboxId, MailboxException> { - public MetadataCacheWrapper(Cache<MailboxId, Long> cache) { + public MetadataCacheWrapper(Cache<MailboxId, Value> cache) { super(cache); } @@ -79,7 +81,7 @@ public class GuavaMailboxMetadataCache extends AbstractGuavaCache implements Mai } - class CountMessagesInMailboxWrapper extends MetadataCacheWrapper { + class CountMessagesInMailboxWrapper extends MetadataCacheWrapper<Long> { public CountMessagesInMailboxWrapper(Cache<MailboxId, Long> cache) { super(cache); @@ -92,7 +94,7 @@ public class GuavaMailboxMetadataCache extends AbstractGuavaCache implements Mai } - class CountUnseenMessagesInMailboxWrapper extends MetadataCacheWrapper { + class CountUnseenMessagesInMailboxWrapper extends MetadataCacheWrapper<Long> { public CountUnseenMessagesInMailboxWrapper(Cache<MailboxId, Long> cache) { super(cache); @@ -105,30 +107,30 @@ public class GuavaMailboxMetadataCache extends AbstractGuavaCache implements Mai } - class FindFirstUnseenMessageUidWrapper extends MetadataCacheWrapper { + class FindFirstUnseenMessageUidWrapper extends MetadataCacheWrapper<MessageUid> { - public FindFirstUnseenMessageUidWrapper(Cache<MailboxId, Long> cache) { + public FindFirstUnseenMessageUidWrapper(Cache<MailboxId, MessageUid> cache) { super(cache); } @Override - public Long load(Mailbox mailbox, MessageMapper underlying) + public MessageUid load(Mailbox mailbox, MessageMapper underlying) throws MailboxException { return underlying.findFirstUnseenMessageUid(mailbox); } } - class LastUidCacheWrapper extends MetadataCacheWrapper { - public LastUidCacheWrapper(Cache<MailboxId, Long> cache) { + class LastUidCacheWrapper extends MetadataCacheWrapper<Optional<MessageUid>> { + public LastUidCacheWrapper(Cache<MailboxId, Optional<MessageUid>> cache) { super(cache); } @Override - public Long load(Mailbox mailbox, MessageMapper underlying) throws MailboxException { + public Optional<MessageUid> load(Mailbox mailbox, MessageMapper underlying) throws MailboxException { return underlying.getLastUid(mailbox); } } - class HighestModseqCacheWrapper extends MetadataCacheWrapper { + class HighestModseqCacheWrapper extends MetadataCacheWrapper<Long> { public HighestModseqCacheWrapper(Cache<MailboxId, Long> cache) { super(cache); } http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/cassandra/pom.xml ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/pom.xml b/mailbox/cassandra/pom.xml index 5695d41..ddc6948 100644 --- a/mailbox/cassandra/pom.xml +++ b/mailbox/cassandra/pom.xml @@ -246,6 +246,11 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-guava</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java index 105cee8..440ee86 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java @@ -77,6 +77,7 @@ import org.apache.james.backends.cassandra.utils.CassandraUtils; import org.apache.james.backends.cassandra.utils.FunctionRunnerWithRetry; import org.apache.james.mailbox.FlagsBuilder; import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.cassandra.CassandraId; import org.apache.james.mailbox.cassandra.mail.utils.MessageDeletedDuringFlagsUpdateException; import org.apache.james.mailbox.cassandra.table.CassandraMailboxCountersTable; @@ -175,7 +176,7 @@ public class CassandraMessageMapper implements MessageMapper { QueryBuilder.delete() .from(TABLE_NAME) .where(eq(MAILBOX_ID, mailboxId.asUuid())) - .and(eq(IMAP_UID, message.getUid()))); + .and(eq(IMAP_UID, message.getUid().asLong()))); decrementCount(mailboxId); if (!message.isSeen()) { decrementUnseen(mailboxId); @@ -187,7 +188,7 @@ public class CassandraMessageMapper implements MessageMapper { CassandraId mailboxId = (CassandraId) mailbox.getMailboxId(); return CassandraUtils.convertToStream(session.execute(buildSelectQueryWithLimit(buildQuery(mailboxId, set, ftype), max))) .map(row -> message(row, ftype)) - .sorted(Comparator.comparingLong(MailboxMessage::getUid)) + .sorted(Comparator.comparing(MailboxMessage::getUid)) .iterator(); } @@ -199,26 +200,28 @@ public class CassandraMessageMapper implements MessageMapper { } @Override - public List<Long> findRecentMessageUidsInMailbox(Mailbox mailbox) throws MailboxException { + public List<MessageUid> findRecentMessageUidsInMailbox(Mailbox mailbox) throws MailboxException { CassandraId mailboxId = (CassandraId) mailbox.getMailboxId(); return CassandraUtils.convertToStream(session.execute(selectAll(mailboxId, FetchType.Metadata).and((eq(RECENT, true))))) .map((row) -> row.getLong(IMAP_UID)) + .map(MessageUid::of) .sorted() .collect(Collectors.toList()); } @Override - public Long findFirstUnseenMessageUid(Mailbox mailbox) throws MailboxException { + public MessageUid findFirstUnseenMessageUid(Mailbox mailbox) throws MailboxException { CassandraId mailboxId = (CassandraId) mailbox.getMailboxId(); return CassandraUtils.convertToStream(session.execute(selectAll(mailboxId, FetchType.Metadata).and((eq(SEEN, false))))) .map((row) -> row.getLong(IMAP_UID)) + .map(MessageUid::of) .sorted() .findFirst() .orElse(null); } @Override - public Map<Long, MessageMetaData> expungeMarkedForDeletionInMailbox(Mailbox mailbox, MessageRange set) throws MailboxException { + public Map<MessageUid, MessageMetaData> expungeMarkedForDeletionInMailbox(Mailbox mailbox, MessageRange set) throws MailboxException { CassandraId mailboxId = (CassandraId) mailbox.getMailboxId(); return CassandraUtils.convertToStream(session.execute(buildQuery(mailboxId, set, FetchType.Metadata).and(eq(DELETED, true)))) .map(row -> message(row, FetchType.Metadata)) @@ -280,7 +283,7 @@ public class CassandraMessageMapper implements MessageMapper { } @Override - public long getLastUid(Mailbox mailbox) throws MailboxException { + public com.google.common.base.Optional<MessageUid> getLastUid(Mailbox mailbox) throws MailboxException { return uidProvider.lastUid(mailboxSession, mailbox); } @@ -315,7 +318,7 @@ public class CassandraMessageMapper implements MessageMapper { getPropertyBuilder(row), CassandraId.of(row.getUUID(MAILBOX_ID)), getAttachments(row, fetchType)); - message.setUid(row.getLong(IMAP_UID)); + message.setUid(MessageUid.of(row.getLong(IMAP_UID))); message.setModSeq(row.getLong(MOD_SEQ)); return message; } @@ -386,7 +389,7 @@ public class CassandraMessageMapper implements MessageMapper { CassandraId mailboxId = (CassandraId) mailbox.getMailboxId(); session.execute(insertInto(TABLE_NAME) .value(MAILBOX_ID, mailboxId.asUuid()) - .value(IMAP_UID, message.getUid()) + .value(IMAP_UID, message.getUid().asLong()) .value(MOD_SEQ, message.getModSeq()) .value(INTERNAL_DATE, message.getInternalDate()) .value(BODY_START_OCTET, message.getFullContentOctets() - message.getBodyOctets()) @@ -446,7 +449,7 @@ public class CassandraMessageMapper implements MessageMapper { private Optional<UpdatedFlags> updateFlagsOnMessage(Mailbox mailbox, FlagsUpdateCalculator flagUpdateCalculator, Row row) { return tryMessageFlagsUpdate(flagUpdateCalculator, mailbox, message(row, FetchType.Metadata)) .map(Optional::of) - .orElse(handleRetries(mailbox, flagUpdateCalculator, row.getLong(IMAP_UID))); + .orElse(handleRetries(mailbox, flagUpdateCalculator, MessageUid.of(row.getLong(IMAP_UID)))); } private Optional<UpdatedFlags> tryMessageFlagsUpdate(FlagsUpdateCalculator flagUpdateCalculator, Mailbox mailbox, MailboxMessage message) { @@ -466,7 +469,7 @@ public class CassandraMessageMapper implements MessageMapper { } } - private Optional<UpdatedFlags> handleRetries(Mailbox mailbox, FlagsUpdateCalculator flagUpdateCalculator, long uid) { + private Optional<UpdatedFlags> handleRetries(Mailbox mailbox, FlagsUpdateCalculator flagUpdateCalculator, MessageUid uid) { try { return Optional.of( new FunctionRunnerWithRetry(maxRetries) @@ -479,7 +482,7 @@ public class CassandraMessageMapper implements MessageMapper { } } - private Optional<UpdatedFlags> retryMessageFlagsUpdate(Mailbox mailbox, long uid, FlagsUpdateCalculator flagUpdateCalculator) { + private Optional<UpdatedFlags> retryMessageFlagsUpdate(Mailbox mailbox, MessageUid uid, FlagsUpdateCalculator flagUpdateCalculator) { CassandraId mailboxId = (CassandraId) mailbox.getMailboxId(); return tryMessageFlagsUpdate(flagUpdateCalculator, mailbox, @@ -501,7 +504,7 @@ public class CassandraMessageMapper implements MessageMapper { .and(set(USER, message.createFlags().contains(Flag.USER))) .and(set(USER_FLAGS, userFlagsSet(message))) .and(set(MOD_SEQ, message.getModSeq())) - .where(eq(IMAP_UID, message.getUid())) + .where(eq(IMAP_UID, message.getUid().asLong())) .and(eq(MAILBOX_ID, mailboxId.asUuid())) .onlyIf(eq(MOD_SEQ, oldModSeq))); return resultSet.one().getBool(CassandraConstants.LIGHTWEIGHT_TRANSACTION_APPLIED); @@ -531,26 +534,26 @@ public class CassandraMessageMapper implements MessageMapper { .where(eq(MAILBOX_ID, mailboxId.asUuid())); } - private Where selectFrom(CassandraId mailboxId, long uid, FetchType fetchType) { + private Where selectFrom(CassandraId mailboxId, MessageUid uid, FetchType fetchType) { return select(retrieveFields(fetchType)) .from(TABLE_NAME) .where(eq(MAILBOX_ID, mailboxId.asUuid())) - .and(gte(IMAP_UID, uid)); + .and(gte(IMAP_UID, uid.asLong())); } - private Where selectRange(CassandraId mailboxId, long from, long to, FetchType fetchType) { + private Where selectRange(CassandraId mailboxId, MessageUid from, MessageUid to, FetchType fetchType) { return select(retrieveFields(fetchType)) .from(TABLE_NAME) .where(eq(MAILBOX_ID, mailboxId.asUuid())) - .and(gte(IMAP_UID, from)) - .and(lte(IMAP_UID, to)); + .and(gte(IMAP_UID, from.asLong())) + .and(lte(IMAP_UID, to.asLong())); } - private Where selectMessage(CassandraId mailboxId, long uid, FetchType fetchType) { + private Where selectMessage(CassandraId mailboxId, MessageUid uid, FetchType fetchType) { return select(retrieveFields(fetchType)) .from(TABLE_NAME) .where(eq(MAILBOX_ID, mailboxId.asUuid())) - .and(eq(IMAP_UID, uid)); + .and(eq(IMAP_UID, uid.asLong())); } private String[] retrieveFields(FetchType fetchType) { http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java index e41609e..febdd71 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraUidProvider.java @@ -34,6 +34,7 @@ import org.apache.james.backends.cassandra.utils.CassandraConstants; import org.apache.james.backends.cassandra.utils.FunctionRunnerWithRetry; import org.apache.james.backends.cassandra.utils.LightweightTransactionException; import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.cassandra.CassandraId; import org.apache.james.mailbox.cassandra.table.CassandraMessageUidTable; import org.apache.james.mailbox.exception.MailboxException; @@ -50,7 +51,6 @@ import com.google.common.base.Throwables; public class CassandraUidProvider implements UidProvider { public final static int DEFAULT_MAX_RETRY = 100000; private static final Logger LOG = LoggerFactory.getLogger(CassandraUidProvider.class); - private static final Uid FIRST_UID = new Uid(0); private final Session session; private final FunctionRunnerWithRetry runner; @@ -66,12 +66,12 @@ public class CassandraUidProvider implements UidProvider { } @Override - public long nextUid(MailboxSession mailboxSession, Mailbox mailbox) throws MailboxException { + public MessageUid nextUid(MailboxSession mailboxSession, Mailbox mailbox) throws MailboxException { CassandraId mailboxId = (CassandraId) mailbox.getMailboxId(); - if (findHighestUid(mailboxId).isFirst()) { - Optional<Uid> optional = tryInsertUid(mailboxId, FIRST_UID); + if (! findHighestUid(mailboxId).isPresent()) { + Optional<MessageUid> optional = tryInsertUid(mailboxId, Optional.empty()); if (optional.isPresent()) { - return optional.get().getValue(); + return optional.get(); } } @@ -79,8 +79,7 @@ public class CassandraUidProvider implements UidProvider { return runner.executeAndRetrieveObject( () -> { try { - return tryUpdateUid(mailboxId, findHighestUid(mailboxId)) - .map(Uid::getValue); + return tryUpdateUid(mailboxId, findHighestUid(mailboxId)); } catch (Exception exception) { LOG.error("Can not retrieve next Uid", exception); throw Throwables.propagate(exception); @@ -92,66 +91,53 @@ public class CassandraUidProvider implements UidProvider { } @Override - public long lastUid(MailboxSession mailboxSession, Mailbox mailbox) throws MailboxException { - return findHighestUid((CassandraId) mailbox.getMailboxId()).getValue(); + public com.google.common.base.Optional<MessageUid> lastUid(MailboxSession mailboxSession, Mailbox mailbox) throws MailboxException { + return findHighestUid((CassandraId) mailbox.getMailboxId()); } - private Uid findHighestUid(CassandraId mailboxId) throws MailboxException { + private com.google.common.base.Optional<MessageUid> findHighestUid(CassandraId mailboxId) throws MailboxException { ResultSet result = session.execute( select(NEXT_UID) .from(CassandraMessageUidTable.TABLE_NAME) .where(eq(CassandraMessageUidTable.MAILBOX_ID, mailboxId.asUuid()))); if (result.isExhausted()) { - return FIRST_UID; + return com.google.common.base.Optional.absent(); } else { - return new Uid(result.one().getLong(NEXT_UID)); + return com.google.common.base.Optional.of(MessageUid.of(result.one().getLong(NEXT_UID))); } } - private Optional<Uid> tryInsertUid(CassandraId mailboxId, Uid uid) { - Uid nextUid = uid.next(); + private Optional<MessageUid> tryInsertUid(CassandraId mailboxId, Optional<MessageUid> uid) { + MessageUid nextUid = uid.map(MessageUid::next).orElse(MessageUid.MIN_VALUE); return transactionalStatementToOptionalUid(nextUid, insertInto(CassandraMessageUidTable.TABLE_NAME) - .value(NEXT_UID, nextUid.getValue()) + .value(NEXT_UID, nextUid.asLong()) .value(CassandraMessageUidTable.MAILBOX_ID, mailboxId.asUuid()) .ifNotExists()); } - private Optional<Uid> tryUpdateUid(CassandraId mailboxId, Uid uid) { - Uid nextUid = uid.next(); - return transactionalStatementToOptionalUid(nextUid, - update(CassandraMessageUidTable.TABLE_NAME) - .onlyIf(eq(NEXT_UID, uid.getValue())) - .with(set(NEXT_UID, nextUid.getValue())) - .where(eq(CassandraMessageUidTable.MAILBOX_ID, mailboxId.asUuid()))); + private Optional<MessageUid> tryUpdateUid(CassandraId mailboxId, com.google.common.base.Optional<MessageUid> uid) { + if (uid.isPresent()) { + MessageUid nextUid = uid.get().next(); + return transactionalStatementToOptionalUid(nextUid, + update(CassandraMessageUidTable.TABLE_NAME) + .onlyIf(eq(NEXT_UID, uid.get().asLong())) + .with(set(NEXT_UID, nextUid.asLong())) + .where(eq(CassandraMessageUidTable.MAILBOX_ID, mailboxId.asUuid()))); + } else { + return transactionalStatementToOptionalUid(MessageUid.MIN_VALUE, + update(CassandraMessageUidTable.TABLE_NAME) + .onlyIf(eq(NEXT_UID, null)) + .with(set(NEXT_UID, MessageUid.MIN_VALUE.asLong())) + .where(eq(CassandraMessageUidTable.MAILBOX_ID, mailboxId.asUuid()))); + } } - private Optional<Uid> transactionalStatementToOptionalUid(Uid uid, BuiltStatement statement) { + private Optional<MessageUid> transactionalStatementToOptionalUid(MessageUid uid, BuiltStatement statement) { if(session.execute(statement).one().getBool(CassandraConstants.LIGHTWEIGHT_TRANSACTION_APPLIED)) { return Optional.of(uid); } return Optional.empty(); } - private static class Uid { - - private final long value; - - public Uid(long value) { - this.value = value; - } - - public Uid next() { - return new Uid(value + 1); - } - - public long getValue() { - return value; - } - - public boolean isFirst() { - return value == FIRST_UID.value; - } - } - } http://git-wip-us.apache.org/repos/asf/james-project/blob/34242a5b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/MessageDeletedDuringFlagsUpdateException.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/MessageDeletedDuringFlagsUpdateException.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/MessageDeletedDuringFlagsUpdateException.java index c8c4651..d34b556 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/MessageDeletedDuringFlagsUpdateException.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/utils/MessageDeletedDuringFlagsUpdateException.java @@ -19,11 +19,12 @@ package org.apache.james.mailbox.cassandra.mail.utils; +import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.cassandra.CassandraId; public class MessageDeletedDuringFlagsUpdateException extends RuntimeException { - public MessageDeletedDuringFlagsUpdateException(CassandraId id, long uid) { + public MessageDeletedDuringFlagsUpdateException(CassandraId id, MessageUid uid) { super("Can not perform flag update as message was deleted for mailbox " + id.serialize() + " and message " + uid); } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
