You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2022/12/12 06:13:44 UTC
[james-project] 01/08: JAMES-3754 Add saveDate field to MailboxMessage and associated Cassandra tables
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 439c961a4c413475686633e5bf66c61acee60915
Author: Quan Tran <hq...@linagora.com>
AuthorDate: Tue Nov 29 16:23:53 2022 +0700
JAMES-3754 Add saveDate field to MailboxMessage and associated Cassandra tables
Add saveDate column to`messageIdTable` and `imapUidTable`
---
.../apache/james/mailbox/MailboxManagerTest.java | 20 +++++++
mailbox/cassandra/pom.xml | 5 ++
.../mailbox/cassandra/CassandraMailboxManager.java | 9 ++--
.../mailbox/cassandra/CassandraMessageManager.java | 7 ++-
.../cassandra/mail/CassandraMessageIdDAO.java | 5 ++
.../mail/CassandraMessageIdToImapUidDAO.java | 8 +++
.../cassandra/mail/CassandraMessageMetadata.java | 34 ++++++++++--
.../cassandra/modules/CassandraMessageModule.java | 2 +
.../cassandra/table/CassandraMessageIdTable.java | 2 +
.../cassandra/CassandraMailboxManagerProvider.java | 12 +++--
.../cassandra/CassandraTestSystemFixture.java | 5 +-
.../CassandraMailboxManagerAttachmentTest.java | 6 ++-
.../cassandra/mail/CassandraMessageDAOV3Test.java | 18 ++++---
.../cassandra/mail/CassandraMessageIdDAOTest.java | 52 ++++++++++++++++++
.../mail/CassandraMessageIdToImapUidDAOTest.java | 51 ++++++++++++++++++
mailbox/jpa/pom.xml | 5 ++
.../model/openjpa/AbstractJPAMailboxMessage.java | 6 +++
.../mailbox/jpa/openjpa/OpenJPAMailboxManager.java | 9 ++--
.../mailbox/jpa/openjpa/OpenJPAMessageFactory.java | 2 +-
.../mailbox/jpa/openjpa/OpenJPAMessageManager.java | 6 ++-
.../james/mailbox/jpa/JPAMailboxManagerTest.java | 6 +++
.../mailbox/jpa/JpaMailboxManagerProvider.java | 5 +-
mailbox/memory/pom.xml | 5 ++
.../mailbox/inmemory/InMemoryMailboxManager.java | 9 ++--
.../mailbox/inmemory/InMemoryMessageManager.java | 7 ++-
.../manager/InMemoryIntegrationResources.java | 6 ++-
mailbox/store/pom.xml | 5 ++
.../apache/james/mailbox/store/MessageFactory.java | 7 +--
.../apache/james/mailbox/store/MessageStorer.java | 34 +++++++-----
.../james/mailbox/store/StoreMailboxManager.java | 13 +++--
.../james/mailbox/store/mail/MessageMapper.java | 1 +
.../store/mail/model/DelegatingMailboxMessage.java | 1 +
.../mailbox/store/mail/model/MailboxMessage.java | 7 +++
.../mail/model/impl/SimpleMailboxMessage.java | 34 +++++++++---
.../apache/james/mailbox/store/MessageBuilder.java | 4 +-
.../mailbox/store/StoreMailboxManagerTest.java | 7 ++-
.../model/MessageWithAttachmentMapperTest.java | 3 +-
.../mail/model/impl/SimpleMailboxMessageTest.java | 63 +++++++++++++++++++++-
mpt/impl/imap-mailbox/cassandra/pom.xml | 5 ++
.../cassandra/host/CassandraHostSystem.java | 6 ++-
mpt/impl/imap-mailbox/jpa/pom.xml | 5 ++
.../mpt/imapmailbox/jpa/host/JPAHostSystem.java | 5 +-
42 files changed, 435 insertions(+), 67 deletions(-)
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index ed642c8c1f..033d9b6bfe 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -2873,6 +2873,26 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
}
}
+ @Nested
+ class SaveDateTests {
+ private MessageManager inboxManager;
+
+ @BeforeEach
+ void setUp() throws Exception {
+ session = mailboxManager.createSystemSession(USER_1);
+ MailboxPath inbox = MailboxPath.inbox(session);
+ mailboxManager.createMailbox(inbox, session).get();
+ inboxManager = mailboxManager.getMailbox(inbox, session);
+ }
+
+ @Test
+ void shouldSetSaveDateWhenAppendMessage() throws Exception {
+ ComposedMessageId composeId1 = inboxManager.appendMessage(AppendCommand.builder().build(message), session).getId();
+ MessageResult messageResult = inboxManager.getMessages(MessageRange.one(composeId1.getUid()), FetchGroup.MINIMAL, session).next();
+ assertThat(messageResult.getSaveDate()).isPresent();
+ }
+ }
+
@Nested
class RightTests {
diff --git a/mailbox/cassandra/pom.xml b/mailbox/cassandra/pom.xml
index 290df88663..4b4bd0dc9a 100644
--- a/mailbox/cassandra/pom.xml
+++ b/mailbox/cassandra/pom.xml
@@ -129,6 +129,11 @@
<artifactId>james-server-task-memory</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>james-server-testing</artifactId>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>james-server-util</artifactId>
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
index a81735072b..5ca039320a 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxManager.java
@@ -19,6 +19,7 @@
package org.apache.james.mailbox.cassandra;
+import java.time.Clock;
import java.util.EnumSet;
import javax.inject.Inject;
@@ -66,7 +67,7 @@ public class CassandraMailboxManager extends StoreMailboxManager {
StoreMailboxAnnotationManager annotationManager, StoreRightManager storeRightManager,
QuotaComponents quotaComponents, MessageSearchIndex index,
MailboxManagerConfiguration configuration,
- PreDeletionHooks preDeletionHooks, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm) {
+ PreDeletionHooks preDeletionHooks, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm, Clock clock) {
super(mapperFactory,
sessionProvider,
locker,
@@ -79,7 +80,8 @@ public class CassandraMailboxManager extends StoreMailboxManager {
index,
configuration,
preDeletionHooks,
- threadIdGuessingAlgorithm);
+ threadIdGuessingAlgorithm,
+ clock);
this.locker = locker;
this.mapperFactory = mapperFactory;
}
@@ -108,7 +110,8 @@ public class CassandraMailboxManager extends StoreMailboxManager {
configuration.getBatchSizes(),
getStoreRightManager(),
getPreDeletionHooks(),
- getThreadIdGuessingAlgorithm());
+ getThreadIdGuessingAlgorithm(),
+ getClock());
}
@Override
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
index cbbe0f4b36..0c02d5d6f0 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java
@@ -19,6 +19,8 @@
package org.apache.james.mailbox.cassandra;
+import java.time.Clock;
+
import javax.mail.Flags;
import org.apache.james.events.EventBus;
@@ -49,10 +51,11 @@ public class CassandraMessageManager extends StoreMessageManager {
BatchSizes batchSizes,
StoreRightManager storeRightManager,
PreDeletionHooks preDeletionHooks,
- ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm) {
+ ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm,
+ Clock clock) {
super(CassandraMailboxManager.MESSAGE_CAPABILITIES, mapperFactory, index, eventBus, locker, mailbox,
quotaManager, quotaRootResolver, batchSizes, storeRightManager,
- preDeletionHooks, new MessageStorer.WithAttachment(mapperFactory, messageIdFactory, new MessageFactory.StoreMessageFactory(), mapperFactory, messageParser, threadIdGuessingAlgorithm));
+ preDeletionHooks, new MessageStorer.WithAttachment(mapperFactory, messageIdFactory, new MessageFactory.StoreMessageFactory(), mapperFactory, messageParser, threadIdGuessingAlgorithm, clock));
}
/**
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
index 4d4177811a..540a33939b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAO.java
@@ -26,6 +26,7 @@ import static com.datastax.oss.driver.api.querybuilder.relation.Relation.column;
import static com.datastax.oss.driver.api.querybuilder.update.Assignment.append;
import static com.datastax.oss.driver.api.querybuilder.update.Assignment.remove;
import static com.datastax.oss.driver.api.querybuilder.update.Assignment.setColumn;
+import static org.apache.james.mailbox.cassandra.table.CassandraMessageIdTable.SAVE_DATE;
import static org.apache.james.mailbox.cassandra.table.CassandraMessageIdTable.TABLE_NAME;
import static org.apache.james.mailbox.cassandra.table.CassandraMessageIdTable.THREAD_ID;
import static org.apache.james.mailbox.cassandra.table.CassandraMessageIds.IMAP_UID;
@@ -171,6 +172,7 @@ public class CassandraMessageIdDAO {
setColumn(SEEN, bindMarker(SEEN)),
setColumn(USER, bindMarker(USER)),
setColumn(INTERNAL_DATE, bindMarker(INTERNAL_DATE)),
+ setColumn(SAVE_DATE, bindMarker(SAVE_DATE)),
setColumn(BODY_START_OCTET, bindMarker(BODY_START_OCTET)),
setColumn(FULL_CONTENT_OCTETS, bindMarker(FULL_CONTENT_OCTETS)),
setColumn(HEADER_CONTENT, bindMarker(HEADER_CONTENT)),
@@ -342,6 +344,7 @@ public class CassandraMessageIdDAO {
.setBoolean(SEEN, flags.contains(Flag.SEEN))
.setBoolean(USER, flags.contains(Flag.USER))
.setInstant(INTERNAL_DATE, metadata.getInternalDate().get().toInstant())
+ .setInstant(SAVE_DATE, metadata.getSaveDate().map(Date::toInstant).orElse(null))
.setInt(BODY_START_OCTET, Math.toIntExact(metadata.getBodyStartOctet().get()))
.setLong(FULL_CONTENT_OCTETS, metadata.getSize().get())
.setString(HEADER_CONTENT, metadata.getHeaderContent().get().asString())
@@ -566,6 +569,8 @@ public class CassandraMessageIdDAO {
.bodyStartOctet(row.get(BODY_START_OCTET, Integer.class))
.internalDate(Optional.ofNullable(row.get(INTERNAL_DATE, TypeCodecs.TIMESTAMP))
.map(Date::from))
+ .saveDate(Optional.ofNullable(row.get(SAVE_DATE, TypeCodecs.TIMESTAMP))
+ .map(Date::from))
.size(row.get(FULL_CONTENT_OCTETS, Long.class))
.headerContent(Optional.ofNullable(row.get(HEADER_CONTENT, TypeCodecs.TEXT))
.map(blobIdFactory::from))
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
index 19d450e1ac..315d7cf535 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAO.java
@@ -26,6 +26,7 @@ import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.selectFrom;
import static com.datastax.oss.driver.api.querybuilder.relation.Relation.column;
import static com.datastax.oss.driver.api.querybuilder.update.Assignment.setColumn;
import static org.apache.james.backends.cassandra.init.configuration.JamesExecutionProfiles.ConsistencyChoice.STRONG;
+import static org.apache.james.mailbox.cassandra.table.CassandraMessageIdTable.SAVE_DATE;
import static org.apache.james.mailbox.cassandra.table.CassandraMessageIds.IMAP_UID;
import static org.apache.james.mailbox.cassandra.table.CassandraMessageIds.MAILBOX_ID;
import static org.apache.james.mailbox.cassandra.table.CassandraMessageIds.MESSAGE_ID;
@@ -144,6 +145,7 @@ public class CassandraMessageIdToImapUidDAO {
.value(USER, bindMarker(USER))
.value(USER_FLAGS, bindMarker(USER_FLAGS))
.value(INTERNAL_DATE, bindMarker(INTERNAL_DATE))
+ .value(SAVE_DATE, bindMarker(SAVE_DATE))
.value(BODY_START_OCTET, bindMarker(BODY_START_OCTET))
.value(FULL_CONTENT_OCTETS, bindMarker(FULL_CONTENT_OCTETS))
.value(HEADER_CONTENT, bindMarker(HEADER_CONTENT));
@@ -161,6 +163,7 @@ public class CassandraMessageIdToImapUidDAO {
setColumn(SEEN, bindMarker(SEEN)),
setColumn(USER, bindMarker(USER)),
setColumn(INTERNAL_DATE, bindMarker(INTERNAL_DATE)),
+ setColumn(SAVE_DATE, bindMarker(SAVE_DATE)),
setColumn(BODY_START_OCTET, bindMarker(BODY_START_OCTET)),
setColumn(FULL_CONTENT_OCTETS, bindMarker(FULL_CONTENT_OCTETS)),
setColumn(HEADER_CONTENT, bindMarker(HEADER_CONTENT)))
@@ -187,6 +190,7 @@ public class CassandraMessageIdToImapUidDAO {
.value(USER, bindMarker(USER))
.value(USER_FLAGS, bindMarker(USER_FLAGS))
.value(INTERNAL_DATE, bindMarker(INTERNAL_DATE))
+ .value(SAVE_DATE, bindMarker(SAVE_DATE))
.value(BODY_START_OCTET, bindMarker(BODY_START_OCTET))
.value(FULL_CONTENT_OCTETS, bindMarker(FULL_CONTENT_OCTETS))
.value(HEADER_CONTENT, bindMarker(HEADER_CONTENT));
@@ -267,6 +271,7 @@ public class CassandraMessageIdToImapUidDAO {
.setBoolean(SEEN, flags.contains(Flag.SEEN))
.setBoolean(USER, flags.contains(Flag.USER))
.setInstant(INTERNAL_DATE, metadata.getInternalDate().get().toInstant())
+ .setInstant(SAVE_DATE, metadata.getSaveDate().map(Date::toInstant).orElse(null))
.setInt(BODY_START_OCTET, Math.toIntExact(metadata.getBodyStartOctet().get()))
.setLong(FULL_CONTENT_OCTETS, metadata.getSize().get())
.setString(HEADER_CONTENT, metadata.getHeaderContent().get().asString())
@@ -290,6 +295,7 @@ public class CassandraMessageIdToImapUidDAO {
.setBoolean(USER, flags.contains(Flag.USER))
.setSet(USER_FLAGS, ImmutableSet.copyOf(flags.getUserFlags()), String.class)
.setInstant(INTERNAL_DATE, metadata.getInternalDate().get().toInstant())
+ .setInstant(SAVE_DATE, metadata.getSaveDate().map(Date::toInstant).orElse(null))
.setInt(BODY_START_OCTET, Math.toIntExact(metadata.getBodyStartOctet().get()))
.setLong(FULL_CONTENT_OCTETS, metadata.getSize().get())
.setString(HEADER_CONTENT, metadata.getHeaderContent().get().asString()));
@@ -398,6 +404,8 @@ public class CassandraMessageIdToImapUidDAO {
.bodyStartOctet(row.get(BODY_START_OCTET, Integer.class))
.internalDate(Optional.ofNullable(row.get(INTERNAL_DATE, TypeCodecs.TIMESTAMP))
.map(Date::from))
+ .saveDate(Optional.ofNullable(row.get(SAVE_DATE, TypeCodecs.TIMESTAMP))
+ .map(Date::from))
.size(row.get(FULL_CONTENT_OCTETS, Long.class))
.headerContent(Optional.ofNullable(row.getString(HEADER_CONTENT))
.map(blobIdFactory::from))
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMetadata.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMetadata.java
index 16ede5de7c..0e34163bf5 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMetadata.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMetadata.java
@@ -53,12 +53,14 @@ public class CassandraMessageMetadata {
public static class Builder {
private ComposedMessageIdWithMetaData composedMessageId;
private Optional<Date> internalDate;
+ private Optional<Date> saveDate;
private Optional<Long> bodyStartOctet;
private Optional<Long> size;
private Optional<BlobId> headerContent;
public Builder() {
this.internalDate = Optional.empty();
+ this.saveDate = Optional.empty();
this.size = Optional.empty();
this.headerContent = Optional.empty();
this.bodyStartOctet = Optional.empty();
@@ -79,6 +81,16 @@ public class CassandraMessageMetadata {
return this;
}
+ public Builder saveDate(Date date) {
+ this.saveDate = Optional.ofNullable(date);
+ return this;
+ }
+
+ public Builder saveDate(Optional<Date> date) {
+ this.saveDate = date;
+ return this;
+ }
+
public Builder bodyStartOctet(Long bodyStartOctet) {
this.bodyStartOctet = Optional.ofNullable(bodyStartOctet);
return this;
@@ -113,7 +125,7 @@ public class CassandraMessageMetadata {
public CassandraMessageMetadata build() {
Preconditions.checkState(composedMessageId != null, "'composedMessageId' is compulsory");
- return new CassandraMessageMetadata(composedMessageId, internalDate, bodyStartOctet, size, headerContent);
+ return new CassandraMessageMetadata(composedMessageId, internalDate, saveDate, bodyStartOctet, size, headerContent);
}
}
@@ -266,6 +278,11 @@ public class CassandraMessageMetadata {
return delegate.getAttachments();
}
+ @Override
+ public Optional<Date> getSaveDate() {
+ return delegate.getSaveDate();
+ }
+
public BlobId getHeaderBlobId() {
return headerBlobId;
}
@@ -289,6 +306,7 @@ public class CassandraMessageMetadata {
.threadId(mailboxMessage.getThreadId())
.build(),
Optional.of(mailboxMessage.getInternalDate()),
+ mailboxMessage.getSaveDate(),
Optional.of(mailboxMessage.getHeaderOctets()),
Optional.of(mailboxMessage.getFullContentOctets()),
Optional.of(headerBlobId));
@@ -303,13 +321,15 @@ public class CassandraMessageMetadata {
private final ComposedMessageIdWithMetaData composedMessageId;
private final Optional<Date> internalDate;
+ private final Optional<Date> saveDate;
private final Optional<Long> bodyStartOctet;
private final Optional<Long> size;
private final Optional<BlobId> headerContent;
- public CassandraMessageMetadata(ComposedMessageIdWithMetaData composedMessageId, Optional<Date> internalDate, Optional<Long> bodyStartOctet, Optional<Long> size, Optional<BlobId> headerContent) {
+ public CassandraMessageMetadata(ComposedMessageIdWithMetaData composedMessageId, Optional<Date> internalDate, Optional<Date> saveDate, Optional<Long> bodyStartOctet, Optional<Long> size, Optional<BlobId> headerContent) {
this.composedMessageId = composedMessageId;
this.internalDate = internalDate;
+ this.saveDate = saveDate;
this.bodyStartOctet = bodyStartOctet;
this.size = size;
this.headerContent = headerContent;
@@ -337,6 +357,7 @@ public class CassandraMessageMetadata {
.size(size.get())
.bodyStartOctet(Math.toIntExact(bodyStartOctet.get()))
.internalDate(internalDate.get())
+ .saveDate(saveDate)
.properties(new PropertyBuilder())
.build(),
getHeaderContent().get());
@@ -362,9 +383,14 @@ public class CassandraMessageMetadata {
return size;
}
+ public Optional<Date> getSaveDate() {
+ return saveDate;
+ }
+
public CassandraMessageMetadata withMailboxId(MailboxId mailboxId) {
return builder()
.internalDate(internalDate)
+ .saveDate(saveDate)
.size(size)
.bodyStartOctet(bodyStartOctet)
.headerContent(headerContent)
@@ -385,6 +411,7 @@ public class CassandraMessageMetadata {
CassandraMessageMetadata other = (CassandraMessageMetadata) obj;
return Objects.equal(this.composedMessageId, other.composedMessageId)
&& Objects.equal(this.internalDate, other.internalDate)
+ && Objects.equal(this.saveDate, other.saveDate)
&& Objects.equal(this.bodyStartOctet, other.bodyStartOctet)
&& Objects.equal(this.size, other.size)
&& Objects.equal(this.headerContent, other.headerContent);
@@ -394,7 +421,7 @@ public class CassandraMessageMetadata {
@Override
public int hashCode() {
- return Objects.hashCode(composedMessageId, internalDate, bodyStartOctet, size, headerContent);
+ return Objects.hashCode(composedMessageId, internalDate, saveDate, bodyStartOctet, size, headerContent);
}
@Override
@@ -403,6 +430,7 @@ public class CassandraMessageMetadata {
.toStringHelper(this)
.add("composedMessageId", composedMessageId)
.add("internalDate", internalDate)
+ .add("saveDate", saveDate)
.add("bodyStartOctet", bodyStartOctet)
.add("size", size)
.add("headerContent", headerContent)
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java
index 96304e5af3..a667a31f66 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java
@@ -67,6 +67,7 @@ public interface CassandraMessageModule {
.withColumn(Flag.USER, BOOLEAN)
.withColumn(Flag.USER_FLAGS, setOf(TEXT))
.withColumn(CassandraMessageV3Table.INTERNAL_DATE, TIMESTAMP)
+ .withColumn(CassandraMessageIdTable.SAVE_DATE, TIMESTAMP)
.withColumn(CassandraMessageV3Table.BODY_START_OCTET, INT)
.withColumn(CassandraMessageV3Table.FULL_CONTENT_OCTETS, BIGINT)
.withColumn(CassandraMessageV3Table.HEADER_CONTENT, TEXT))
@@ -91,6 +92,7 @@ public interface CassandraMessageModule {
.withColumn(Flag.USER, BOOLEAN)
.withColumn(Flag.USER_FLAGS, setOf(TEXT))
.withColumn(CassandraMessageV3Table.INTERNAL_DATE, TIMESTAMP)
+ .withColumn(CassandraMessageIdTable.SAVE_DATE, TIMESTAMP)
.withColumn(CassandraMessageV3Table.BODY_START_OCTET, INT)
.withColumn(CassandraMessageV3Table.FULL_CONTENT_OCTETS, BIGINT)
.withColumn(CassandraMessageV3Table.HEADER_CONTENT, TEXT))
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageIdTable.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageIdTable.java
index 6ab2d26bd2..15ba47fcba 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageIdTable.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageIdTable.java
@@ -27,4 +27,6 @@ public interface CassandraMessageIdTable {
CqlIdentifier MOD_SEQ = CqlIdentifier.fromCql("modSeq");
CqlIdentifier THREAD_ID = CqlIdentifier.fromCql("threadId");
+
+ CqlIdentifier SAVE_DATE = CqlIdentifier.fromCql("save_date");
}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
index 376cec8f73..f3b669ec97 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
@@ -19,6 +19,9 @@
package org.apache.james.mailbox.cassandra;
+import java.time.Clock;
+import java.time.Instant;
+
import org.apache.james.backends.cassandra.CassandraCluster;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
import org.apache.james.events.EventBusTestFixture;
@@ -56,6 +59,7 @@ import org.apache.james.mailbox.store.quota.StoreQuotaManager;
import org.apache.james.mailbox.store.search.MessageSearchIndex;
import org.apache.james.mailbox.store.search.SimpleMessageSearchIndex;
import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.utils.UpdatableTickingClock;
import com.datastax.oss.driver.api.core.CqlSession;
@@ -81,6 +85,7 @@ public class CassandraMailboxManagerProvider {
MailboxManagerConfiguration mailboxManagerConfiguration) {
CassandraMessageId.Factory messageIdFactory = new CassandraMessageId.Factory();
ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm = new NaiveThreadIdGuessingAlgorithm();
+ UpdatableTickingClock clock = new UpdatableTickingClock(Instant.now());
CassandraMailboxSessionMapperFactory mapperFactory = TestCassandraMailboxSessionMapperFactory.forTests(
cassandra,
@@ -88,7 +93,7 @@ public class CassandraMailboxManagerProvider {
cassandraConfiguration);
return provideMailboxManager(cassandra.getConf(), preDeletionHooks, mapperFactory,
- mailboxManagerConfiguration, messageIdFactory, threadIdGuessingAlgorithm);
+ mailboxManagerConfiguration, messageIdFactory, threadIdGuessingAlgorithm, clock);
}
private static CassandraMailboxManager provideMailboxManager(CqlSession session,
@@ -96,7 +101,8 @@ public class CassandraMailboxManagerProvider {
CassandraMailboxSessionMapperFactory mapperFactory,
MailboxManagerConfiguration mailboxManagerConfiguration,
MessageId.Factory messageIdFactory,
- ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm) {
+ ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm,
+ Clock clock) {
MailboxACLResolver aclResolver = new UnionMailboxACLResolver();
MessageParser messageParser = new MessageParser();
InVMEventBus eventBus = new InVMEventBus(new InVmEventDelivery(new RecordingMetricFactory()), EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION, new MemoryEventDeadLetters());
@@ -122,7 +128,7 @@ public class CassandraMailboxManagerProvider {
CassandraMailboxManager manager = new CassandraMailboxManager(mapperFactory, sessionProvider, new NoMailboxPathLocker(),
messageParser, messageIdFactory, eventBus, annotationManager, storeRightManager,
- quotaComponents, index, mailboxManagerConfiguration, preDeletionHooks, threadIdGuessingAlgorithm);
+ quotaComponents, index, mailboxManagerConfiguration, preDeletionHooks, threadIdGuessingAlgorithm, clock);
eventBus.register(quotaUpdater);
eventBus.register(new MailboxAnnotationListener(mapperFactory, sessionProvider));
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
index a31836e8b2..774959e2ca 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
@@ -21,6 +21,8 @@ package org.apache.james.mailbox.cassandra;
import static org.mockito.Mockito.mock;
+import java.time.Instant;
+
import org.apache.james.backends.cassandra.CassandraCluster;
import org.apache.james.events.EventBus;
import org.apache.james.events.EventBusTestFixture;
@@ -56,6 +58,7 @@ import org.apache.james.mailbox.store.quota.QuotaComponents;
import org.apache.james.mailbox.store.search.MessageSearchIndex;
import org.apache.james.mailbox.store.search.SimpleMessageSearchIndex;
import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.utils.UpdatableTickingClock;
public class CassandraTestSystemFixture {
@@ -78,7 +81,7 @@ public class CassandraTestSystemFixture {
CassandraMailboxManager cassandraMailboxManager = new CassandraMailboxManager(mapperFactory, sessionProvider,
new NoMailboxPathLocker(), new MessageParser(), new CassandraMessageId.Factory(),
eventBus, annotationManager, storeRightManager, quotaComponents, index, MailboxManagerConfiguration.DEFAULT, PreDeletionHooks.NO_PRE_DELETION_HOOK,
- new NaiveThreadIdGuessingAlgorithm());
+ new NaiveThreadIdGuessingAlgorithm(), new UpdatableTickingClock(Instant.now()));
eventBus.register(new MailboxAnnotationListener(mapperFactory, sessionProvider));
eventBus.register(mapperFactory.deleteMessageListener());
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
index 273f354e8e..a0e3b7e50c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
@@ -23,6 +23,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.InputStream;
+import java.time.Instant;
import org.apache.james.backends.cassandra.CassandraClusterExtension;
import org.apache.james.events.EventBusTestFixture;
@@ -55,6 +56,7 @@ import org.apache.james.mailbox.store.quota.QuotaComponents;
import org.apache.james.mailbox.store.search.MessageSearchIndex;
import org.apache.james.mailbox.store.search.SimpleMessageSearchIndex;
import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.utils.UpdatableTickingClock;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -92,13 +94,13 @@ class CassandraMailboxManagerAttachmentTest extends AbstractMailboxManagerAttach
mailboxManager = new CassandraMailboxManager(mailboxSessionMapperFactory, sessionProvider, new NoMailboxPathLocker(), new MessageParser(),
messageIdFactory, eventBus, annotationManager, storeRightManager, quotaComponents,
- index, MailboxManagerConfiguration.DEFAULT, PreDeletionHooks.NO_PRE_DELETION_HOOK, threadIdGuessingAlgorithm);
+ index, MailboxManagerConfiguration.DEFAULT, PreDeletionHooks.NO_PRE_DELETION_HOOK, threadIdGuessingAlgorithm, new UpdatableTickingClock(Instant.now()));
MessageParser failingMessageParser = mock(MessageParser.class);
when(failingMessageParser.retrieveAttachments(any(InputStream.class)))
.thenThrow(new RuntimeException("Message parser set to fail"));
parseFailingMailboxManager = new CassandraMailboxManager(mailboxSessionMapperFactory, sessionProvider,
new NoMailboxPathLocker(), failingMessageParser, messageIdFactory,
- eventBus, annotationManager, storeRightManager, quotaComponents, index, MailboxManagerConfiguration.DEFAULT, PreDeletionHooks.NO_PRE_DELETION_HOOK, threadIdGuessingAlgorithm);
+ eventBus, annotationManager, storeRightManager, quotaComponents, index, MailboxManagerConfiguration.DEFAULT, PreDeletionHooks.NO_PRE_DELETION_HOOK, threadIdGuessingAlgorithm, new UpdatableTickingClock(Instant.now()));
}
@Override
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java
index 9b6f6fd2ce..23f64fa854 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAOV3Test.java
@@ -18,12 +18,14 @@
****************************************************************/
package org.apache.james.mailbox.cassandra.mail;
+import static org.apache.james.mailbox.store.mail.model.MailboxMessage.EMPTY_SAVE_DATE;
import static org.assertj.core.api.Assertions.assertThat;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Date;
import java.util.List;
+import java.util.Optional;
import javax.mail.Flags;
@@ -112,7 +114,7 @@ class CassandraMessageDAOV3Test {
@Test
void saveShouldSaveNullValueForTextualLineCountAsZero() throws Exception {
- message = createMessage(messageId, threadId, CONTENT, BODY_START, new PropertyBuilder(), NO_ATTACHMENT);
+ message = createMessage(messageId, threadId, CONTENT, BODY_START, new PropertyBuilder(), NO_ATTACHMENT, EMPTY_SAVE_DATE);
testee.save(message).block();
@@ -128,7 +130,7 @@ class CassandraMessageDAOV3Test {
long textualLineCount = 10L;
PropertyBuilder propertyBuilder = new PropertyBuilder();
propertyBuilder.setTextualLineCount(textualLineCount);
- message = createMessage(messageId, threadId, CONTENT, BODY_START, propertyBuilder, NO_ATTACHMENT);
+ message = createMessage(messageId, threadId, CONTENT, BODY_START, propertyBuilder, NO_ATTACHMENT, EMPTY_SAVE_DATE);
testee.save(message).block();
@@ -140,7 +142,7 @@ class CassandraMessageDAOV3Test {
@Test
void saveShouldStoreMessageWithFullContent() throws Exception {
- message = createMessage(messageId, threadId, CONTENT, BODY_START, new PropertyBuilder(), NO_ATTACHMENT);
+ message = createMessage(messageId, threadId, CONTENT, BODY_START, new PropertyBuilder(), NO_ATTACHMENT, EMPTY_SAVE_DATE);
testee.save(message).block();
@@ -153,7 +155,7 @@ class CassandraMessageDAOV3Test {
@Test
void saveShouldStoreMessageWithHeaderContent() throws Exception {
- message = createMessage(messageId, threadId, CONTENT, BODY_START, new PropertyBuilder(), NO_ATTACHMENT);
+ message = createMessage(messageId, threadId, CONTENT, BODY_START, new PropertyBuilder(), NO_ATTACHMENT, EMPTY_SAVE_DATE);
testee.save(message).block();
@@ -172,8 +174,8 @@ class CassandraMessageDAOV3Test {
@Test
void blobReferencesShouldReturnAllBlobs() throws Exception {
- message = createMessage(messageId, threadId, CONTENT, BODY_START, new PropertyBuilder(), NO_ATTACHMENT);
- MailboxMessage message2 = createMessage(messageId2, threadId, CONTENT_2, BODY_START, new PropertyBuilder(), NO_ATTACHMENT);
+ message = createMessage(messageId, threadId, CONTENT, BODY_START, new PropertyBuilder(), NO_ATTACHMENT, EMPTY_SAVE_DATE);
+ MailboxMessage message2 = createMessage(messageId2, threadId, CONTENT_2, BODY_START, new PropertyBuilder(), NO_ATTACHMENT, EMPTY_SAVE_DATE);
testee.save(message).block();
testee.save(message2).block();
@@ -181,13 +183,15 @@ class CassandraMessageDAOV3Test {
.hasSize(4);
}
- private SimpleMailboxMessage createMessage(MessageId messageId, ThreadId threadId, String content, int bodyStart, PropertyBuilder propertyBuilder, Collection<MessageAttachmentMetadata> attachments) {
+ private SimpleMailboxMessage createMessage(MessageId messageId, ThreadId threadId, String content, int bodyStart, PropertyBuilder propertyBuilder,
+ Collection<MessageAttachmentMetadata> attachments, Optional<Date> saveDate) {
return SimpleMailboxMessage.builder()
.messageId(messageId)
.threadId(threadId)
.mailboxId(MAILBOX_ID)
.uid(messageUid)
.internalDate(new Date())
+ .saveDate(saveDate)
.bodyStartOctet(bodyStart)
.size(content.length())
.content(new ByteContent(content.getBytes(StandardCharsets.UTF_8)))
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
index 6f76a71fef..a3f65698d1 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdDAOTest.java
@@ -207,6 +207,58 @@ class CassandraMessageIdDAOTest {
assertThat(message.get().getComposedMessageId()).isEqualTo(composedMessageIdWithMetaData);
}
+ @Test
+ void shouldHandleNullSaveDateWell() {
+ CassandraMessageId messageId = messageIdFactory.generate();
+ CassandraId mailboxId = CassandraId.timeBased();
+ MessageUid messageUid = MessageUid.of(1);
+
+ ComposedMessageIdWithMetaData composedMessageIdWithMetaData = ComposedMessageIdWithMetaData.builder()
+ .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
+ .flags(new Flags())
+ .modSeq(ModSeq.of(1))
+ .threadId(ThreadId.fromBaseMessageId(messageId))
+ .build();
+ testee.insert(CassandraMessageMetadata.builder()
+ .ids(composedMessageIdWithMetaData)
+ .internalDate(new Date())
+ .bodyStartOctet(18L)
+ .size(36L)
+ .headerContent(Optional.of(HEADER_BLOB_ID_1))
+ .build())
+ .block();
+
+ Optional<CassandraMessageMetadata> message = testee.retrieve(mailboxId, messageUid).block();
+ assertThat(message.get().getSaveDate()).isEmpty();
+ }
+
+ @Test
+ void shouldHandleSaveDateWell() {
+ CassandraMessageId messageId = messageIdFactory.generate();
+ CassandraId mailboxId = CassandraId.timeBased();
+ MessageUid messageUid = MessageUid.of(1);
+ Optional<Date> saveDate = Optional.of(new Date());
+
+ ComposedMessageIdWithMetaData composedMessageIdWithMetaData = ComposedMessageIdWithMetaData.builder()
+ .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
+ .flags(new Flags())
+ .modSeq(ModSeq.of(1))
+ .threadId(ThreadId.fromBaseMessageId(messageId))
+ .build();
+ testee.insert(CassandraMessageMetadata.builder()
+ .ids(composedMessageIdWithMetaData)
+ .internalDate(new Date())
+ .saveDate(saveDate)
+ .bodyStartOctet(18L)
+ .size(36L)
+ .headerContent(Optional.of(HEADER_BLOB_ID_1))
+ .build())
+ .block();
+
+ Optional<CassandraMessageMetadata> message = testee.retrieve(mailboxId, messageUid).block();
+ assertThat(message.get().getSaveDate()).isEqualTo(saveDate);
+ }
+
@Test
void updateShouldUpdateModSeq() {
CassandraMessageId messageId = messageIdFactory.generate();
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
index 0891106753..857ac74ae1 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdToImapUidDAOTest.java
@@ -181,6 +181,57 @@ class CassandraMessageIdToImapUidDAOTest {
.containsOnly(expectedComposedMessageId);
}
+ @Test
+ void shouldHandleNullSaveDateWell() {
+ CassandraMessageId messageId = CassandraMessageId.Factory.of(Uuids.timeBased());
+ CassandraId mailboxId = CassandraId.timeBased();
+ MessageUid messageUid = MessageUid.of(1);
+
+ testee.insert(CassandraMessageMetadata.builder()
+ .ids(ComposedMessageIdWithMetaData.builder()
+ .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
+ .flags(new Flags())
+ .modSeq(ModSeq.of(1))
+ .threadId(ThreadId.fromBaseMessageId(messageId))
+ .build())
+ .internalDate(new Date())
+ .saveDate(Optional.empty())
+ .bodyStartOctet(18L)
+ .size(36L)
+ .headerContent(Optional.of(HEADER_BLOB_ID_1))
+ .build())
+ .block();
+
+ List<CassandraMessageMetadata> messages = testee.retrieve(messageId, Optional.empty()).collectList().block();
+ assertThat(messages.get(0).getSaveDate()).isEmpty();
+ }
+
+ @Test
+ void shouldHandleSaveDateWell() {
+ CassandraMessageId messageId = CassandraMessageId.Factory.of(Uuids.timeBased());
+ CassandraId mailboxId = CassandraId.timeBased();
+ MessageUid messageUid = MessageUid.of(1);
+ Optional<Date> saveDate = Optional.of(new Date());
+
+ testee.insert(CassandraMessageMetadata.builder()
+ .ids(ComposedMessageIdWithMetaData.builder()
+ .composedMessageId(new ComposedMessageId(mailboxId, messageId, messageUid))
+ .flags(new Flags())
+ .modSeq(ModSeq.of(1))
+ .threadId(ThreadId.fromBaseMessageId(messageId))
+ .build())
+ .internalDate(new Date())
+ .saveDate(saveDate)
+ .bodyStartOctet(18L)
+ .size(36L)
+ .headerContent(Optional.of(HEADER_BLOB_ID_1))
+ .build())
+ .block();
+
+ List<CassandraMessageMetadata> messages = testee.retrieve(messageId, Optional.empty()).collectList().block();
+ assertThat(messages.get(0).getSaveDate()).isEqualTo(saveDate);
+ }
+
@Test
void updateShouldReturnTrueWhenOldModSeqMatches() {
CassandraMessageId messageId = CassandraMessageId.Factory.of(Uuids.timeBased());
diff --git a/mailbox/jpa/pom.xml b/mailbox/jpa/pom.xml
index ee8e93a90f..8fbaf2ad5d 100644
--- a/mailbox/jpa/pom.xml
+++ b/mailbox/jpa/pom.xml
@@ -89,6 +89,11 @@
<artifactId>james-server-data-jpa</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>james-server-testing</artifactId>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>james-server-util</artifactId>
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java
index cae6c2554c..879171416d 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java
@@ -25,6 +25,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import javax.mail.Flags;
@@ -500,6 +501,11 @@ public abstract class AbstractJPAMailboxMessage implements MailboxMessage {
return new ThreadId(getMessageId());
}
+ @Override
+ public Optional<Date> getSaveDate() {
+ return Optional.empty();
+ }
+
public String toString() {
return "message("
+ "mailboxId = " + this.getMailboxId() + TOSTRING_SEPARATOR
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMailboxManager.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMailboxManager.java
index 606d8a71e2..5346770f52 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMailboxManager.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMailboxManager.java
@@ -19,6 +19,7 @@
package org.apache.james.mailbox.jpa.openjpa;
+import java.time.Clock;
import java.util.EnumSet;
import javax.inject.Inject;
@@ -61,11 +62,12 @@ public class OpenJPAMailboxManager extends StoreMailboxManager {
StoreRightManager storeRightManager,
QuotaComponents quotaComponents,
MessageSearchIndex index,
- ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm) {
+ ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm,
+ Clock clock) {
super(mapperFactory, sessionProvider, new JVMMailboxPathLocker(),
messageParser, messageIdFactory, annotationManager,
eventBus, storeRightManager, quotaComponents,
- index, MailboxManagerConfiguration.DEFAULT, PreDeletionHooks.NO_PRE_DELETION_HOOK, threadIdGuessingAlgorithm);
+ index, MailboxManagerConfiguration.DEFAULT, PreDeletionHooks.NO_PRE_DELETION_HOOK, threadIdGuessingAlgorithm, clock);
}
@Override
@@ -80,7 +82,8 @@ public class OpenJPAMailboxManager extends StoreMailboxManager {
getMessageIdFactory(),
configuration.getBatchSizes(),
getStoreRightManager(),
- getThreadIdGuessingAlgorithm());
+ getThreadIdGuessingAlgorithm(),
+ getClock());
}
@Override
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageFactory.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageFactory.java
index b296258ced..79b08c492e 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageFactory.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageFactory.java
@@ -52,7 +52,7 @@ public class OpenJPAMessageFactory implements MessageFactory<AbstractJPAMailboxM
}
@Override
- public AbstractJPAMailboxMessage createMessage(MessageId messageId, ThreadId threadId, Mailbox mailbox, Date internalDate, int size, int bodyStartOctet, Content content, Flags flags, PropertyBuilder propertyBuilder, List<MessageAttachmentMetadata> attachments) throws MailboxException {
+ public AbstractJPAMailboxMessage createMessage(MessageId messageId, ThreadId threadId, Mailbox mailbox, Date internalDate, Date saveDate, int size, int bodyStartOctet, Content content, Flags flags, PropertyBuilder propertyBuilder, List<MessageAttachmentMetadata> attachments) throws MailboxException {
switch (feature) {
case Streaming:
return new JPAStreamingMailboxMessage(JPAMailbox.from(mailbox), internalDate, size, flags, content,
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java
index 21dfb88926..567e8d5ac6 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java
@@ -19,6 +19,8 @@
package org.apache.james.mailbox.jpa.openjpa;
+import java.time.Clock;
+
import javax.mail.Flags;
import org.apache.james.events.EventBus;
@@ -48,10 +50,10 @@ public class OpenJPAMessageManager extends StoreMessageManager {
MailboxPathLocker locker, Mailbox mailbox,
QuotaManager quotaManager, QuotaRootResolver quotaRootResolver,
MessageId.Factory messageIdFactory, BatchSizes batchSizes,
- StoreRightManager storeRightManager, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm) {
+ StoreRightManager storeRightManager, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm, Clock clock) {
super(StoreMailboxManager.DEFAULT_NO_MESSAGE_CAPABILITIES, mapperFactory, index, eventBus, locker, mailbox,
quotaManager, quotaRootResolver, batchSizes, storeRightManager, PreDeletionHooks.NO_PRE_DELETION_HOOK,
- new MessageStorer.WithoutAttachment(mapperFactory, messageIdFactory, new OpenJPAMessageFactory(OpenJPAMessageFactory.AdvancedFeature.None), threadIdGuessingAlgorithm));
+ new MessageStorer.WithoutAttachment(mapperFactory, messageIdFactory, new OpenJPAMessageFactory(OpenJPAMessageFactory.AdvancedFeature.None), threadIdGuessingAlgorithm, clock));
}
/**
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
index bab657d713..b31ce31433 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
@@ -67,6 +67,12 @@ class JPAMailboxManagerTest extends MailboxManagerTest<OpenJPAMailboxManager> {
}
+ @Nested
+ @Disabled("JPA does not support saveDate.")
+ class SaveDateTests {
+
+ }
+
@Override
protected EventBus retrieveEventBus(OpenJPAMailboxManager mailboxManager) {
return mailboxManager.getEventBus();
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java
index 1aafb340d2..b951986ab2 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java
@@ -19,6 +19,8 @@
package org.apache.james.mailbox.jpa;
+import java.time.Instant;
+
import javax.persistence.EntityManagerFactory;
import org.apache.james.backends.jpa.JpaTestCluster;
@@ -44,6 +46,7 @@ import org.apache.james.mailbox.store.quota.QuotaComponents;
import org.apache.james.mailbox.store.search.MessageSearchIndex;
import org.apache.james.mailbox.store.search.SimpleMessageSearchIndex;
import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.utils.UpdatableTickingClock;
public class JpaMailboxManagerProvider {
@@ -71,6 +74,6 @@ public class JpaMailboxManagerProvider {
return new OpenJPAMailboxManager(mf, sessionProvider,
messageParser, new DefaultMessageId.Factory(),
eventBus, annotationManager,
- storeRightManager, quotaComponents, index, new NaiveThreadIdGuessingAlgorithm());
+ storeRightManager, quotaComponents, index, new NaiveThreadIdGuessingAlgorithm(), new UpdatableTickingClock(Instant.now()));
}
}
diff --git a/mailbox/memory/pom.xml b/mailbox/memory/pom.xml
index ab6466cb74..13443d537f 100644
--- a/mailbox/memory/pom.xml
+++ b/mailbox/memory/pom.xml
@@ -74,6 +74,11 @@
<artifactId>james-server-data-memory</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>james-server-testing</artifactId>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>james-server-util</artifactId>
diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java
index bf27e7767d..f7380c749f 100644
--- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java
+++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxManager.java
@@ -19,6 +19,7 @@
package org.apache.james.mailbox.inmemory;
+import java.time.Clock;
import java.util.EnumSet;
import javax.inject.Inject;
@@ -60,10 +61,11 @@ public class InMemoryMailboxManager extends StoreMailboxManager {
QuotaComponents quotaComponents,
MessageSearchIndex searchIndex,
PreDeletionHooks preDeletionHooks,
- ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm) {
+ ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm,
+ Clock clock) {
super(mailboxSessionMapperFactory, sessionProvider, locker, messageParser, messageIdFactory,
annotationManager, eventBus, storeRightManager, quotaComponents, searchIndex, MailboxManagerConfiguration.DEFAULT,
- preDeletionHooks, threadIdGuessingAlgorithm);
+ preDeletionHooks, threadIdGuessingAlgorithm, clock);
}
@Override
@@ -90,6 +92,7 @@ public class InMemoryMailboxManager extends StoreMailboxManager {
configuration.getBatchSizes(),
getStoreRightManager(),
getPreDeletionHooks(),
- getThreadIdGuessingAlgorithm());
+ getThreadIdGuessingAlgorithm(),
+ getClock());
}
}
diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java
index 9f95cf7f71..46d61cec72 100644
--- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java
+++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java
@@ -1,5 +1,7 @@
package org.apache.james.mailbox.inmemory;
+import java.time.Clock;
+
import javax.mail.Flags;
import org.apache.james.events.EventBus;
@@ -33,12 +35,13 @@ public class InMemoryMessageManager extends StoreMessageManager {
BatchSizes batchSizes,
StoreRightManager storeRightManager,
PreDeletionHooks preDeletionHooks,
- ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm) {
+ ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm,
+ Clock clock) {
super(InMemoryMailboxManager.MESSAGE_CAPABILITIES, mapperFactory, index, eventBus, locker, mailbox, quotaManager, quotaRootResolver,
batchSizes, storeRightManager, preDeletionHooks,
new MessageStorer.WithAttachment(mapperFactory, messageIdFactory, new MessageFactory.StoreMessageFactory(), (InMemoryMailboxSessionMapperFactory) mapperFactory, messageParser,
- threadIdGuessingAlgorithm));
+ threadIdGuessingAlgorithm, clock));
}
@Override
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
index 724938e235..d6a5c06759 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
@@ -19,6 +19,7 @@
package org.apache.james.mailbox.inmemory.manager;
+import java.time.Instant;
import java.util.Collection;
import java.util.Optional;
import java.util.function.Function;
@@ -72,6 +73,7 @@ import org.apache.james.mailbox.store.search.ListeningMessageSearchIndex;
import org.apache.james.mailbox.store.search.MessageSearchIndex;
import org.apache.james.mailbox.store.search.SimpleMessageSearchIndex;
import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.utils.UpdatableTickingClock;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -312,6 +314,7 @@ public class InMemoryIntegrationResources implements IntegrationResources<StoreM
InMemoryMessageId.Factory messageIdFactory = new InMemoryMessageId.Factory();
ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm = new NaiveThreadIdGuessingAlgorithm();
+ UpdatableTickingClock clock = new UpdatableTickingClock(Instant.now());
MailboxManagerPreInstanciationStage preInstanciationStage = new MailboxManagerPreInstanciationStage(mailboxSessionMapperFactory, sessionProvider);
PreDeletionHooks hooks = createHooks(preInstanciationStage);
@@ -334,7 +337,8 @@ public class InMemoryIntegrationResources implements IntegrationResources<StoreM
quotaComponents,
index,
hooks,
- threadIdGuessingAlgorithm);
+ threadIdGuessingAlgorithm,
+ clock);
eventBus.register(listeningCurrentQuotaUpdater);
eventBus.register(new MailboxAnnotationListener(mailboxSessionMapperFactory, sessionProvider));
diff --git a/mailbox/store/pom.xml b/mailbox/store/pom.xml
index 43b2320f26..199632266e 100644
--- a/mailbox/store/pom.xml
+++ b/mailbox/store/pom.xml
@@ -55,6 +55,11 @@
<artifactId>james-mdn</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>james-server-testing</artifactId>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>james-server-util</artifactId>
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/MessageFactory.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/MessageFactory.java
index dffe153301..0c6181e0ff 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/MessageFactory.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/MessageFactory.java
@@ -21,6 +21,7 @@ package org.apache.james.mailbox.store;
import java.util.Date;
import java.util.List;
+import java.util.Optional;
import javax.mail.Flags;
@@ -35,17 +36,17 @@ import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
public interface MessageFactory<T extends MailboxMessage> {
- T createMessage(MessageId messageId, ThreadId threadId, Mailbox mailbox, Date internalDate, int size, int bodyStartOctet,
+ T createMessage(MessageId messageId, ThreadId threadId, Mailbox mailbox, Date internalDate, Date saveDate, int size, int bodyStartOctet,
Content content, Flags flags, PropertyBuilder propertyBuilder,
List<MessageAttachmentMetadata> attachments) throws MailboxException;
class StoreMessageFactory implements MessageFactory<SimpleMailboxMessage> {
@Override
- public SimpleMailboxMessage createMessage(MessageId messageId, ThreadId threadId, Mailbox mailbox, Date internalDate, int size,
+ public SimpleMailboxMessage createMessage(MessageId messageId, ThreadId threadId, Mailbox mailbox, Date internalDate, Date saveDate, int size,
int bodyStartOctet, Content content, Flags flags,
PropertyBuilder propertyBuilder, List<MessageAttachmentMetadata> attachments) {
return new SimpleMailboxMessage(messageId, threadId, internalDate, size, bodyStartOctet, content, flags, propertyBuilder.build(),
- mailbox.getMailboxId(), attachments);
+ mailbox.getMailboxId(), attachments, Optional.of(saveDate));
}
}
}
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/MessageStorer.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/MessageStorer.java
index 797648020c..b612de7b45 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/MessageStorer.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/MessageStorer.java
@@ -20,6 +20,7 @@
package org.apache.james.mailbox.store;
import java.io.InputStream;
+import java.time.Clock;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@@ -60,14 +61,14 @@ public interface MessageStorer {
/**
* If supported by the underlying implementation, this method will parse the messageContent to retrieve associated
* attachments and will store them.
- *
+ * <p>
* Otherwize an empty optional will be returned on the right side of the pair.
*/
Mono<Pair<MessageMetaData, Optional<List<MessageAttachmentMetadata>>>> appendMessageToStore(Mailbox mailbox, Date internalDate, int size, int bodyStartOctet, Content content, Flags flags, PropertyBuilder propertyBuilder, Optional<Message> maybeMessage, MailboxSession session, HeaderImpl headers) throws MailboxException;
/**
* MessageStorer parsing, storing and returning AttachmentMetadata
- *
+ * <p>
* To be used with implementation that supports attachment content storage
*/
class WithAttachment implements MessageStorer {
@@ -79,16 +80,18 @@ public interface MessageStorer {
private final AttachmentMapperFactory attachmentMapperFactory;
private final MessageParser messageParser;
private final ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm;
+ private final Clock clock;
public WithAttachment(MailboxSessionMapperFactory mapperFactory, MessageId.Factory messageIdFactory,
MessageFactory messageFactory, AttachmentMapperFactory attachmentMapperFactory,
- MessageParser messageParser, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm) {
+ MessageParser messageParser, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm, Clock clock) {
this.mapperFactory = mapperFactory;
this.messageIdFactory = messageIdFactory;
this.messageFactory = messageFactory;
this.attachmentMapperFactory = attachmentMapperFactory;
this.messageParser = messageParser;
this.threadIdGuessingAlgorithm = threadIdGuessingAlgorithm;
+ this.clock = clock;
}
@Override
@@ -105,13 +108,14 @@ public interface MessageStorer {
storeAttachments(messageId, content, maybeMessage, session)
.zipWith(threadIdGuessingAlgorithm.guessThreadIdReactive(messageId, mimeMessageId, inReplyTo, references, subject, session))
.flatMap(Throwing.function((Tuple2<List<MessageAttachmentMetadata>, ThreadId> pair) -> {
- List<MessageAttachmentMetadata> attachments = pair.getT1();
- ThreadId threadId = pair.getT2();
-
- MailboxMessage message = messageFactory.createMessage(messageId, threadId, mailbox, internalDate, size, bodyStartOctet, content, flags, propertyBuilder, attachments);
- return Mono.from(messageMapper.addReactive(mailbox, message))
- .map(metadata -> Pair.of(metadata, Optional.of(attachments)));
- }).sneakyThrow()));
+ List<MessageAttachmentMetadata> attachments = pair.getT1();
+ ThreadId threadId = pair.getT2();
+ Date saveDate = Date.from(clock.instant());
+
+ MailboxMessage message = messageFactory.createMessage(messageId, threadId, mailbox, internalDate, saveDate, size, bodyStartOctet, content, flags, propertyBuilder, attachments);
+ return Mono.from(messageMapper.addReactive(mailbox, message))
+ .map(metadata -> Pair.of(metadata, Optional.of(attachments)));
+ }).sneakyThrow()));
}
private Mono<List<MessageAttachmentMetadata>> storeAttachments(MessageId messageId, Content messageContent, Optional<Message> maybeMessage, MailboxSession session) {
@@ -141,7 +145,7 @@ public interface MessageStorer {
/**
* MessageStorer that does not parse, store, nor return Attachment metadata
- *
+ * <p>
* To be used when the underlying implementation does not support attachment storage.
*/
class WithoutAttachment implements MessageStorer {
@@ -149,12 +153,14 @@ public interface MessageStorer {
private final MessageId.Factory messageIdFactory;
private final MessageFactory messageFactory;
private final ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm;
+ private final Clock clock;
- public WithoutAttachment(MailboxSessionMapperFactory mapperFactory, MessageId.Factory messageIdFactory, MessageFactory messageFactory, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm) {
+ public WithoutAttachment(MailboxSessionMapperFactory mapperFactory, MessageId.Factory messageIdFactory, MessageFactory messageFactory, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm, Clock clock) {
this.mapperFactory = mapperFactory;
this.messageIdFactory = messageIdFactory;
this.messageFactory = messageFactory;
this.threadIdGuessingAlgorithm = threadIdGuessingAlgorithm;
+ this.clock = clock;
}
@Override
@@ -169,7 +175,9 @@ public interface MessageStorer {
return mapperFactory.getMessageMapper(session)
.executeReactive(threadIdGuessingAlgorithm.guessThreadIdReactive(messageId, mimeMessageId, inReplyTo, references, subject, session)
.flatMap(Throwing.function((ThreadId threadId) -> {
- MailboxMessage message = messageFactory.createMessage(messageId, threadId, mailbox, internalDate, size, bodyStartOctet, content, flags, propertyBuilder, ImmutableList.of());
+ Date saveDate = Date.from(clock.instant());
+
+ MailboxMessage message = messageFactory.createMessage(messageId, threadId, mailbox, internalDate, saveDate, size, bodyStartOctet, content, flags, propertyBuilder, ImmutableList.of());
return Mono.from(messageMapper.addReactive(mailbox, message))
.map(metadata -> Pair.of(metadata, Optional.empty()));
})));
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
index 9577ac410a..8d374d587a 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
@@ -22,6 +22,7 @@ package org.apache.james.mailbox.store;
import static org.apache.james.mailbox.store.MailboxReactorUtils.block;
import static org.apache.james.mailbox.store.mail.AbstractMessageMapper.UNLIMITED;
+import java.time.Clock;
import java.time.Duration;
import java.util.EnumSet;
import java.util.List;
@@ -132,14 +133,15 @@ public class StoreMailboxManager implements MailboxManager {
private final PreDeletionHooks preDeletionHooks;
protected final MailboxManagerConfiguration configuration;
private final ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm;
+ private final Clock clock;
@Inject
public StoreMailboxManager(MailboxSessionMapperFactory mailboxSessionMapperFactory, SessionProvider sessionProvider,
MailboxPathLocker locker, MessageParser messageParser,
- MessageId.Factory messageIdFactory, MailboxAnnotationManager annotationManager,
+ Factory messageIdFactory, MailboxAnnotationManager annotationManager,
EventBus eventBus, StoreRightManager storeRightManager,
QuotaComponents quotaComponents, MessageSearchIndex searchIndex, MailboxManagerConfiguration configuration,
- PreDeletionHooks preDeletionHooks, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm) {
+ PreDeletionHooks preDeletionHooks, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm, Clock clock) {
Preconditions.checkNotNull(eventBus);
Preconditions.checkNotNull(mailboxSessionMapperFactory);
@@ -158,6 +160,7 @@ public class StoreMailboxManager implements MailboxManager {
this.configuration = configuration;
this.preDeletionHooks = preDeletionHooks;
this.threadIdGuessingAlgorithm = threadIdGuessingAlgorithm;
+ this.clock = clock;
}
public QuotaComponents getQuotaComponents() {
@@ -231,6 +234,10 @@ public class StoreMailboxManager implements MailboxManager {
return threadIdGuessingAlgorithm;
}
+ public Clock getClock() {
+ return clock;
+ }
+
@Override
public MailboxSession createSystemSession(Username userName) {
return sessionProvider.createSystemSession(userName);
@@ -271,7 +278,7 @@ public class StoreMailboxManager implements MailboxManager {
return new StoreMessageManager(DEFAULT_NO_MESSAGE_CAPABILITIES, getMapperFactory(), getMessageSearchIndex(), getEventBus(),
getLocker(), mailbox, quotaManager,
getQuotaComponents().getQuotaRootResolver(), configuration.getBatchSizes(),
- getStoreRightManager(), preDeletionHooks, new MessageStorer.WithoutAttachment(mailboxSessionMapperFactory, messageIdFactory, new MessageFactory.StoreMessageFactory(), threadIdGuessingAlgorithm));
+ getStoreRightManager(), preDeletionHooks, new MessageStorer.WithoutAttachment(mailboxSessionMapperFactory, messageIdFactory, new MessageFactory.StoreMessageFactory(), threadIdGuessingAlgorithm, clock));
}
@Override
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
index 4cefb617ca..3d25e3507f 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
@@ -289,6 +289,7 @@ public interface MessageMapper extends Mapper {
* {@link MailboxMessage#getBodyOctets()}
* {@link MailboxMessage#getFullContentOctets()}
* {@link MailboxMessage#getInternalDate()}
+ * {@link MailboxMessage#getSaveDate()}
* {@link MailboxMessage#getMailboxId()}
* {@link MailboxMessage#getMediaType()}
* {@link MailboxMessage#getModSeq()}
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java
index 94fa44dd3d..dc41398a47 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java
@@ -113,6 +113,7 @@ public abstract class DelegatingMailboxMessage implements MailboxMessage {
return message.getMessageId();
}
+ @Override
public ThreadId getThreadId() {
return new ThreadId(message.getMessageId());
}
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/MailboxMessage.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/MailboxMessage.java
index a5d89b0503..6bfd3efa1f 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/MailboxMessage.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/MailboxMessage.java
@@ -18,6 +18,9 @@
****************************************************************/
package org.apache.james.mailbox.store.mail.model;
+import java.util.Date;
+import java.util.Optional;
+
import javax.mail.Flags;
import org.apache.james.mailbox.MessageUid;
@@ -36,6 +39,8 @@ import org.apache.james.mailbox.model.ThreadId;
*/
public interface MailboxMessage extends Message, Comparable<MailboxMessage> {
+ Optional<Date> EMPTY_SAVE_DATE = Optional.empty();
+
ThreadId getThreadId();
ComposedMessageIdWithMetaData getComposedMessageIdWithMetaData();
@@ -120,4 +125,6 @@ public interface MailboxMessage extends Message, Comparable<MailboxMessage> {
}
MailboxMessage copy(Mailbox mailbox) throws MailboxException;
+
+ Optional<Date> getSaveDate();
}
\ No newline at end of file
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java
index c611139539..e5caaa9bef 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java
@@ -43,6 +43,7 @@ import org.apache.james.mailbox.model.ThreadId;
import org.apache.james.mailbox.store.mail.model.DelegatingMailboxMessage;
import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
@@ -59,6 +60,7 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
private MessageId messageId;
private ThreadId threadId;
private Date internalDate;
+ private Optional<Date> saveDate = Optional.empty();
private Long size;
private Integer bodyStartOctet;
private Content content;
@@ -94,6 +96,16 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
return this;
}
+ public Builder saveDate(Date saveDate) {
+ this.saveDate = Optional.ofNullable(saveDate);
+ return this;
+ }
+
+ public Builder saveDate(Optional<Date> saveDate) {
+ this.saveDate = saveDate;
+ return this;
+ }
+
public Builder size(long size) {
Preconditions.checkArgument(size >= 0, "size can not be negative");
this.size = size;
@@ -149,7 +161,7 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
ImmutableList<MessageAttachmentMetadata> attachments = this.attachments.build();
SimpleMailboxMessage simpleMailboxMessage = new SimpleMailboxMessage(messageId, threadId, internalDate, size,
- bodyStartOctet, content, flags, properties, mailboxId, attachments);
+ bodyStartOctet, content, flags, properties, mailboxId, attachments, saveDate);
uid.ifPresent(simpleMailboxMessage::setUid);
modseq.ifPresent(simpleMailboxMessage::setModSeq);
@@ -174,6 +186,7 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
.content(copyFullContent(original))
.messageId(original.getMessageId())
.internalDate(original.getInternalDate())
+ .saveDate(original.getSaveDate())
.size(original.getFullContentOctets())
.flags(original.createFlags())
.properties(original.getProperties());
@@ -195,6 +208,7 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
private MessageUid uid;
private final MailboxId mailboxId;
private final ThreadId threadId;
+ private final Optional<Date> saveDate;
private boolean answered;
private boolean deleted;
private boolean draft;
@@ -206,7 +220,7 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
public SimpleMailboxMessage(MessageId messageId, ThreadId threadId, Date internalDate, long size, int bodyStartOctet,
Content content, Flags flags,
- Properties properties, MailboxId mailboxId, List<MessageAttachmentMetadata> attachments) {
+ Properties properties, MailboxId mailboxId, List<MessageAttachmentMetadata> attachments, Optional<Date> saveDate) {
super(new SimpleMessage(
messageId,
content, size, internalDate,
@@ -215,17 +229,19 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
properties,
attachments));
- setFlags(flags);
- this.mailboxId = mailboxId;
- this.threadId = threadId;
+ setFlags(flags);
+ this.mailboxId = mailboxId;
+ this.threadId = threadId;
+ this.saveDate = saveDate;
}
+ @VisibleForTesting
public SimpleMailboxMessage(MessageId messageId, ThreadId threadId, Date internalDate, long size, int bodyStartOctet,
Content content, Flags flags,
Properties properties, MailboxId mailboxId) {
this(messageId, threadId, internalDate, size, bodyStartOctet,
content, flags,
- properties, mailboxId, ImmutableList.of());
+ properties, mailboxId, ImmutableList.of(), EMPTY_SAVE_DATE);
}
@Override
@@ -303,6 +319,11 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
this.uid = uid;
}
+ @Override
+ public Optional<Date> getSaveDate() {
+ return saveDate;
+ }
+
@Override
public synchronized void setFlags(Flags flags) {
answered = flags.contains(Flags.Flag.ANSWERED);
@@ -333,6 +354,7 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
.add("uid", this.uid)
.add("mailboxId", this.mailboxId)
.add("threadId", this.threadId)
+ .add("saveDate", this.saveDate)
.add("answered", this.answered)
.add("deleted", this.deleted)
.add("draft", this.draft)
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageBuilder.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageBuilder.java
index 79eecaadcd..91de349a16 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageBuilder.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageBuilder.java
@@ -26,6 +26,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import java.util.Optional;
import javax.mail.Flags;
@@ -50,6 +51,7 @@ public class MessageBuilder {
private TestId mailboxId = TestId.of(113);
private MessageUid uid = MessageUid.of(776);
private Date internalDate = new Date();
+ private Optional<Date> saveDate = Optional.of(new Date());
private int size = 8867;
private Flags flags = new Flags();
private byte[] body = {};
@@ -83,7 +85,7 @@ public class MessageBuilder {
byte[] headerContent = getHeaderContent();
ThreadId threadId = ThreadId.fromBaseMessageId(messageId);
SimpleMailboxMessage mailboxMessage = new SimpleMailboxMessage(messageId, threadId, internalDate, size, headerContent.length,
- new ByteContent(Bytes.concat(headerContent, body)), flags, new PropertyBuilder().build(), mailboxId, NO_ATTACHMENTS);
+ new ByteContent(Bytes.concat(headerContent, body)), flags, new PropertyBuilder().build(), mailboxId, NO_ATTACHMENTS, saveDate);
mailboxMessage.setUid(uid);
return mailboxMessage;
}
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java
index f6fbfa3442..8ac2b58d86 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java
@@ -25,6 +25,8 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.time.Instant;
+
import org.apache.james.core.Username;
import org.apache.james.events.InVMEventBus;
import org.apache.james.events.MemoryEventDeadLetters;
@@ -36,9 +38,9 @@ import org.apache.james.mailbox.MailboxSessionUtil;
import org.apache.james.mailbox.MessageManager;
import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
import org.apache.james.mailbox.exception.BadCredentialsException;
+import org.apache.james.mailbox.exception.ForbiddenDelegationException;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.MailboxNotFoundException;
-import org.apache.james.mailbox.exception.ForbiddenDelegationException;
import org.apache.james.mailbox.exception.UserDoesNotExistException;
import org.apache.james.mailbox.model.Mailbox;
import org.apache.james.mailbox.model.MailboxACL;
@@ -58,6 +60,7 @@ import org.apache.james.mailbox.store.quota.QuotaComponents;
import org.apache.james.mailbox.store.search.MessageSearchIndex;
import org.apache.james.mailbox.store.search.SimpleMessageSearchIndex;
import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.utils.UpdatableTickingClock;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -110,7 +113,7 @@ class StoreMailboxManagerTest {
storeMailboxManager = new StoreMailboxManager(mockedMapperFactory, sessionProvider,
new JVMMailboxPathLocker(), new MessageParser(), messageIdFactory,
annotationManager, eventBus, storeRightManager, quotaComponents, index, MailboxManagerConfiguration.DEFAULT,
- PreDeletionHooks.NO_PRE_DELETION_HOOK, threadIdGuessingAlgorithm);
+ PreDeletionHooks.NO_PRE_DELETION_HOOK, threadIdGuessingAlgorithm, new UpdatableTickingClock(Instant.now()));
}
@Test
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageWithAttachmentMapperTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageWithAttachmentMapperTest.java
index 42d66e0098..c39bba5e45 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageWithAttachmentMapperTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageWithAttachmentMapperTest.java
@@ -19,6 +19,7 @@
package org.apache.james.mailbox.store.mail.model;
+import static org.apache.james.mailbox.store.mail.model.MailboxMessage.EMPTY_SAVE_DATE;
import static org.apache.james.mailbox.store.mail.model.MessageAssert.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
@@ -181,7 +182,7 @@ public abstract class MessageWithAttachmentMapperTest {
}
private SimpleMailboxMessage createMessage(Mailbox mailbox, MessageId messageId, ThreadId threadId, String content, int bodyStart, PropertyBuilder propertyBuilder, List<MessageAttachmentMetadata> attachments) {
- return new SimpleMailboxMessage(messageId, threadId, new Date(), content.length(), bodyStart, new ByteContent(content.getBytes()), new Flags(), propertyBuilder.build(), mailbox.getMailboxId(), attachments);
+ return new SimpleMailboxMessage(messageId, threadId, new Date(), content.length(), bodyStart, new ByteContent(content.getBytes()), new Flags(), propertyBuilder.build(), mailbox.getMailboxId(), attachments, EMPTY_SAVE_DATE);
}
private SimpleMailboxMessage createMessage(Mailbox mailbox, MessageId messageId, ThreadId threadId, String content, int bodyStart, PropertyBuilder propertyBuilder) {
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessageTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessageTest.java
index 217009043d..4f4ed98701 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessageTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessageTest.java
@@ -19,6 +19,7 @@
package org.apache.james.mailbox.store.mail.model.impl;
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 java.io.IOException;
@@ -26,6 +27,8 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.Date;
+import java.util.List;
+import java.util.Optional;
import javax.mail.Flags;
@@ -43,6 +46,7 @@ import org.apache.james.mailbox.model.TestId;
import org.apache.james.mailbox.model.TestMessageId;
import org.apache.james.mailbox.model.ThreadId;
import org.apache.james.mailbox.store.mail.model.DefaultMessageId;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -113,13 +117,16 @@ class SimpleMailboxMessageTest {
propertyBuilder.setSubType(plain);
MessageId messageId = new TestMessageId.Factory().generate();
ThreadId threadId = ThreadId.fromBaseMessageId(messageId);
+ Optional<Date> saveDate = Optional.of(new Date());
SimpleMailboxMessage original = new SimpleMailboxMessage(messageId, threadId, new Date(),
MESSAGE_CONTENT.length(),
BODY_START_OCTET,
CONTENT_STREAM,
new Flags(),
propertyBuilder.build(),
- TEST_ID);
+ TEST_ID,
+ List.of(),
+ saveDate);
SimpleMailboxMessage copy = SimpleMailboxMessage.copy(TestId.of(1337), original);
@@ -132,7 +139,7 @@ class SimpleMailboxMessageTest {
assertThat(SimpleMailboxMessage.copy(TEST_ID, original).getTextualLineCount()).isEqualTo(textualLineCount);
assertThat(SimpleMailboxMessage.copy(TEST_ID, original).getMediaType()).isEqualTo(text);
assertThat(SimpleMailboxMessage.copy(TEST_ID, original).getSubType()).isEqualTo(plain);
-
+ assertThat(SimpleMailboxMessage.copy(TEST_ID, original).getSaveDate()).isEqualTo(saveDate);
}
private static SimpleMailboxMessage buildMessage(String content) {
@@ -254,6 +261,22 @@ class SimpleMailboxMessageTest {
.isInstanceOf(NullPointerException.class);
}
+ @Test
+ void buildShouldNotThrowOnMissingSaveDate() {
+ assertThatCode(() -> SimpleMailboxMessage.builder()
+ .messageId(MESSAGE_ID)
+ .mailboxId(TEST_ID)
+ .threadId(THREAD_ID)
+ .internalDate(new Date())
+ .bodyStartOctet(BODY_START_OCTET)
+ .size(SIZE)
+ .content(CONTENT_STREAM)
+ .flags(new Flags())
+ .properties(new PropertyBuilder())
+ .build())
+ .doesNotThrowAnyException();
+ }
+
@Test
void buildShouldThrowOnMissingMailboxId() {
Date internalDate = new Date();
@@ -370,4 +393,40 @@ class SimpleMailboxMessageTest {
assertThat(message.getThreadId().getBaseMessageId()).isInstanceOf(MessageId.class);
}
+ @Test
+ void simpleMessageShouldReturnSaveDateWhenEmpty() {
+ MailboxMessage mailboxMessage = SimpleMailboxMessage.builder()
+ .messageId(MESSAGE_ID)
+ .mailboxId(TEST_ID)
+ .threadId(THREAD_ID)
+ .internalDate(new Date())
+ .bodyStartOctet(BODY_START_OCTET)
+ .size(SIZE)
+ .content(CONTENT_STREAM)
+ .flags(new Flags())
+ .properties(new PropertyBuilder())
+ .build();
+
+ assertThat(mailboxMessage.getSaveDate()).isEmpty();
+ }
+
+ @Test
+ void simpleMessageShouldReturnSaveDate() {
+ Optional<Date> saveDate = Optional.of(new Date());
+ MailboxMessage mailboxMessage = SimpleMailboxMessage.builder()
+ .messageId(MESSAGE_ID)
+ .mailboxId(TEST_ID)
+ .threadId(THREAD_ID)
+ .internalDate(new Date())
+ .saveDate(saveDate)
+ .bodyStartOctet(BODY_START_OCTET)
+ .size(SIZE)
+ .content(CONTENT_STREAM)
+ .flags(new Flags())
+ .properties(new PropertyBuilder())
+ .build();
+
+ assertThat(mailboxMessage.getSaveDate()).isEqualTo(saveDate);
+ }
+
}
diff --git a/mpt/impl/imap-mailbox/cassandra/pom.xml b/mpt/impl/imap-mailbox/cassandra/pom.xml
index d50eb2454b..2d0ef3d317 100644
--- a/mpt/impl/imap-mailbox/cassandra/pom.xml
+++ b/mpt/impl/imap-mailbox/cassandra/pom.xml
@@ -76,6 +76,11 @@
<artifactId>event-bus-in-vm</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>james-server-testing</artifactId>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>metrics-tests</artifactId>
diff --git a/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java b/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
index e9b7b3c789..055718d03e 100644
--- a/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
+++ b/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
@@ -18,6 +18,8 @@
****************************************************************/
package org.apache.james.mpt.imapmailbox.cassandra.host;
+import java.time.Instant;
+
import org.apache.james.backends.cassandra.CassandraCluster;
import org.apache.james.core.quota.QuotaCountLimit;
import org.apache.james.core.quota.QuotaSizeLimit;
@@ -65,6 +67,7 @@ import org.apache.james.metrics.tests.RecordingMetricFactory;
import org.apache.james.mpt.api.ImapFeatures;
import org.apache.james.mpt.api.ImapFeatures.Feature;
import org.apache.james.mpt.host.JamesImapHostSystem;
+import org.apache.james.utils.UpdatableTickingClock;
import com.datastax.oss.driver.api.core.CqlSession;
@@ -95,6 +98,7 @@ public class CassandraHostSystem extends JamesImapHostSystem {
CqlSession session = cassandra.getConf();
CassandraMessageId.Factory messageIdFactory = new CassandraMessageId.Factory();
ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm = new NaiveThreadIdGuessingAlgorithm();
+ UpdatableTickingClock clock = new UpdatableTickingClock(Instant.now());
CassandraMailboxSessionMapperFactory mapperFactory = TestCassandraMailboxSessionMapperFactory.forTests(
cassandra, messageIdFactory);
@@ -123,7 +127,7 @@ public class CassandraHostSystem extends JamesImapHostSystem {
mailboxManager = new CassandraMailboxManager(mapperFactory, sessionProvider,
new JVMMailboxPathLocker(), new MessageParser(), messageIdFactory,
eventBus, annotationManager, storeRightManager, quotaComponents, index, MailboxManagerConfiguration.DEFAULT,
- PreDeletionHooks.NO_PRE_DELETION_HOOK, threadIdGuessingAlgorithm);
+ PreDeletionHooks.NO_PRE_DELETION_HOOK, threadIdGuessingAlgorithm, clock);
eventBus.register(quotaUpdater);
diff --git a/mpt/impl/imap-mailbox/jpa/pom.xml b/mpt/impl/imap-mailbox/jpa/pom.xml
index 2a51980556..64553eea5f 100644
--- a/mpt/impl/imap-mailbox/jpa/pom.xml
+++ b/mpt/impl/imap-mailbox/jpa/pom.xml
@@ -74,6 +74,11 @@
<artifactId>event-bus-in-vm</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>james-server-testing</artifactId>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>metrics-tests</artifactId>
diff --git a/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/host/JPAHostSystem.java b/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/host/JPAHostSystem.java
index 4ef7a4fa78..f2ecfd6b74 100644
--- a/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/host/JPAHostSystem.java
+++ b/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/host/JPAHostSystem.java
@@ -19,6 +19,8 @@
package org.apache.james.mpt.imapmailbox.jpa.host;
+import java.time.Instant;
+
import javax.persistence.EntityManagerFactory;
import org.apache.james.backends.jpa.JpaTestCluster;
@@ -65,6 +67,7 @@ import org.apache.james.metrics.tests.RecordingMetricFactory;
import org.apache.james.mpt.api.ImapFeatures;
import org.apache.james.mpt.api.ImapFeatures.Feature;
import org.apache.james.mpt.host.JamesImapHostSystem;
+import org.apache.james.utils.UpdatableTickingClock;
import com.google.common.collect.ImmutableList;
@@ -116,7 +119,7 @@ public class JPAHostSystem extends JamesImapHostSystem {
MessageSearchIndex index = new SimpleMessageSearchIndex(mapperFactory, mapperFactory, new DefaultTextExtractor(), attachmentContentLoader);
mailboxManager = new OpenJPAMailboxManager(mapperFactory, sessionProvider, messageParser, new DefaultMessageId.Factory(),
- eventBus, annotationManager, storeRightManager, quotaComponents, index, new NaiveThreadIdGuessingAlgorithm());
+ eventBus, annotationManager, storeRightManager, quotaComponents, index, new NaiveThreadIdGuessingAlgorithm(), new UpdatableTickingClock(Instant.now()));
eventBus.register(quotaUpdater);
eventBus.register(new MailboxAnnotationListener(mapperFactory, sessionProvider));
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org