This is an automated email from the ASF dual-hosted git repository.
matthieu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push:
new 5e69e0d [Refactoring] use a strong type for IMAP MessageSequenceNumber
5e69e0d is described below
commit 5e69e0dbddbf788f9aee136596aecdcc024c9454
Author: Matthieu Baechler <[email protected]>
AuthorDate: Mon Apr 20 17:23:26 2020 +0200
[Refactoring] use a strong type for IMAP MessageSequenceNumber
---
.../james/imap/api/display/HumanReadableText.java | 5 +-
.../imap/api/message/response/StatusResponse.java | 5 +-
.../james/imap/api/process/SelectedMailbox.java | 9 +-
.../james/imap/encode/ExpungeResponseEncoder.java | 3 +-
.../james/imap/encode/FetchResponseEncoder.java | 5 +-
.../imap/message/response/ExpungeResponse.java | 7 +-
.../james/imap/message/response/FetchResponse.java | 7 +-
.../imap/processor/AbstractMailboxProcessor.java | 56 ++++----
.../imap/processor/AbstractSelectionProcessor.java | 12 +-
.../james/imap/processor/SearchProcessor.java | 7 +-
.../james/imap/processor/StoreProcessor.java | 82 +++++------
.../imap/processor/base/SelectedMailboxImpl.java | 9 +-
.../james/imap/processor/base/UidMsnConverter.java | 7 +-
.../imap/processor/fetch/FetchResponseBuilder.java | 150 ++++++++++-----------
.../MessageSequenceNumber.java} | 43 ++++--
.../mailbox/NullableMessageSequenceNumber.java | 90 +++++++++++++
.../encode/FetchResponseEncoderEnvelopeTest.java | 3 +-
.../FetchResponseEncoderNoExtensionsTest.java | 10 +-
.../imap/encode/FetchResponseEncoderTest.java | 8 +-
.../imap/processor/base/UidMsnConverterTest.java | 8 +-
.../james/mailbox/MessageSequenceNumberTest.java} | 40 ++++--
.../mailbox/NullableMessageSequenceNumberTest.java | 94 +++++++++++++
22 files changed, 455 insertions(+), 205 deletions(-)
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
b/protocols/imap/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
index e231dd6..ac52c7d 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
@@ -24,6 +24,7 @@ import java.util.Arrays;
import javax.mail.Flags;
import org.apache.james.imap.api.ImapConstants;
+import org.apache.james.mailbox.MessageSequenceNumber;
import com.google.common.base.Joiner;
@@ -36,8 +37,8 @@ public class HumanReadableText {
public static final HumanReadableText SELECT = new
HumanReadableText("org.apache.james.imap.SELECT", "completed.");
- public static HumanReadableText unseen(long numberUnseen) {
- return new HumanReadableText("org.apache.james.imap.UNSEEN",
"MailboxMessage " + numberUnseen + " is first unseen");
+ public static HumanReadableText unseen(MessageSequenceNumber numberUnseen)
{
+ return new HumanReadableText("org.apache.james.imap.UNSEEN",
"MailboxMessage " + numberUnseen.asInt() + " is first unseen");
}
public static final HumanReadableText UIDNEXT = new
HumanReadableText("org.apache.james.imap.UIDNEXT", "Predicted next UID");
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/api/message/response/StatusResponse.java
b/protocols/imap/src/main/java/org/apache/james/imap/api/message/response/StatusResponse.java
index 39ecc29..b2307cd 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/api/message/response/StatusResponse.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/api/message/response/StatusResponse.java
@@ -34,6 +34,7 @@ import org.apache.james.imap.api.display.HumanReadableText;
import org.apache.james.imap.api.message.IdRange;
import org.apache.james.imap.api.message.MessageFlags;
import org.apache.james.imap.api.message.UidRange;
+import org.apache.james.mailbox.MessageSequenceNumber;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
import org.apache.james.mailbox.model.UidValidity;
@@ -299,8 +300,8 @@ public interface StatusResponse extends ImapResponseMessage
{
* positive non-zero integer
* @return <code>ResponseCode</code>, not null
*/
- public static ResponseCode unseen(int numberUnseen) {
- return new ResponseCode("UNSEEN", numberUnseen);
+ public static ResponseCode unseen(MessageSequenceNumber numberUnseen) {
+ return new ResponseCode("UNSEEN", numberUnseen.asInt());
}
/**
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java
b/protocols/imap/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java
index c16bdbc..8516109 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java
@@ -25,6 +25,7 @@ import java.util.Optional;
import javax.mail.Flags;
import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.NullableMessageSequenceNumber;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
@@ -42,10 +43,10 @@ public interface SelectedMailbox {
void deselect();
/**
- * Return the msg index of the given uid or {@link #NO_SUCH_MESSAGE} if no
+ * Return the msg index of the given uid or {@link
NullableMessageSequenceNumber#noMessage()} instance if no
* message with the given uid was found
*/
- int msn(MessageUid uid);
+ NullableMessageSequenceNumber msn(MessageUid uid);
/**
* Return the uid of the message for the given index or empty if no
message with the given index was found
@@ -144,10 +145,10 @@ public interface SelectedMailbox {
* @param uid
* not null
* @return the message sequence number that the UID held before or
- * {@link #NO_SUCH_MESSAGE} if no message with the given uid was
+ * {@link NullableMessageSequenceNumber#noMessage()} instance if
no message with the given uid was
* found being expunged
*/
- int remove(MessageUid uid);
+ NullableMessageSequenceNumber remove(MessageUid uid);
/**
* Return a Collection which holds all uids reflecting the Messages which
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/encode/ExpungeResponseEncoder.java
b/protocols/imap/src/main/java/org/apache/james/imap/encode/ExpungeResponseEncoder.java
index 992ee56..49a7c7e 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/encode/ExpungeResponseEncoder.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/encode/ExpungeResponseEncoder.java
@@ -25,6 +25,7 @@ import org.apache.james.imap.message.response.ExpungeResponse;
public class ExpungeResponseEncoder implements
ImapResponseEncoder<ExpungeResponse> {
public static final String EXPUNGE = "EXPUNGE";
+ private static final int NO_MESSAGE = -1;
@Override
public Class<ExpungeResponse> acceptableMessages() {
@@ -33,7 +34,7 @@ public class ExpungeResponseEncoder implements
ImapResponseEncoder<ExpungeRespon
@Override
public void encode(ExpungeResponse expungeResponse, ImapResponseComposer
composer) throws IOException {
- int messageSequenceNumber = expungeResponse.getMessageSequenceNumber();
+ int messageSequenceNumber =
expungeResponse.getMessageSequenceNumber().asInt().orElse(NO_MESSAGE);
composer.untagged().message(messageSequenceNumber).message(EXPUNGE).end();
}
}
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/encode/FetchResponseEncoder.java
b/protocols/imap/src/main/java/org/apache/james/imap/encode/FetchResponseEncoder.java
index 2849cda..9776f16 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/encode/FetchResponseEncoder.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/encode/FetchResponseEncoder.java
@@ -33,6 +33,7 @@ import javax.mail.Flags;
import org.apache.james.imap.api.ImapConstants;
import org.apache.james.imap.message.response.FetchResponse;
import org.apache.james.imap.message.response.FetchResponse.Structure;
+import org.apache.james.mailbox.MessageSequenceNumber;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
import org.slf4j.Logger;
@@ -63,9 +64,9 @@ public class FetchResponseEncoder implements
ImapResponseEncoder<FetchResponse>
@Override
public void encode(FetchResponse fetchResponse, ImapResponseComposer
composer) throws IOException {
- long messageNumber = fetchResponse.getMessageNumber();
+ MessageSequenceNumber messageNumber = fetchResponse.getMessageNumber();
-
composer.untagged().message(messageNumber).message(ImapConstants.FETCH_COMMAND.getName()).openParen();
+
composer.untagged().message(messageNumber.asInt()).message(ImapConstants.FETCH_COMMAND.getName()).openParen();
encodeModSeq(composer, fetchResponse);
encodeFlags(composer, fetchResponse);
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/message/response/ExpungeResponse.java
b/protocols/imap/src/main/java/org/apache/james/imap/message/response/ExpungeResponse.java
index 2d13203..2c46fce 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/message/response/ExpungeResponse.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/message/response/ExpungeResponse.java
@@ -20,16 +20,17 @@
package org.apache.james.imap.message.response;
import org.apache.james.imap.api.message.response.ImapResponseMessage;
+import org.apache.james.mailbox.NullableMessageSequenceNumber;
public final class ExpungeResponse implements ImapResponseMessage {
- private final int messageSequenceNumber;
+ private final NullableMessageSequenceNumber messageSequenceNumber;
- public ExpungeResponse(int messageSequenceNumber) {
+ public ExpungeResponse(NullableMessageSequenceNumber
messageSequenceNumber) {
this.messageSequenceNumber = messageSequenceNumber;
}
- public int getMessageSequenceNumber() {
+ public NullableMessageSequenceNumber getMessageSequenceNumber() {
return messageSequenceNumber;
}
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/message/response/FetchResponse.java
b/protocols/imap/src/main/java/org/apache/james/imap/message/response/FetchResponse.java
index 0d64091..1b5133f 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/message/response/FetchResponse.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/message/response/FetchResponse.java
@@ -26,11 +26,12 @@ import java.util.Map;
import javax.mail.Flags;
import org.apache.james.imap.api.message.response.ImapResponseMessage;
+import org.apache.james.mailbox.MessageSequenceNumber;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
public final class FetchResponse implements ImapResponseMessage {
- private final int messageNumber;
+ private final MessageSequenceNumber messageNumber;
private final Flags flags;
private final MessageUid uid;
private final Date internalDate;
@@ -41,7 +42,7 @@ public final class FetchResponse implements
ImapResponseMessage {
private final Structure bodystructure;
private final ModSeq modSeq;
- public FetchResponse(int messageNumber, Flags flags, MessageUid uid,
ModSeq modSeq, Date internalDate, Long size, Envelope envelope, Structure body,
Structure bodystructure, List<BodyElement> elements) {
+ public FetchResponse(MessageSequenceNumber messageNumber, Flags flags,
MessageUid uid, ModSeq modSeq, Date internalDate, Long size, Envelope envelope,
Structure body, Structure bodystructure, List<BodyElement> elements) {
this.messageNumber = messageNumber;
this.flags = flags;
this.uid = uid;
@@ -79,7 +80,7 @@ public final class FetchResponse implements
ImapResponseMessage {
*
* @return message number
*/
- public int getMessageNumber() {
+ public MessageSequenceNumber getMessageNumber() {
return messageNumber;
}
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
index f094609..8377e05 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
@@ -57,6 +57,7 @@ import org.apache.james.mailbox.MessageManager;
import org.apache.james.mailbox.MessageManager.MetaData;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
+import org.apache.james.mailbox.NullableMessageSequenceNumber;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.MessageRangeException;
import org.apache.james.mailbox.model.FetchGroup;
@@ -178,7 +179,7 @@ public abstract class AbstractMailboxProcessor<R extends
ImapRequest> extends Ab
// we need to remove the message in the loop to the sequence
numbers
// are updated correctly.
// See 7.4.1. EXPUNGE Response
- final int msn = selected.remove(uid);
+ final NullableMessageSequenceNumber msn = selected.remove(uid);
ExpungeResponse response = new ExpungeResponse(msn);
responder.respond(response);
}
@@ -245,37 +246,38 @@ public abstract class AbstractMailboxProcessor<R extends
ImapRequest> extends Ab
while (it.hasNext()) {
MessageResult mr = it.next();
final MessageUid uid = mr.getUid();
- int msn = selected.msn(uid);
- if (msn == SelectedMailbox.NO_SUCH_MESSAGE) {
+ selected.msn(uid).fold(() -> {
LOGGER.debug("No message found with uid {} in the uid<->msn
mapping for mailbox {}. This may be because it was deleted by a concurrent
session. So skip it..", uid, selected.getMailboxId().serialize());
// skip this as it was not found in the mapping
//
// See IMAP-346
- continue;
- }
+ return null;
+ }, msn -> {
- final Flags flags = mr.getFlags();
- final MessageUid uidOut;
- if (useUid || qresyncEnabled) {
- uidOut = uid;
- } else {
- uidOut = null;
- }
- if (selected.isRecent(uid)) {
- flags.add(Flags.Flag.RECENT);
- } else {
- flags.remove(Flags.Flag.RECENT);
- }
- final FetchResponse response;
-
- // Check if we also need to return the MODSEQ in the response.
This is true if CONDSTORE or
- // if QRESYNC was enabled, and the mailbox supports the permant
storage of mod-sequences
- if ((condstoreEnabled || qresyncEnabled) && isModSeqPermanent) {
- response = new FetchResponse(msn, flags, uidOut,
mr.getModSeq(), null, null, null, null, null, null);
- } else {
- response = new FetchResponse(msn, flags, uidOut, null, null,
null, null, null, null, null);
- }
- responder.respond(response);
+ final Flags flags = mr.getFlags();
+ final MessageUid uidOut;
+ if (useUid || qresyncEnabled) {
+ uidOut = uid;
+ } else {
+ uidOut = null;
+ }
+ if (selected.isRecent(uid)) {
+ flags.add(Flags.Flag.RECENT);
+ } else {
+ flags.remove(Flags.Flag.RECENT);
+ }
+ final FetchResponse response;
+
+ // Check if we also need to return the MODSEQ in the response.
This is true if CONDSTORE or
+ // if QRESYNC was enabled, and the mailbox supports the
permant storage of mod-sequences
+ if ((condstoreEnabled || qresyncEnabled) && isModSeqPermanent)
{
+ response = new FetchResponse(msn, flags, uidOut,
mr.getModSeq(), null, null, null, null, null, null);
+ } else {
+ response = new FetchResponse(msn, flags, uidOut, null,
null, null, null, null, null, null);
+ }
+ responder.respond(response);
+ return null;
+ });
}
}
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
index df3f61a..97d9055 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
@@ -349,15 +349,15 @@ abstract class AbstractSelectionProcessor<R extends
AbstractMailboxSelectionRequ
private boolean unseen(Responder responder, MessageUid firstUnseen,
SelectedMailbox selected) throws MailboxException {
if (firstUnseen != null) {
final MessageUid unseenUid = firstUnseen;
- int msn = selected.msn(unseenUid);
- if (msn == SelectedMailbox.NO_SUCH_MESSAGE) {
+ return selected.msn(unseenUid).fold(() -> {
LOGGER.debug("No message found with uid {} in mailbox {}",
unseenUid, selected.getMailboxId().serialize());
return false;
- }
-
- final StatusResponse untaggedOk =
statusResponseFactory.untaggedOk(HumanReadableText.unseen(msn),
ResponseCode.unseen(msn));
- responder.respond(untaggedOk);
+ }, msn -> {
+ final StatusResponse untaggedOk =
statusResponseFactory.untaggedOk(HumanReadableText.unseen(msn),
ResponseCode.unseen(msn));
+ responder.respond(untaggedOk);
+ return true;
+ });
}
return true;
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
b/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
index 80b16ad..91d4ee4 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
@@ -67,6 +67,7 @@ import org.apache.james.util.MDCBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.github.fge.lambdas.Throwing;
import com.github.steveash.guavate.Guavate;
import com.google.common.collect.ImmutableList;
@@ -212,8 +213,10 @@ public class SearchProcessor extends
AbstractMailboxProcessor<SearchRequest> imp
} else {
return uids.stream()
.map(uid -> session.getSelected().msn(uid))
- .map(Integer::longValue)
- .filter(msn -> msn != SelectedMailbox.NO_SUCH_MESSAGE)
+ .flatMap(Throwing.function(nullableMsn ->
+ nullableMsn.fold(
+ Stream::empty,
+ msn ->
Stream.of(Integer.valueOf(msn.asInt()).longValue()))))
.collect(Guavate.toImmutableList());
}
}
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/processor/StoreProcessor.java
b/protocols/imap/src/main/java/org/apache/james/imap/processor/StoreProcessor.java
index 79fe6fa..8c34775 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/processor/StoreProcessor.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/processor/StoreProcessor.java
@@ -49,6 +49,7 @@ import org.apache.james.mailbox.MessageManager;
import org.apache.james.mailbox.MessageManager.MetaData;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
+import org.apache.james.mailbox.NullableMessageSequenceNumber;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.MessageRangeException;
import org.apache.james.mailbox.model.FetchGroup;
@@ -111,7 +112,7 @@ public class StoreProcessor extends
AbstractMailboxProcessor<StoreRequest> {
}
final List<MessageUid> failed = new ArrayList<>();
- List<Long> failedMsns = new ArrayList<>();
+ List<NullableMessageSequenceNumber> failedMsns = new ArrayList<>();
final List<String> userFlags = Arrays.asList(flags.getUserFlags());
for (IdRange range : idSet) {
final SelectedMailbox selected = session.getSelected();
@@ -157,7 +158,7 @@ public class StoreProcessor extends
AbstractMailboxProcessor<StoreRequest> {
if (useUids) {
failed.add(uid);
} else {
- failedMsns.add((long)selected.msn(uid));
+ failedMsns.add(selected.msn(uid));
}
}
}
@@ -198,8 +199,8 @@ public class StoreProcessor extends
AbstractMailboxProcessor<StoreRequest> {
responder.respond(response);
} else {
List<IdRange> ranges = new ArrayList<>();
- for (long msn: failedMsns) {
- ranges.add(new IdRange(msn));
+ for (NullableMessageSequenceNumber msn: failedMsns) {
+ msn.ifPresent(id -> ranges.add(new
IdRange(id.asInt())));
}
IdRange[] failedRanges =
IdRange.mergeRanges(ranges).toArray(IdRange[]::new);
// See RFC4551 3.2. STORE and UID STORE Commands
@@ -264,50 +265,51 @@ public class StoreProcessor extends
AbstractMailboxProcessor<StoreRequest> {
for (Map.Entry<MessageUid, Flags> entry : flagsByUid.entrySet()) {
final MessageUid uid = entry.getKey();
- final int msn = selected.msn(uid);
- if (msn == SelectedMailbox.NO_SUCH_MESSAGE) {
+ selected.msn(uid).fold(() -> {
LOGGER.debug("No message found with uid {} in the
uid<->msn mapping for mailbox {}. This may be because it was deleted by a
concurrent session. So skip it..", uid, selected.getPath().asString());
// skip this as it was not found in the mapping
//
// See IMAP-346
- continue;
- }
+ return null;
+ }, msn -> {
- final Flags resultFlags = entry.getValue();
- final MessageUid resultUid;
-
- // Check if we need to include the uid. T
- //
- // This is the case if one of these is true:
- // - FETCH (UID...) was used
- // - QRESYNC was enabled via ENABLE QRESYNC
- if (useUids || qresyncEnabled) {
- resultUid = uid;
- } else {
- resultUid = null;
- }
+ final Flags resultFlags = entry.getValue();
+ final MessageUid resultUid;
- if (selected.isRecent(uid)) {
- resultFlags.add(Flags.Flag.RECENT);
- }
-
- final FetchResponse response;
- // For more information related to the FETCH response see
- //
- // RFC4551 3.2. STORE and UID STORE Commands
- if (silent && (unchangedSince != -1 || qresyncEnabled ||
condstoreEnabled)) {
- // We need to return an FETCH response which contains the
mod-sequence of the message even if FLAGS.SILENT was used
- response = new FetchResponse(msn, null, resultUid,
modSeqs.get(uid), null, null, null, null, null, null);
- } else if (!silent && (unchangedSince != -1 || qresyncEnabled
|| condstoreEnabled)) {
+ // Check if we need to include the uid. T
//
- // Use a FETCH response which contains the mod-sequence
and the flags
- response = new FetchResponse(msn, resultFlags, resultUid,
modSeqs.get(uid), null, null, null, null, null, null);
- } else {
- // Use a FETCH response which only contains the flags as
no CONDSTORE was used
- response = new FetchResponse(msn, resultFlags, resultUid,
null, null, null, null, null, null, null);
- }
- responder.respond(response);
+ // This is the case if one of these is true:
+ // - FETCH (UID...) was used
+ // - QRESYNC was enabled via ENABLE QRESYNC
+ if (useUids || qresyncEnabled) {
+ resultUid = uid;
+ } else {
+ resultUid = null;
+ }
+
+ if (selected.isRecent(uid)) {
+ resultFlags.add(Flags.Flag.RECENT);
+ }
+
+ final FetchResponse response;
+ // For more information related to the FETCH response see
+ //
+ // RFC4551 3.2. STORE and UID STORE Commands
+ if (silent && (unchangedSince != -1 || qresyncEnabled ||
condstoreEnabled)) {
+ // We need to return an FETCH response which contains
the mod-sequence of the message even if FLAGS.SILENT was used
+ response = new FetchResponse(msn, null, resultUid,
modSeqs.get(uid), null, null, null, null, null, null);
+ } else if (!silent && (unchangedSince != -1 ||
qresyncEnabled || condstoreEnabled)) {
+ //
+ // Use a FETCH response which contains the
mod-sequence and the flags
+ response = new FetchResponse(msn, resultFlags,
resultUid, modSeqs.get(uid), null, null, null, null, null, null);
+ } else {
+ // Use a FETCH response which only contains the flags
as no CONDSTORE was used
+ response = new FetchResponse(msn, resultFlags,
resultUid, null, null, null, null, null, null, null);
+ }
+ responder.respond(response);
+ return null;
+ });
}
if (unchangedSince != -1) {
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
index a8ca86f..1aef2bf 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
@@ -38,6 +38,7 @@ import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageManager;
import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.NullableMessageSequenceNumber;
import org.apache.james.mailbox.events.Event;
import org.apache.james.mailbox.events.EventBus;
import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
@@ -183,8 +184,8 @@ public class SelectedMailboxImpl implements
SelectedMailbox, MailboxListener {
}
@Override
- public synchronized int remove(MessageUid uid) {
- final int result = msn(uid);
+ public synchronized NullableMessageSequenceNumber remove(MessageUid uid) {
+ NullableMessageSequenceNumber result = msn(uid);
uidMsnConverter.remove(uid);
return result;
}
@@ -391,8 +392,8 @@ public class SelectedMailboxImpl implements
SelectedMailbox, MailboxListener {
}
@Override
- public synchronized int msn(MessageUid uid) {
- return uidMsnConverter.getMsn(uid).orElse(NO_SUCH_MESSAGE);
+ public synchronized NullableMessageSequenceNumber msn(MessageUid uid) {
+ return uidMsnConverter.getMsn(uid);
}
@Override
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java
b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java
index ff56229..fc7b114 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java
@@ -26,6 +26,7 @@ import java.util.Optional;
import java.util.TreeSet;
import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.NullableMessageSequenceNumber;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
@@ -48,12 +49,12 @@ public class UidMsnConverter {
uids.addAll(tmp);
}
- public synchronized Optional<Integer> getMsn(MessageUid uid) {
+ public synchronized NullableMessageSequenceNumber getMsn(MessageUid uid) {
int position = Collections.binarySearch(uids, uid);
if (position < 0) {
- return Optional.empty();
+ return NullableMessageSequenceNumber.noMessage();
}
- return Optional.of(position + 1);
+ return NullableMessageSequenceNumber.of(position + 1);
}
public synchronized Optional<MessageUid> getUid(int msn) {
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java
b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java
index 40cd7f6..4229b5e 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java
+++
b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java
@@ -41,6 +41,7 @@ import org.apache.james.imap.api.process.SelectedMailbox;
import org.apache.james.imap.message.response.FetchResponse;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.MessageSequenceNumber;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
import org.apache.james.mailbox.exception.MailboxException;
@@ -55,7 +56,7 @@ public final class FetchResponseBuilder {
private final EnvelopeBuilder envelopeBuilder;
- private int msn;
+ private MessageSequenceNumber msn;
private MessageUid uid;
@@ -80,7 +81,7 @@ public final class FetchResponseBuilder {
this.envelopeBuilder = envelopeBuilder;
}
- public void reset(int msn) {
+ public void reset(MessageSequenceNumber msn) {
this.msn = msn;
uid = null;
flags = null;
@@ -112,95 +113,94 @@ public final class FetchResponseBuilder {
public FetchResponse build(FetchData fetch, MessageResult result,
MessageManager mailbox, ImapSession session, boolean useUids) throws
MessageRangeException, MailboxException {
final SelectedMailbox selected = session.getSelected();
final MessageUid resultUid = result.getUid();
- final int resultMsn = selected.msn(resultUid);
-
- if (resultMsn == SelectedMailbox.NO_SUCH_MESSAGE) {
+ return selected.msn(resultUid).fold(() -> {
throw new MessageRangeException("No such message found with uid "
+ resultUid);
- }
+ }, msn -> {
+
+ reset(msn);
+ // setMsn(resultMsn);
+
+ // Check if this fetch will cause the "SEEN" flag to be set on this
+ // message. If so, update the flags, and ensure that a flags
response is
+ // included in the response.
+ final MailboxSession mailboxSession = session.getMailboxSession();
+ boolean ensureFlagsResponse = false;
+ final Flags resultFlags = result.getFlags();
+ if (fetch.isSetSeen() && !resultFlags.contains(Flags.Flag.SEEN)) {
+ mailbox.setFlags(new Flags(Flags.Flag.SEEN),
MessageManager.FlagsUpdateMode.ADD, MessageRange.one(resultUid),
mailboxSession);
+ resultFlags.add(Flags.Flag.SEEN);
+ ensureFlagsResponse = true;
+ }
- reset(resultMsn);
- // setMsn(resultMsn);
-
- // Check if this fetch will cause the "SEEN" flag to be set on this
- // message. If so, update the flags, and ensure that a flags response
is
- // included in the response.
- final MailboxSession mailboxSession = session.getMailboxSession();
- boolean ensureFlagsResponse = false;
- final Flags resultFlags = result.getFlags();
- if (fetch.isSetSeen() && !resultFlags.contains(Flags.Flag.SEEN)) {
- mailbox.setFlags(new Flags(Flags.Flag.SEEN),
MessageManager.FlagsUpdateMode.ADD, MessageRange.one(resultUid),
mailboxSession);
- resultFlags.add(Flags.Flag.SEEN);
- ensureFlagsResponse = true;
- }
+ // FLAGS response
+ if (fetch.contains(Item.FLAGS) || ensureFlagsResponse) {
+ if (selected.isRecent(resultUid)) {
+ resultFlags.add(Flags.Flag.RECENT);
+ }
+ setFlags(resultFlags);
+ }
- // FLAGS response
- if (fetch.contains(Item.FLAGS) || ensureFlagsResponse) {
- if (selected.isRecent(resultUid)) {
- resultFlags.add(Flags.Flag.RECENT);
+ // INTERNALDATE response
+ if (fetch.contains(Item.INTERNAL_DATE)) {
+ setInternalDate(result.getInternalDate());
}
- setFlags(resultFlags);
- }
- // INTERNALDATE response
- if (fetch.contains(Item.INTERNAL_DATE)) {
- setInternalDate(result.getInternalDate());
- }
+ // RFC822.SIZE response
+ if (fetch.contains(Item.SIZE)) {
+ setSize(result.getSize());
+ }
- // RFC822.SIZE response
- if (fetch.contains(Item.SIZE)) {
- setSize(result.getSize());
- }
+ if (fetch.contains(Item.ENVELOPE)) {
+ this.envelope = buildEnvelope(result);
+ }
- if (fetch.contains(Item.ENVELOPE)) {
- this.envelope = buildEnvelope(result);
- }
+ // BODY part responses.
+ Collection<BodyFetchElement> elements = fetch.getBodyElements();
+ this.elements = new ArrayList<>();
+ for (BodyFetchElement fetchElement : elements) {
+ final FetchResponse.BodyElement element = bodyFetch(result,
fetchElement);
+ if (element != null) {
+ this.elements.add(element);
+ }
+ }
+
+ // Only create when needed
+ if (fetch.contains(Item.BODY) ||
fetch.contains(Item.BODY_STRUCTURE)) {
+ // BODY response
+ //
+ // the STRUCTURE is only needed when no specific element is
requested otherwise we don't need
+ // to access it and may be able to not parse the message
+ //
+ // See IMAP-333
+ if (fetch.contains(Item.BODY) && this.elements.isEmpty()) {
+ body = new MimeDescriptorStructure(false,
result.getMimeDescriptor(), envelopeBuilder);
+ }
- // BODY part responses.
- Collection<BodyFetchElement> elements = fetch.getBodyElements();
- this.elements = new ArrayList<>();
- for (BodyFetchElement fetchElement : elements) {
- final FetchResponse.BodyElement element = bodyFetch(result,
fetchElement);
- if (element != null) {
- this.elements.add(element);
+ // BODYSTRUCTURE response
+ if (fetch.contains(Item.BODY_STRUCTURE)) {
+ bodystructure = new MimeDescriptorStructure(true,
result.getMimeDescriptor(), envelopeBuilder);
+ }
}
- }
-
- // Only create when needed
- if (fetch.contains(Item.BODY) || fetch.contains(Item.BODY_STRUCTURE)) {
- // BODY response
- //
- // the STRUCTURE is only needed when no specific element is
requested otherwise we don't need
- // to access it and may be able to not parse the message
- //
- // See IMAP-333
- if (fetch.contains(Item.BODY) && this.elements.isEmpty()) {
- body = new MimeDescriptorStructure(false,
result.getMimeDescriptor(), envelopeBuilder);
+ // UID response
+ if (fetch.contains(Item.UID)) {
+ setUid(resultUid);
}
- // BODYSTRUCTURE response
- if (fetch.contains(Item.BODY_STRUCTURE)) {
- bodystructure = new MimeDescriptorStructure(true,
result.getMimeDescriptor(), envelopeBuilder);
- }
- }
- // UID response
- if (fetch.contains(Item.UID)) {
- setUid(resultUid);
- }
-
- if (fetch.contains(Item.MODSEQ)) {
- long changedSince = fetch.getChangedSince();
- if (changedSince != -1) {
- // check if the modsequence if higher then the one specified
by the CHANGEDSINCE option
- if (changedSince < result.getModSeq().asLong()) {
+ if (fetch.contains(Item.MODSEQ)) {
+ long changedSince = fetch.getChangedSince();
+ if (changedSince != -1) {
+ // check if the modsequence if higher then the one
specified by the CHANGEDSINCE option
+ if (changedSince < result.getModSeq().asLong()) {
+ setModSeq(result.getModSeq());
+ }
+ } else {
setModSeq(result.getModSeq());
}
- } else {
- setModSeq(result.getModSeq());
}
- }
- return build();
+ return build();
+ });
}
private FetchResponse.Envelope buildEnvelope(MessageResult result) throws
MailboxException {
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/message/response/ExpungeResponse.java
b/protocols/imap/src/main/java/org/apache/james/mailbox/MessageSequenceNumber.java
similarity index 56%
copy from
protocols/imap/src/main/java/org/apache/james/imap/message/response/ExpungeResponse.java
copy to
protocols/imap/src/main/java/org/apache/james/mailbox/MessageSequenceNumber.java
index 2d13203..df1c829 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/message/response/ExpungeResponse.java
+++
b/protocols/imap/src/main/java/org/apache/james/mailbox/MessageSequenceNumber.java
@@ -17,23 +17,48 @@
* under the License. *
****************************************************************/
-package org.apache.james.imap.message.response;
+package org.apache.james.mailbox;
-import org.apache.james.imap.api.message.response.ImapResponseMessage;
+import java.util.Objects;
-public final class ExpungeResponse implements ImapResponseMessage {
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
- private final int messageSequenceNumber;
+public final class MessageSequenceNumber {
- public ExpungeResponse(int messageSequenceNumber) {
- this.messageSequenceNumber = messageSequenceNumber;
+ public static MessageSequenceNumber of(int msn) {
+ Preconditions.checkArgument(msn >= 0);
+ return new MessageSequenceNumber(msn);
}
- public int getMessageSequenceNumber() {
- return messageSequenceNumber;
+ private final int msn;
+
+ private MessageSequenceNumber(int msn) {
+ this.msn = msn;
+ }
+
+ public int asInt() {
+ return msn;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof MessageSequenceNumber) {
+ MessageSequenceNumber that = (MessageSequenceNumber) o;
+ return Objects.equals(msn, that.msn);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(msn);
}
+ @Override
public String toString() {
- return "EXPUNGE " + messageSequenceNumber;
+ return MoreObjects.toStringHelper(this)
+ .add("msn", msn)
+ .toString();
}
}
diff --git
a/protocols/imap/src/main/java/org/apache/james/mailbox/NullableMessageSequenceNumber.java
b/protocols/imap/src/main/java/org/apache/james/mailbox/NullableMessageSequenceNumber.java
new file mode 100644
index 0000000..75d51bd
--- /dev/null
+++
b/protocols/imap/src/main/java/org/apache/james/mailbox/NullableMessageSequenceNumber.java
@@ -0,0 +1,90 @@
+/****************************************************************
+ * 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 java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+import org.apache.james.mailbox.exception.MailboxException;
+
+import com.google.common.base.MoreObjects;
+
+public final class NullableMessageSequenceNumber {
+
+ public interface HandleNoMessage<T> {
+ T handle() throws MailboxException;
+ }
+
+ public interface HandleMessage<T> {
+ T handle(MessageSequenceNumber sequenceNumber) throws MailboxException;
+ }
+
+ public static NullableMessageSequenceNumber noMessage() {
+ return new NullableMessageSequenceNumber(Optional.empty());
+ }
+
+ public static NullableMessageSequenceNumber of(int msn) {
+ return new
NullableMessageSequenceNumber(Optional.of(MessageSequenceNumber.of(msn)));
+ }
+
+ private final Optional<MessageSequenceNumber> msn;
+
+ private NullableMessageSequenceNumber(Optional<MessageSequenceNumber> msn)
{
+ this.msn = msn;
+ }
+
+ public void ifPresent(Consumer<MessageSequenceNumber> consumer) {
+ msn.ifPresent(consumer);
+ }
+
+ public <T> T fold(HandleNoMessage<T> handleNoMessage, HandleMessage<T>
handleMessage) throws MailboxException {
+ if (msn.isPresent()) {
+ return handleMessage.handle(msn.get());
+ } else {
+ return handleNoMessage.handle();
+ }
+ }
+
+ public Optional<Integer> asInt() {
+ return msn.map(MessageSequenceNumber::asInt);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof NullableMessageSequenceNumber) {
+ NullableMessageSequenceNumber that =
(NullableMessageSequenceNumber) o;
+ return Objects.equals(msn, that.msn);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(msn);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("msn", msn)
+ .toString();
+ }
+}
diff --git
a/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderEnvelopeTest.java
b/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderEnvelopeTest.java
index 340b8ce..281afc6 100644
---
a/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderEnvelopeTest.java
+++
b/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderEnvelopeTest.java
@@ -27,6 +27,7 @@ import
org.apache.james.imap.encode.base.ByteImapResponseWriter;
import org.apache.james.imap.encode.base.ImapResponseComposerImpl;
import org.apache.james.imap.message.response.FetchResponse;
import org.apache.james.imap.message.response.FetchResponse.Envelope.Address;
+import org.apache.james.mailbox.MessageSequenceNumber;
import org.junit.Before;
import org.junit.Test;
@@ -49,7 +50,7 @@ public class FetchResponseEncoderEnvelopeTest {
private static final String ADDRESS_TWO_NAME = "2NAME";
- private static final int MSN = 100;
+ private static final MessageSequenceNumber MSN =
MessageSequenceNumber.of(100);
private FetchResponseEncoder encoder;
diff --git
a/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderNoExtensionsTest.java
b/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderNoExtensionsTest.java
index a805a9c..40face7 100644
---
a/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderNoExtensionsTest.java
+++
b/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderNoExtensionsTest.java
@@ -33,11 +33,13 @@ import javax.mail.Flags;
import org.apache.james.imap.encode.base.ByteImapResponseWriter;
import org.apache.james.imap.encode.base.ImapResponseComposerImpl;
import org.apache.james.imap.message.response.FetchResponse;
+import org.apache.james.mailbox.MessageSequenceNumber;
import org.apache.james.mailbox.MessageUid;
import org.junit.Before;
import org.junit.Test;
public class FetchResponseEncoderNoExtensionsTest {
+ private static final MessageSequenceNumber MSN =
MessageSequenceNumber.of(100);
private ByteImapResponseWriter writer = new ByteImapResponseWriter();
private ImapResponseComposer composer = new
ImapResponseComposerImpl(writer);
private Flags flags;
@@ -55,7 +57,7 @@ public class FetchResponseEncoderNoExtensionsTest {
@Test
public void testShouldEncodeFlagsResponse() throws Exception {
- FetchResponse message = new FetchResponse(100, flags, null, null,
null, null,
+ FetchResponse message = new FetchResponse(MSN, flags, null, null,
null, null,
null, null, null, null);
encoder.encode(message, composer);
assertThat(writer.getString()).isEqualTo("* 100 FETCH (FLAGS
(\\Deleted))\r\n");
@@ -63,7 +65,7 @@ public class FetchResponseEncoderNoExtensionsTest {
@Test
public void testShouldEncodeUidResponse() throws Exception {
- FetchResponse message = new FetchResponse(100, null,
MessageUid.of(72), null,
+ FetchResponse message = new FetchResponse(MSN, null,
MessageUid.of(72), null,
null, null, null, null, null, null);
encoder.encode(message, composer);
assertThat(writer.getString()).isEqualTo("* 100 FETCH (UID 72)\r\n");
@@ -72,7 +74,7 @@ public class FetchResponseEncoderNoExtensionsTest {
@Test
public void testShouldEncodeAllResponse() throws Exception {
- FetchResponse message = new FetchResponse(100, flags,
MessageUid.of(72), null,
+ FetchResponse message = new FetchResponse(MSN, flags,
MessageUid.of(72), null,
null, null, null, null, null, null);
encoder.encode(message, composer);
assertThat(writer.getString()).isEqualTo("* 100 FETCH (FLAGS
(\\Deleted) UID 72)\r\n");
@@ -81,7 +83,7 @@ public class FetchResponseEncoderNoExtensionsTest {
@Test
public void testShouldNotAddExtensionsWithEncodingBodyStructure() throws
Exception {
- FetchResponse message = new FetchResponse(100, flags,
MessageUid.of(72), null,
+ FetchResponse message = new FetchResponse(MSN, flags,
MessageUid.of(72), null,
null, null, null, null, stubStructure, null);
final Map<String, String> parameters = new HashMap<>();
parameters.put("CHARSET", "US-ASCII");
diff --git
a/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderTest.java
b/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderTest.java
index 3a56fb6..5447cd0 100644
---
a/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderTest.java
+++
b/protocols/imap/src/test/java/org/apache/james/imap/encode/FetchResponseEncoderTest.java
@@ -26,11 +26,13 @@ import javax.mail.Flags;
import org.apache.james.imap.encode.base.ByteImapResponseWriter;
import org.apache.james.imap.encode.base.ImapResponseComposerImpl;
import org.apache.james.imap.message.response.FetchResponse;
+import org.apache.james.mailbox.MessageSequenceNumber;
import org.apache.james.mailbox.MessageUid;
import org.junit.Before;
import org.junit.Test;
public class FetchResponseEncoderTest {
+ private static final MessageSequenceNumber MSN =
MessageSequenceNumber.of(100);
private ByteImapResponseWriter writer = new ByteImapResponseWriter();
private ImapResponseComposer composer = new
ImapResponseComposerImpl(writer);
private Flags flags;
@@ -49,7 +51,7 @@ public class FetchResponseEncoderTest {
@Test
public void testShouldEncodeFlagsResponse() throws Exception {
- FetchResponse message = new FetchResponse(100, flags, null, null,
null, null,
+ FetchResponse message = new FetchResponse(MSN, flags, null, null,
null, null,
null, null, null, null);
encoder.encode(message, composer);
assertThat(writer.getString()).isEqualTo("* 100 FETCH (FLAGS
(\\Deleted))\r\n");
@@ -59,7 +61,7 @@ public class FetchResponseEncoderTest {
@Test
public void testShouldEncodeUidResponse() throws Exception {
- FetchResponse message = new FetchResponse(100, null,
MessageUid.of(72), null,
+ FetchResponse message = new FetchResponse(MSN, null,
MessageUid.of(72), null,
null, null, null, null, null, null);
encoder.encode(message, composer);
assertThat(writer.getString()).isEqualTo("* 100 FETCH (UID 72)\r\n");
@@ -69,7 +71,7 @@ public class FetchResponseEncoderTest {
@Test
public void testShouldEncodeAllResponse() throws Exception {
- FetchResponse message = new FetchResponse(100, flags,
MessageUid.of(72), null,
+ FetchResponse message = new FetchResponse(MSN, flags,
MessageUid.of(72), null,
null, null, null, null, null, null);
encoder.encode(message, composer);
assertThat(writer.getString()).isEqualTo("* 100 FETCH (FLAGS
(\\Deleted) UID 72)\r\n");
diff --git
a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java
b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java
index 3c7c66c..7976841 100644
---
a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java
+++
b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java
@@ -24,6 +24,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.time.Duration;
import java.util.Map;
+import org.apache.james.mailbox.MessageSequenceNumber;
+import org.apache.james.mailbox.NullableMessageSequenceNumber;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.util.concurrency.ConcurrentTestRunner;
import org.junit.Before;
@@ -98,7 +100,7 @@ public class UidMsnConverterTest {
public void getMsnShouldReturnAbsentIfNoCorrespondingMessage() {
testee.addUid(messageUid1);
- assertThat(testee.getMsn(messageUid2)).isEmpty();
+
assertThat(testee.getMsn(messageUid2)).isEqualTo(NullableMessageSequenceNumber.noMessage());
}
@Test
@@ -107,7 +109,7 @@ public class UidMsnConverterTest {
testee.addUid(messageUid2);
assertThat(testee.getMsn(messageUid2))
- .contains(2);
+ .isEqualTo(NullableMessageSequenceNumber.of(2));
}
@Test
@@ -173,7 +175,7 @@ public class UidMsnConverterTest {
testee.addUid(messageUid2);
assertThat(testee.getMsn(messageUid2))
- .contains(2);
+ .isEqualTo(NullableMessageSequenceNumber.of(2));
}
@Test
diff --git
a/protocols/imap/src/main/java/org/apache/james/imap/message/response/ExpungeResponse.java
b/protocols/imap/src/test/java/org/apache/james/mailbox/MessageSequenceNumberTest.java
similarity index 54%
copy from
protocols/imap/src/main/java/org/apache/james/imap/message/response/ExpungeResponse.java
copy to
protocols/imap/src/test/java/org/apache/james/mailbox/MessageSequenceNumberTest.java
index 2d13203..16369cf 100644
---
a/protocols/imap/src/main/java/org/apache/james/imap/message/response/ExpungeResponse.java
+++
b/protocols/imap/src/test/java/org/apache/james/mailbox/MessageSequenceNumberTest.java
@@ -17,23 +17,41 @@
* under the License. *
****************************************************************/
-package org.apache.james.imap.message.response;
+package org.apache.james.mailbox;
-import org.apache.james.imap.api.message.response.ImapResponseMessage;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
-public final class ExpungeResponse implements ImapResponseMessage {
+import org.junit.jupiter.api.Test;
- private final int messageSequenceNumber;
+import nl.jqno.equalsverifier.EqualsVerifier;
- public ExpungeResponse(int messageSequenceNumber) {
- this.messageSequenceNumber = messageSequenceNumber;
+class MessageSequenceNumberTest {
+
+ @Test
+ void ofShouldThrowOnNegative() {
+ assertThatThrownBy(() ->
MessageSequenceNumber.of(-1)).isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void ofShouldNotThrowOnZero() {
+ assertThatCode(() ->
MessageSequenceNumber.of(0)).doesNotThrowAnyException();
}
- public int getMessageSequenceNumber() {
- return messageSequenceNumber;
+ @Test
+ void ofShouldNotThrowOnPositiveValue() {
+ assertThatCode(() ->
MessageSequenceNumber.of(12)).doesNotThrowAnyException();
}
- public String toString() {
- return "EXPUNGE " + messageSequenceNumber;
+ @Test
+ void asIntShouldReturnValue() {
+ assertThat(MessageSequenceNumber.of(12).asInt()).isEqualTo(12);
}
-}
+
+ @Test
+ void shouldRespectBeanContract() {
+ EqualsVerifier.forClass(MessageSequenceNumber.class).verify();
+ }
+
+}
\ No newline at end of file
diff --git
a/protocols/imap/src/test/java/org/apache/james/mailbox/NullableMessageSequenceNumberTest.java
b/protocols/imap/src/test/java/org/apache/james/mailbox/NullableMessageSequenceNumberTest.java
new file mode 100644
index 0000000..9cb57b5
--- /dev/null
+++
b/protocols/imap/src/test/java/org/apache/james/mailbox/NullableMessageSequenceNumberTest.java
@@ -0,0 +1,94 @@
+/****************************************************************
+ * 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 static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class NullableMessageSequenceNumberTest {
+
+ @Test
+ void ofShouldThrowOnNegative() {
+ assertThatThrownBy(() ->
NullableMessageSequenceNumber.of(-1)).isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void ofShouldNotThrowOnZero() {
+ assertThatCode(() ->
NullableMessageSequenceNumber.of(0)).doesNotThrowAnyException();
+ }
+
+ @Test
+ void ofShouldNotThrowOnPositiveValue() {
+ assertThatCode(() ->
NullableMessageSequenceNumber.of(12)).doesNotThrowAnyException();
+ }
+
+ @Test
+ void asIntShouldReturnIntWhenMessage() {
+ assertThat(NullableMessageSequenceNumber.of(12).asInt()).contains(12);
+ }
+
+ @Test
+ void asIntShouldReturnEmptyWhenNoMessage() {
+
assertThat(NullableMessageSequenceNumber.noMessage().asInt()).isEmpty();
+ }
+
+ @Test
+ void foldShouldCallOnlyFirstMethodOnNoMessage() {
+ assertThatCode(
+ () -> NullableMessageSequenceNumber.noMessage().fold(() -> 12, msn
-> fail()))
+ .doesNotThrowAnyException();
+ }
+
+ @Test
+ void foldShouldCallOnlySecondMethodOnMessage() {
+ assertThatCode(
+ () -> NullableMessageSequenceNumber.of(24).fold(Assertions::fail,
msn -> 12))
+ .doesNotThrowAnyException();
+ }
+
+ @Test
+ void ifPresentShouldNotCallMethodOnNoMessage() {
+ assertThatCode(
+ () -> NullableMessageSequenceNumber.noMessage().ifPresent(ignored
-> Assertions.fail()))
+ .doesNotThrowAnyException();
+ }
+
+ @Test
+ void ifPresentShouldCallMethodOnWithMessage() {
+ AtomicReference<MessageSequenceNumber> ref = new AtomicReference<>();
+ NullableMessageSequenceNumber.of(24).ifPresent(ref::set);
+ assertThat(ref.get()).isNotNull();
+ }
+
+ @Test
+ void shouldRespectBeanContract() {
+ EqualsVerifier.forClass(NullableMessageSequenceNumber.class).verify();
+ }
+
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]