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]

Reply via email to