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:49 UTC
[james-project] 06/08: JAMES-3754 Mapper layers should set new saveDate when add/copy/move messages
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 746ca874aecfb5ea77679a081a32999471bbbce7
Author: Quan Tran <hq...@linagora.com>
AuthorDate: Thu Dec 1 17:35:58 2022 +0700
JAMES-3754 Mapper layers should set new saveDate when add/copy/move messages
---
.../CassandraMailboxSessionMapperFactory.java | 9 +-
.../mailbox/cassandra/mail/AttachmentLoader.java | 5 +-
.../cassandra/mail/CassandraMessageIdMapper.java | 10 ++-
.../cassandra/mail/CassandraMessageMapper.java | 24 ++++--
.../cassandra/mail/CassandraMessageMetadata.java | 5 ++
.../cassandra/mail/MessageRepresentation.java | 4 +-
.../CassandraSubscriptionManagerTest.java | 5 +-
.../TestCassandraMailboxSessionMapperFactory.java | 13 +++
.../cassandra/mail/CassandraMapperProvider.java | 14 +++-
...andraMessageIdMapperRelaxedConsistencyTest.java | 39 ++++++---
.../mail/CassandraMessageIdMapperTest.java | 16 +++-
...ssandraMessageMapperRelaxedConsistencyTest.java | 39 ++++++---
.../cassandra/mail/CassandraMessageMapperTest.java | 16 +++-
.../mailbox/cassandra/mail/utils/GuiceUtils.java | 4 +-
.../model/openjpa/AbstractJPAMailboxMessage.java | 5 ++
.../mailbox/jpa/mail/JpaMessageMapperTest.java | 16 +++-
.../InMemoryMailboxSessionMapperFactory.java | 6 +-
.../inmemory/mail/InMemoryMessageMapper.java | 7 +-
.../inmemory/mail/InMemoryMapperProvider.java | 9 +-
.../inmemory/mail/InMemoryMessageIdMapperTest.java | 9 +-
.../inmemory/mail/MemoryMessageMapperTest.java | 10 ++-
.../manager/InMemoryIntegrationResources.java | 4 +-
.../OpenSearchListeningMessageSearchIndexTest.java | 6 +-
.../mailbox/store/mail/AbstractMessageMapper.java | 5 +-
.../mailbox/store/mail/model/MailboxMessage.java | 2 +
.../mail/model/impl/SimpleMailboxMessage.java | 7 +-
.../store/mail/model/MessageIdMapperTest.java | 51 ++++++++++++
.../store/mail/model/MessageMapperTest.java | 96 ++++++++++++++++++++++
28 files changed, 370 insertions(+), 66 deletions(-)
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
index 4e57852f88..22e150af51 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java
@@ -19,6 +19,8 @@
package org.apache.james.mailbox.cassandra;
+import java.time.Clock;
+
import javax.inject.Inject;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
@@ -106,7 +108,8 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa
CassandraUserMailboxRightsDAO userMailboxRightsDAO,
RecomputeMailboxCountersService recomputeMailboxCountersService,
CassandraConfiguration cassandraConfiguration,
- BatchSizes batchSizes) {
+ BatchSizes batchSizes,
+ Clock clock) {
this.uidProvider = uidProvider;
this.modSeqProvider = modSeqProvider;
this.threadDAO = threadDAO;
@@ -150,10 +153,10 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa
firstUnseenDAO,
deletedMessageDAO,
blobStore,
- cassandraConfiguration, batchSizes, recomputeMailboxCountersService);
+ cassandraConfiguration, batchSizes, recomputeMailboxCountersService, clock);
this.cassandraMessageIdMapper = new CassandraMessageIdMapper(cassandraMailboxMapper, mailboxDAO,
cassandraAttachmentMapper, imapUidDAO, messageIdDAO, messageDAO, messageDAOV3, indexTableHandler,
- modSeqProvider, blobStore, cassandraConfiguration, batchSizes);
+ modSeqProvider, blobStore, cassandraConfiguration, batchSizes, clock);
this.cassandraAnnotationMapper = new CassandraAnnotationMapper(session);
}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoader.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoader.java
index 4d1a4f77c8..f37267caa2 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoader.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/AttachmentLoader.java
@@ -18,7 +18,9 @@
****************************************************************/
package org.apache.james.mailbox.cassandra.mail;
+import java.util.Date;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Stream;
import org.apache.commons.lang3.tuple.Pair;
@@ -43,9 +45,10 @@ public class AttachmentLoader {
}
public Mono<CassandraMailboxMessage> addAttachmentToMessage(Pair<ComposedMessageIdWithMetaData, MessageRepresentation> messageRepresentation,
+ Optional<Date> saveDate,
MessageMapper.FetchType fetchType) {
return loadAttachments(messageRepresentation.getRight().getAttachments().stream(), fetchType)
- .map(attachments -> messageRepresentation.getRight().toMailboxMessage(messageRepresentation.getLeft(), attachments))
+ .map(attachments -> messageRepresentation.getRight().toMailboxMessage(messageRepresentation.getLeft(), attachments, saveDate))
.map(message -> new CassandraMailboxMessage(message, messageRepresentation.getRight().getHeaderId()));
}
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
index 39bf53c626..9b2b7dd7af 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java
@@ -23,8 +23,10 @@ import static org.apache.james.backends.cassandra.init.configuration.JamesExecut
import static org.apache.james.blob.api.BlobStore.StoragePolicy.SIZE_BASED;
import static org.apache.james.util.ReactorUtils.DEFAULT_CONCURRENCY;
+import java.time.Clock;
import java.time.Duration;
import java.util.Collection;
+import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
@@ -90,11 +92,12 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
private final BlobStore blobStore;
private final CassandraConfiguration cassandraConfiguration;
private final BatchSizes batchSizes;
+ private final Clock clock;
public CassandraMessageIdMapper(MailboxMapper mailboxMapper, CassandraMailboxDAO mailboxDAO, CassandraAttachmentMapper attachmentMapper,
CassandraMessageIdToImapUidDAO imapUidDAO, CassandraMessageIdDAO messageIdDAO,
CassandraMessageDAO messageDAO, CassandraMessageDAOV3 messageDAOV3, CassandraIndexTableHandler indexTableHandler,
- ModSeqProvider modSeqProvider, BlobStore blobStore, CassandraConfiguration cassandraConfiguration, BatchSizes batchSizes) {
+ ModSeqProvider modSeqProvider, BlobStore blobStore, CassandraConfiguration cassandraConfiguration, BatchSizes batchSizes, Clock clock) {
this.mailboxMapper = mailboxMapper;
this.mailboxDAO = mailboxDAO;
@@ -108,6 +111,7 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
this.blobStore = blobStore;
this.cassandraConfiguration = cassandraConfiguration;
this.batchSizes = batchSizes;
+ this.clock = clock;
}
@Override
@@ -138,7 +142,7 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
return messageDAOV3.retrieveMessage(metadata.getComposedMessageId(), fetchType)
.switchIfEmpty(Mono.defer(() -> messageDAO.retrieveMessage(metadata.getComposedMessageId(), fetchType)))
.map(messageRepresentation -> Pair.of(metadata.getComposedMessageId(), messageRepresentation))
- .flatMap(messageRepresentation -> attachmentLoader.addAttachmentToMessage(messageRepresentation, fetchType));
+ .flatMap(messageRepresentation -> attachmentLoader.addAttachmentToMessage(messageRepresentation, metadata.getSaveDate(), fetchType));
}
@Override
@@ -187,6 +191,7 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
@Override
public void save(MailboxMessage mailboxMessage) throws MailboxException {
CassandraId mailboxId = (CassandraId) mailboxMessage.getMailboxId();
+ mailboxMessage.setSaveDate(Date.from(clock.instant()));
MailboxReactorUtils.block(mailboxMapper.findMailboxById(mailboxId)
.switchIfEmpty(Mono.error(() -> new MailboxNotFoundException(mailboxId)))
.then(messageDAOV3.save(mailboxMessage))
@@ -200,6 +205,7 @@ public class CassandraMessageIdMapper implements MessageIdMapper {
@Override
public Mono<Void> copyInMailboxReactive(MailboxMessage mailboxMessage, Mailbox mailbox) {
+ mailboxMessage.setSaveDate(Date.from(clock.instant()));
CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
return insertMetadata(mailboxMessage, mailboxId, CassandraMessageMetadata.from(mailboxMessage)
.withMailboxId(mailboxId));
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
index ae473652a4..5f6924ae0b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
@@ -25,9 +25,11 @@ import static org.apache.james.blob.api.BlobStore.StoragePolicy.SIZE_BASED;
import static org.apache.james.util.ReactorUtils.DEFAULT_CONCURRENCY;
import java.security.SecureRandom;
+import java.time.Clock;
import java.time.Duration;
import java.util.Collection;
import java.util.Comparator;
+import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -110,6 +112,7 @@ public class CassandraMessageMapper implements MessageMapper {
private final RecomputeMailboxCountersService recomputeMailboxCountersService;
private final SecureRandom secureRandom;
private final int reactorConcurrency;
+ private final Clock clock;
public CassandraMessageMapper(UidProvider uidProvider, ModSeqProvider modSeqProvider,
CassandraAttachmentMapper attachmentMapper,
@@ -118,7 +121,7 @@ public class CassandraMessageMapper implements MessageMapper {
CassandraMailboxRecentsDAO mailboxRecentDAO, CassandraApplicableFlagDAO applicableFlagDAO,
CassandraIndexTableHandler indexTableHandler, CassandraFirstUnseenDAO firstUnseenDAO,
CassandraDeletedMessageDAO deletedMessageDAO, BlobStore blobStore, CassandraConfiguration cassandraConfiguration,
- BatchSizes batchSizes, RecomputeMailboxCountersService recomputeMailboxCountersService) {
+ BatchSizes batchSizes, RecomputeMailboxCountersService recomputeMailboxCountersService, Clock clock) {
this.uidProvider = uidProvider;
this.modSeqProvider = modSeqProvider;
this.messageDAO = messageDAO;
@@ -138,6 +141,7 @@ public class CassandraMessageMapper implements MessageMapper {
this.recomputeMailboxCountersService = recomputeMailboxCountersService;
this.secureRandom = new SecureRandom();
this.reactorConcurrency = evaluateReactorConcurrency();
+ this.clock = clock;
}
@Override
@@ -273,7 +277,7 @@ public class CassandraMessageMapper implements MessageMapper {
return messageDAOV3.retrieveMessage(metadata.getComposedMessageId(), fetchType)
.switchIfEmpty(Mono.defer(() -> messageDAO.retrieveMessage(metadata.getComposedMessageId(), fetchType)))
.map(messageRepresentation -> Pair.of(metadata.getComposedMessageId(), messageRepresentation))
- .flatMap(messageRepresentation -> attachmentLoader.addAttachmentToMessage(messageRepresentation, fetchType));
+ .flatMap(messageRepresentation -> attachmentLoader.addAttachmentToMessage(messageRepresentation, metadata.getSaveDate(), fetchType));
}
@Override
@@ -333,18 +337,17 @@ public class CassandraMessageMapper implements MessageMapper {
return Flux.fromIterable(MessageRange.toRanges(uids))
.concatMap(range -> messageIdDAO.retrieveMessages(mailboxId, range, Limit.unlimited()))
- .map(CassandraMessageMetadata::getComposedMessageId)
- .flatMap(this::expungeOne, cassandraConfiguration.getExpungeChunkSize())
+ .flatMap(cassandraMessageMetadata -> expungeOne(cassandraMessageMetadata.getComposedMessageId(), cassandraMessageMetadata.getSaveDate()), cassandraConfiguration.getExpungeChunkSize())
.collect(ImmutableMap.toImmutableMap(MailboxMessage::getUid, MailboxMessage::metaData))
.flatMap(messageMap -> indexTableHandler.updateIndexOnDelete(mailboxId, messageMap.values())
.thenReturn(messageMap));
}
- private Mono<SimpleMailboxMessage> expungeOne(ComposedMessageIdWithMetaData metaData) {
+ private Mono<SimpleMailboxMessage> expungeOne(ComposedMessageIdWithMetaData metaData, Optional<Date> saveDate) {
return delete(metaData)
.then(messageDAOV3.retrieveMessage(metaData, FetchType.METADATA)
.switchIfEmpty(Mono.defer(() -> messageDAO.retrieveMessage(metaData, FetchType.METADATA))))
- .map(pair -> pair.toMailboxMessage(metaData, ImmutableList.of()));
+ .map(pair -> pair.toMailboxMessage(metaData, ImmutableList.of(), saveDate));
}
@Override
@@ -401,14 +404,14 @@ public class CassandraMessageMapper implements MessageMapper {
public Mono<MessageMetaData> addReactive(Mailbox mailbox, MailboxMessage message) {
CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
- return addUidAndModseq(message, mailboxId)
+ return addUidAndModseqAndSaveDate(message, mailboxId)
.flatMap(Throwing.function((MailboxMessage messageWithUidAndModSeq) ->
save(mailbox, messageWithUidAndModSeq)
.thenReturn(messageWithUidAndModSeq)))
.map(MailboxMessage::metaData);
}
- private Mono<MailboxMessage> addUidAndModseq(MailboxMessage message, CassandraId mailboxId) {
+ private Mono<MailboxMessage> addUidAndModseqAndSaveDate(MailboxMessage message, CassandraId mailboxId) {
Mono<MessageUid> messageUidMono = uidProvider
.nextUidReactive(mailboxId)
.switchIfEmpty(Mono.error(() -> new MailboxException("Can not find a UID to save " + message.getMessageId() + " in " + mailboxId)));
@@ -420,6 +423,7 @@ public class CassandraMessageMapper implements MessageMapper {
.doOnNext(tuple -> {
message.setUid(tuple.getT1());
message.setModSeq(tuple.getT2());
+ message.setSaveDate(Date.from(clock.instant()));
})
.thenReturn(message);
}
@@ -545,6 +549,7 @@ public class CassandraMessageMapper implements MessageMapper {
@Override
public Mono<MessageMetaData> copyReactive(Mailbox mailbox, MailboxMessage original) {
original.setFlags(new FlagsBuilder().add(original.createFlags()).add(Flag.RECENT).build());
+ original.setSaveDate(Date.from(clock.instant()));
return setInMailboxReactive(mailbox, original);
}
@@ -556,6 +561,7 @@ public class CassandraMessageMapper implements MessageMapper {
return setMessagesInMailboxReactive(mailbox, originals.stream()
.map(original -> {
original.setFlags(new FlagsBuilder().add(original.createFlags()).add(Flag.RECENT).build());
+ original.setSaveDate(Date.from(clock.instant()));
return original;
}).collect(ImmutableList.toImmutableList()))
.collectList();
@@ -584,7 +590,7 @@ public class CassandraMessageMapper implements MessageMapper {
private Mono<MessageMetaData> setInMailboxReactive(Mailbox mailbox, MailboxMessage message) {
CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
- return addUidAndModseq(message, mailboxId)
+ return addUidAndModseqAndSaveDate(message, mailboxId)
.flatMap(messageWithUidAndModseq ->
insertMetadata(messageWithUidAndModseq, mailboxId,
CassandraMessageMetadata.from(messageWithUidAndModseq)
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 0e34163bf5..ebc9436315 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
@@ -203,6 +203,11 @@ public class CassandraMessageMetadata {
delegate.setFlags(flags);
}
+ @Override
+ public void setSaveDate(Date saveDate) {
+ delegate.setSaveDate(saveDate);
+ }
+
@Override
public Flags createFlags() {
return delegate.createFlags();
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/MessageRepresentation.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/MessageRepresentation.java
index 39cada4b95..025e1b2bf9 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/MessageRepresentation.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/MessageRepresentation.java
@@ -21,6 +21,7 @@ package org.apache.james.mailbox.cassandra.mail;
import java.util.Date;
import java.util.List;
+import java.util.Optional;
import org.apache.james.blob.api.BlobId;
import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
@@ -54,7 +55,7 @@ public class MessageRepresentation {
this.bodyId = bodyId;
}
- public SimpleMailboxMessage toMailboxMessage(ComposedMessageIdWithMetaData metadata, List<MessageAttachmentMetadata> attachments) {
+ public SimpleMailboxMessage toMailboxMessage(ComposedMessageIdWithMetaData metadata, List<MessageAttachmentMetadata> attachments, Optional<Date> saveDate) {
return SimpleMailboxMessage.builder()
.messageId(messageId)
.threadId(metadata.getThreadId())
@@ -62,6 +63,7 @@ public class MessageRepresentation {
.uid(metadata.getComposedMessageId().getUid())
.modseq(metadata.getModSeq())
.internalDate(internalDate)
+ .saveDate(saveDate)
.bodyStartOctet(bodyStartOctet)
.size(size)
.content(content)
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java
index 2c6a90d691..e51dc31081 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java
@@ -21,6 +21,8 @@ package org.apache.james.mailbox.cassandra;
import static org.assertj.core.api.Assertions.assertThat;
+import java.time.Clock;
+
import org.apache.james.backends.cassandra.CassandraClusterExtension;
import org.apache.james.backends.cassandra.components.CassandraModule;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
@@ -136,7 +138,8 @@ class CassandraSubscriptionManagerTest implements SubscriptionManagerContract {
userMailboxRightsDAO,
recomputeMailboxCountersService,
CassandraConfiguration.DEFAULT_CONFIGURATION,
- BatchSizes.defaultValues());
+ BatchSizes.defaultValues(),
+ Clock.systemUTC());
InVMEventBus eventBus = new InVMEventBus(new InVmEventDelivery(new RecordingMetricFactory()), EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION, new MemoryEventDeadLetters());
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java
index a1e3d7976f..a4cd1f124d 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java
@@ -19,11 +19,14 @@
package org.apache.james.mailbox.cassandra;
+import java.time.Clock;
+
import org.apache.james.backends.cassandra.CassandraCluster;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
import org.apache.james.mailbox.cassandra.mail.utils.GuiceUtils;
import org.apache.james.mailbox.store.BatchSizes;
+import org.apache.james.utils.UpdatableTickingClock;
import com.google.inject.Guice;
import com.google.inject.util.Modules;
@@ -42,6 +45,16 @@ public class TestCassandraMailboxSessionMapperFactory {
.getInstance(CassandraMailboxSessionMapperFactory.class);
}
+ public static CassandraMailboxSessionMapperFactory forTests(CassandraCluster cassandra,
+ CassandraMessageId.Factory factory,
+ CassandraConfiguration cassandraConfiguration,
+ UpdatableTickingClock updatableTickingClock) {
+
+ return Guice.createInjector(Modules.override(GuiceUtils.commonModules(cassandra.getConf(), cassandra.getTypesProvider(), factory, cassandraConfiguration))
+ .with(binder -> binder.bind(Clock.class).toInstance(updatableTickingClock)))
+ .getInstance(CassandraMailboxSessionMapperFactory.class);
+ }
+
public static CassandraMailboxSessionMapperFactory forTests(CassandraCluster cassandra,
CassandraMessageId.Factory factory,
CassandraConfiguration cassandraConfiguration,
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java
index 145fb709b8..e3e7cd9f2b 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java
@@ -18,6 +18,7 @@
****************************************************************/
package org.apache.james.mailbox.cassandra.mail;
+import java.time.Instant;
import java.util.List;
import org.apache.james.backends.cassandra.CassandraCluster;
@@ -41,6 +42,7 @@ import org.apache.james.mailbox.store.mail.MessageIdMapper;
import org.apache.james.mailbox.store.mail.MessageMapper;
import org.apache.james.mailbox.store.mail.model.MapperProvider;
import org.apache.james.mailbox.store.mail.model.MessageUidProvider;
+import org.apache.james.utils.UpdatableTickingClock;
import com.google.common.collect.ImmutableList;
@@ -51,6 +53,7 @@ public class CassandraMapperProvider implements MapperProvider {
private final CassandraCluster cassandra;
private final MessageUidProvider messageUidProvider;
private final CassandraModSeqProvider cassandraModSeqProvider;
+ private final UpdatableTickingClock updatableTickingClock;
private final MailboxSession mailboxSession = MailboxSessionUtil.create(Username.of("benwa"));
private CassandraMailboxSessionMapperFactory mapperFactory;
@@ -61,7 +64,8 @@ public class CassandraMapperProvider implements MapperProvider {
cassandraModSeqProvider = new CassandraModSeqProvider(
this.cassandra.getConf(),
cassandraConfiguration);
- mapperFactory = createMapperFactory(cassandraConfiguration);
+ updatableTickingClock = new UpdatableTickingClock(Instant.now());
+ mapperFactory = createMapperFactory(cassandraConfiguration, updatableTickingClock);
}
@Override
@@ -84,10 +88,11 @@ public class CassandraMapperProvider implements MapperProvider {
return mapperFactory.getMessageIdMapper(mailboxSession);
}
- private CassandraMailboxSessionMapperFactory createMapperFactory(CassandraConfiguration cassandraConfiguration) {
+ private CassandraMailboxSessionMapperFactory createMapperFactory(CassandraConfiguration cassandraConfiguration, UpdatableTickingClock updatableTickingClock) {
return TestCassandraMailboxSessionMapperFactory.forTests(cassandra,
new CassandraMessageId.Factory(),
- cassandraConfiguration);
+ cassandraConfiguration,
+ updatableTickingClock);
}
@Override
@@ -125,4 +130,7 @@ public class CassandraMapperProvider implements MapperProvider {
return cassandraModSeqProvider.highestModSeq(mailbox);
}
+ public UpdatableTickingClock getUpdatableTickingClock() {
+ return updatableTickingClock;
+ }
}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperRelaxedConsistencyTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperRelaxedConsistencyTest.java
index 5a00c78bc2..5380a66fa9 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperRelaxedConsistencyTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperRelaxedConsistencyTest.java
@@ -22,6 +22,7 @@ package org.apache.james.mailbox.cassandra.mail;
import org.apache.james.backends.cassandra.CassandraClusterExtension;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
import org.apache.james.mailbox.store.mail.model.MessageIdMapperTest;
+import org.apache.james.utils.UpdatableTickingClock;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -32,27 +33,41 @@ class CassandraMessageIdMapperRelaxedConsistencyTest {
@Nested
class WeakReadConsistency extends MessageIdMapperTest {
+ private final CassandraMapperProvider mapperProvider = new CassandraMapperProvider(
+ cassandraCluster.getCassandraCluster(),
+ CassandraConfiguration.builder()
+ .messageReadStrongConsistency(false)
+ .messageWriteStrongConsistency(true)
+ .build());
+
@Override
protected CassandraMapperProvider provideMapper() {
- return new CassandraMapperProvider(
- cassandraCluster.getCassandraCluster(),
- CassandraConfiguration.builder()
- .messageReadStrongConsistency(false)
- .messageWriteStrongConsistency(true)
- .build());
+ return mapperProvider;
+ }
+
+ @Override
+ protected UpdatableTickingClock updatableTickingClock() {
+ return mapperProvider.getUpdatableTickingClock();
}
}
@Nested
class WeakWriteConsistency extends MessageIdMapperTest {
+ private final CassandraMapperProvider mapperProvider = new CassandraMapperProvider(
+ cassandraCluster.getCassandraCluster(),
+ CassandraConfiguration.builder()
+ .messageReadStrongConsistency(false)
+ .messageWriteStrongConsistency(false)
+ .build());
+
@Override
protected CassandraMapperProvider provideMapper() {
- return new CassandraMapperProvider(
- cassandraCluster.getCassandraCluster(),
- CassandraConfiguration.builder()
- .messageReadStrongConsistency(false)
- .messageWriteStrongConsistency(false)
- .build());
+ return mapperProvider;
+ }
+
+ @Override
+ protected UpdatableTickingClock updatableTickingClock() {
+ return mapperProvider.getUpdatableTickingClock();
}
@Disabled("JAMES-3435 Without strong consistency flags update is not thread safe as long as it follows a read-before-write pattern")
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java
index 958be20af9..4af4d7785b 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java
@@ -47,6 +47,7 @@ import org.apache.james.mailbox.store.mail.MessageMapper;
import org.apache.james.mailbox.store.mail.model.MailboxMessage;
import org.apache.james.mailbox.store.mail.model.MessageIdMapperTest;
import org.apache.james.util.streams.Limit;
+import org.apache.james.utils.UpdatableTickingClock;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Tag;
@@ -61,12 +62,19 @@ class CassandraMessageIdMapperTest extends MessageIdMapperTest {
@RegisterExtension
static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MailboxAggregateModule.MODULE);
-
+
+ private final CassandraMapperProvider mapperProvider = new CassandraMapperProvider(
+ cassandraCluster.getCassandraCluster(),
+ CassandraConfiguration.DEFAULT_CONFIGURATION);
+
@Override
protected CassandraMapperProvider provideMapper() {
- return new CassandraMapperProvider(
- cassandraCluster.getCassandraCluster(),
- CassandraConfiguration.DEFAULT_CONFIGURATION);
+ return mapperProvider;
+ }
+
+ @Override
+ protected UpdatableTickingClock updatableTickingClock() {
+ return mapperProvider.getUpdatableTickingClock();
}
@Test
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperRelaxedConsistencyTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperRelaxedConsistencyTest.java
index 4028772cec..f6d65f6c00 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperRelaxedConsistencyTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperRelaxedConsistencyTest.java
@@ -23,6 +23,7 @@ import org.apache.james.backends.cassandra.CassandraClusterExtension;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
import org.apache.james.mailbox.store.mail.model.MapperProvider;
import org.apache.james.mailbox.store.mail.model.MessageMapperTest;
+import org.apache.james.utils.UpdatableTickingClock;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -33,27 +34,41 @@ class CassandraMessageMapperRelaxedConsistencyTest {
@Nested
class WeakReadConsistency extends MessageMapperTest {
+ private final CassandraMapperProvider cassandraMapperProvider = new CassandraMapperProvider(
+ cassandraCluster.getCassandraCluster(),
+ CassandraConfiguration.builder()
+ .messageReadStrongConsistency(false)
+ .messageWriteStrongConsistency(true)
+ .build());
+
@Override
protected MapperProvider createMapperProvider() {
- return new CassandraMapperProvider(
- cassandraCluster.getCassandraCluster(),
- CassandraConfiguration.builder()
- .messageReadStrongConsistency(false)
- .messageWriteStrongConsistency(true)
- .build());
+ return cassandraMapperProvider;
+ }
+
+ @Override
+ protected UpdatableTickingClock updatableTickingClock() {
+ return cassandraMapperProvider.getUpdatableTickingClock();
}
}
@Nested
class WeakWriteConsistency extends MessageMapperTest {
+ private final CassandraMapperProvider cassandraMapperProvider = new CassandraMapperProvider(
+ cassandraCluster.getCassandraCluster(),
+ CassandraConfiguration.builder()
+ .messageReadStrongConsistency(false)
+ .messageWriteStrongConsistency(false)
+ .build());
+
@Override
protected MapperProvider createMapperProvider() {
- return new CassandraMapperProvider(
- cassandraCluster.getCassandraCluster(),
- CassandraConfiguration.builder()
- .messageReadStrongConsistency(false)
- .messageWriteStrongConsistency(false)
- .build());
+ return cassandraMapperProvider;
+ }
+
+ @Override
+ protected UpdatableTickingClock updatableTickingClock() {
+ return cassandraMapperProvider.getUpdatableTickingClock();
}
@Disabled("JAMES-3435 Without strong consistency flags update is not thread safe as long as it follows a read-before-write pattern")
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java
index ec84ffb1fe..dfc02de3ac 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java
@@ -46,6 +46,7 @@ import org.apache.james.mailbox.store.mail.model.MailboxMessage;
import org.apache.james.mailbox.store.mail.model.MapperProvider;
import org.apache.james.mailbox.store.mail.model.MessageMapperTest;
import org.apache.james.util.streams.Limit;
+import org.apache.james.utils.UpdatableTickingClock;
import org.assertj.core.api.SoftAssertions;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Nested;
@@ -58,12 +59,19 @@ import com.google.common.collect.ImmutableList;
class CassandraMessageMapperTest extends MessageMapperTest {
@RegisterExtension
static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MailboxAggregateModule.MODULE);
-
+
+ private final CassandraMapperProvider cassandraMapperProvider = new CassandraMapperProvider(
+ cassandraCluster.getCassandraCluster(),
+ CassandraConfiguration.DEFAULT_CONFIGURATION);
+
@Override
protected MapperProvider createMapperProvider() {
- return new CassandraMapperProvider(
- cassandraCluster.getCassandraCluster(),
- CassandraConfiguration.DEFAULT_CONFIGURATION);
+ return cassandraMapperProvider;
+ }
+
+ @Override
+ protected UpdatableTickingClock updatableTickingClock() {
+ return cassandraMapperProvider.getUpdatableTickingClock();
}
@Nested
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
index a6dd9b3773..ed06c2c280 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/utils/GuiceUtils.java
@@ -19,6 +19,7 @@
package org.apache.james.mailbox.cassandra.mail.utils;
+import java.time.Clock;
import java.util.Set;
import org.apache.james.backends.cassandra.CassandraCluster;
@@ -94,6 +95,7 @@ public class GuiceUtils {
binder -> Multibinder.newSetBinder(binder, new TypeLiteral<EventDTOModule<? extends Event, ? extends EventDTO>>() {}),
binder -> binder.bind(EventStore.class).to(CassandraEventStore.class),
binder -> binder.bind(CassandraTypesProvider.class).toInstance(typesProvider),
- binder -> binder.bind(CassandraConfiguration.class).toInstance(configuration));
+ binder -> binder.bind(CassandraConfiguration.class).toInstance(configuration),
+ binder -> binder.bind(Clock.class).toInstance(Clock.systemUTC()));
}
}
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 879171416d..d8c40546db 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
@@ -435,6 +435,11 @@ public abstract class AbstractJPAMailboxMessage implements MailboxMessage {
this.uid = uid.asLong();
}
+ @Override
+ public void setSaveDate(Date saveDate) {
+
+ }
+
@Override
public long getHeaderOctets() {
return bodyStartOctet;
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/JpaMessageMapperTest.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/JpaMessageMapperTest.java
index 1e5db354e0..6a9c7055dd 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/JpaMessageMapperTest.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/JpaMessageMapperTest.java
@@ -35,7 +35,10 @@ import org.apache.james.mailbox.model.UpdatedFlags;
import org.apache.james.mailbox.store.FlagsUpdateCalculator;
import org.apache.james.mailbox.store.mail.model.MapperProvider;
import org.apache.james.mailbox.store.mail.model.MessageMapperTest;
+import org.apache.james.utils.UpdatableTickingClock;
import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
class JpaMessageMapperTest extends MessageMapperTest {
@@ -46,7 +49,12 @@ class JpaMessageMapperTest extends MessageMapperTest {
protected MapperProvider createMapperProvider() {
return new JPAMapperProvider(JPA_TEST_CLUSTER);
}
-
+
+ @Override
+ protected UpdatableTickingClock updatableTickingClock() {
+ return null;
+ }
+
@AfterEach
void cleanUp() {
JPA_TEST_CLUSTER.clear(JPAMailboxFixture.MAILBOX_TABLE_NAMES);
@@ -139,4 +147,10 @@ class JpaMessageMapperTest extends MessageMapperTest {
.newFlags(new Flags())
.build());
}
+
+ @Nested
+ @Disabled("JPA does not support saveDate.")
+ class SaveDateTests {
+
+ }
}
diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxSessionMapperFactory.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxSessionMapperFactory.java
index 42967eeccf..c9e384f3bb 100644
--- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxSessionMapperFactory.java
+++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMailboxSessionMapperFactory.java
@@ -18,6 +18,8 @@
****************************************************************/
package org.apache.james.mailbox.inmemory;
+import java.time.Clock;
+
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.inmemory.mail.InMemoryAnnotationMapper;
@@ -49,11 +51,11 @@ public class InMemoryMailboxSessionMapperFactory extends MailboxSessionMapperFac
private final InMemoryUidProvider uidProvider;
private final InMemoryModSeqProvider modSeqProvider;
- public InMemoryMailboxSessionMapperFactory() {
+ public InMemoryMailboxSessionMapperFactory(Clock clock) {
mailboxMapper = new InMemoryMailboxMapper();
uidProvider = new InMemoryUidProvider();
modSeqProvider = new InMemoryModSeqProvider();
- messageMapper = new InMemoryMessageMapper(null, uidProvider, modSeqProvider);
+ messageMapper = new InMemoryMessageMapper(null, uidProvider, modSeqProvider, clock);
messageIdMapper = new InMemoryMessageIdMapper(mailboxMapper, messageMapper);
subscriptionMapper = new InMemorySubscriptionMapper();
diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageMapper.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageMapper.java
index 3545e85b7c..5b6295e0c5 100644
--- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageMapper.java
+++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageMapper.java
@@ -19,8 +19,10 @@
package org.apache.james.mailbox.inmemory.mail;
+import java.time.Clock;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -54,8 +56,8 @@ public class InMemoryMessageMapper extends AbstractMessageMapper {
private static final int INITIAL_SIZE = 256;
public InMemoryMessageMapper(MailboxSession session, UidProvider uidProvider,
- ModSeqProvider modSeqProvider) {
- super(session, uidProvider, modSeqProvider);
+ ModSeqProvider modSeqProvider, Clock clock) {
+ super(session, uidProvider, modSeqProvider, clock);
this.mailboxByUid = new ConcurrentHashMap<>(INITIAL_SIZE);
}
@@ -200,6 +202,7 @@ public class InMemoryMessageMapper extends AbstractMessageMapper {
SimpleMailboxMessage copy = SimpleMailboxMessage.copy(mailbox.getMailboxId(), message);
copy.setUid(message.getUid());
copy.setModSeq(message.getModSeq());
+ copy.setSaveDate(Date.from(clock.instant()));
getMembershipByUidForMailbox(mailbox).put(message.getUid(), copy);
return copy.metaData();
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMapperProvider.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMapperProvider.java
index 8f60b26760..4667385719 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMapperProvider.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMapperProvider.java
@@ -19,6 +19,7 @@
package org.apache.james.mailbox.inmemory.mail;
+import java.time.Instant;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
@@ -39,6 +40,7 @@ import org.apache.james.mailbox.store.mail.MessageIdMapper;
import org.apache.james.mailbox.store.mail.MessageMapper;
import org.apache.james.mailbox.store.mail.model.MapperProvider;
import org.apache.james.mailbox.store.mail.model.MessageUidProvider;
+import org.apache.james.utils.UpdatableTickingClock;
import com.google.common.collect.ImmutableList;
@@ -50,12 +52,14 @@ public class InMemoryMapperProvider implements MapperProvider {
private final MessageId.Factory messageIdFactory;
private final MessageUidProvider messageUidProvider;
private final InMemoryMailboxSessionMapperFactory inMemoryMailboxSessionMapperFactory;
+ private final UpdatableTickingClock clock;
public InMemoryMapperProvider() {
messageIdFactory = new InMemoryMessageId.Factory();
messageUidProvider = new MessageUidProvider();
- inMemoryMailboxSessionMapperFactory = new InMemoryMailboxSessionMapperFactory();
+ clock = new UpdatableTickingClock(Instant.now());
+ inMemoryMailboxSessionMapperFactory = new InMemoryMailboxSessionMapperFactory(clock);
}
@Override
@@ -124,4 +128,7 @@ public class InMemoryMapperProvider implements MapperProvider {
.highestModSeq(mailbox);
}
+ public UpdatableTickingClock getClock() {
+ return clock;
+ }
}
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageIdMapperTest.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageIdMapperTest.java
index faf70ab9f9..080f8b8915 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageIdMapperTest.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/InMemoryMessageIdMapperTest.java
@@ -21,11 +21,18 @@ package org.apache.james.mailbox.inmemory.mail;
import org.apache.james.mailbox.store.mail.model.MapperProvider;
import org.apache.james.mailbox.store.mail.model.MessageIdMapperTest;
+import org.apache.james.utils.UpdatableTickingClock;
class InMemoryMessageIdMapperTest extends MessageIdMapperTest {
+ private final InMemoryMapperProvider mapperProvider = new InMemoryMapperProvider();
@Override
protected MapperProvider provideMapper() {
- return new InMemoryMapperProvider();
+ return mapperProvider;
+ }
+
+ @Override
+ protected UpdatableTickingClock updatableTickingClock() {
+ return mapperProvider.getClock();
}
}
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/MemoryMessageMapperTest.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/MemoryMessageMapperTest.java
index 77b3696081..8e0c618a69 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/MemoryMessageMapperTest.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/MemoryMessageMapperTest.java
@@ -21,11 +21,19 @@ package org.apache.james.mailbox.inmemory.mail;
import org.apache.james.mailbox.store.mail.model.MapperProvider;
import org.apache.james.mailbox.store.mail.model.MessageMapperTest;
+import org.apache.james.utils.UpdatableTickingClock;
class MemoryMessageMapperTest extends MessageMapperTest {
+ private final InMemoryMapperProvider inMemoryMapperProvider = new InMemoryMapperProvider();
@Override
protected MapperProvider createMapperProvider() {
- return new InMemoryMapperProvider();
+ return inMemoryMapperProvider;
}
+
+ @Override
+ protected UpdatableTickingClock updatableTickingClock() {
+ return inMemoryMapperProvider.getClock();
+ }
+
}
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 d6a5c06759..8a390fecfa 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
@@ -294,7 +294,8 @@ public class InMemoryIntegrationResources implements IntegrationResources<StoreM
Preconditions.checkState(searchIndexFactory.isPresent());
Preconditions.checkState(messageParser.isPresent());
- InMemoryMailboxSessionMapperFactory mailboxSessionMapperFactory = new InMemoryMailboxSessionMapperFactory();
+ UpdatableTickingClock clock = new UpdatableTickingClock(Instant.now());
+ InMemoryMailboxSessionMapperFactory mailboxSessionMapperFactory = new InMemoryMailboxSessionMapperFactory(clock);
EventBus eventBus = this.eventBus.get();
StoreRightManager storeRightManager = new StoreRightManager(mailboxSessionMapperFactory, new UnionMailboxACLResolver(), eventBus);
@@ -314,7 +315,6 @@ 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);
diff --git a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndexTest.java b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndexTest.java
index 3070f59872..ce34fbe26b 100644
--- a/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndexTest.java
+++ b/mailbox/opensearch/src/test/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndexTest.java
@@ -26,6 +26,7 @@ import static org.awaitility.Durations.ONE_HUNDRED_MILLISECONDS;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
+import java.time.Instant;
import java.time.ZoneId;
import java.util.Date;
@@ -77,6 +78,7 @@ import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
import org.apache.james.mailbox.store.search.ListeningMessageSearchIndex;
import org.apache.james.mailbox.store.search.ListeningMessageSearchIndexContract;
+import org.apache.james.utils.UpdatableTickingClock;
import org.awaitility.Awaitility;
import org.awaitility.Durations;
import org.awaitility.core.ConditionFactory;
@@ -166,13 +168,15 @@ class OpenSearchListeningMessageSearchIndexTest {
OpenSearchIndexer openSearchIndexer;
OpenSearchSearcher openSearchSearcher;
SessionProviderImpl sessionProvider;
+ UpdatableTickingClock clock;
@RegisterExtension
DockerOpenSearchExtension openSearch = new DockerOpenSearchExtension();
@BeforeEach
void setup() throws Exception {
- mapperFactory = new InMemoryMailboxSessionMapperFactory();
+ clock = new UpdatableTickingClock(Instant.now());
+ mapperFactory = new InMemoryMailboxSessionMapperFactory(clock);
MessageToOpenSearchJson messageToOpenSearchJson = new MessageToOpenSearchJson(
new DefaultTextExtractor(),
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/AbstractMessageMapper.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/AbstractMessageMapper.java
index ad1d9adeed..96a5d09ebc 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/AbstractMessageMapper.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/AbstractMessageMapper.java
@@ -18,6 +18,7 @@
****************************************************************/
package org.apache.james.mailbox.store.mail;
+import java.time.Clock;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -54,11 +55,13 @@ public abstract class AbstractMessageMapper extends TransactionalMapper implemen
protected final MailboxSession mailboxSession;
private final UidProvider uidProvider;
private final ModSeqProvider modSeqProvider;
+ protected final Clock clock;
- public AbstractMessageMapper(MailboxSession mailboxSession, UidProvider uidProvider, ModSeqProvider modSeqProvider) {
+ public AbstractMessageMapper(MailboxSession mailboxSession, UidProvider uidProvider, ModSeqProvider modSeqProvider, Clock clock) {
this.mailboxSession = mailboxSession;
this.uidProvider = uidProvider;
this.modSeqProvider = modSeqProvider;
+ this.clock = clock;
}
@Override
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 d6e7f17b2b..249cece8dc 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
@@ -108,6 +108,8 @@ public interface MailboxMessage extends Message, Comparable<MailboxMessage> {
*/
void setFlags(Flags flags);
+ void setSaveDate(Date saveDate);
+
/**
* Creates a new flags instance populated
* with the current flag data.
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 e5caaa9bef..c5339ff690 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
@@ -208,7 +208,7 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
private MessageUid uid;
private final MailboxId mailboxId;
private final ThreadId threadId;
- private final Optional<Date> saveDate;
+ private Optional<Date> saveDate;
private boolean answered;
private boolean deleted;
private boolean draft;
@@ -319,6 +319,11 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage {
this.uid = uid;
}
+ @Override
+ public void setSaveDate(Date saveDate) {
+ this.saveDate = Optional.of(saveDate);
+ }
+
@Override
public Optional<Date> getSaveDate() {
return saveDate;
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageIdMapperTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageIdMapperTest.java
index cf66cdcd05..a1c2abd8fb 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageIdMapperTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageIdMapperTest.java
@@ -24,6 +24,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.time.Duration;
+import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
@@ -52,9 +53,11 @@ import org.apache.james.mailbox.store.mail.MessageMapper.FetchType;
import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
import org.apache.james.util.concurrency.ConcurrentTestRunner;
+import org.apache.james.utils.UpdatableTickingClock;
import org.assertj.core.data.MapEntry;
import org.junit.Assume;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import com.google.common.collect.ImmutableList;
@@ -84,6 +87,8 @@ public abstract class MessageIdMapperTest {
protected abstract MapperProvider provideMapper();
+ protected abstract UpdatableTickingClock updatableTickingClock();
+
@BeforeEach
void setUp() throws MailboxException {
this.mapperProvider = provideMapper();
@@ -984,6 +989,52 @@ public abstract class MessageIdMapperTest {
.build());
}
+ @Nested
+ class SaveDateTests {
+ @Test
+ void saveMessagesShouldSetNewSaveDate() throws MailboxException {
+ message1.setUid(mapperProvider.generateMessageUid());
+ message1.setModSeq(mapperProvider.generateModSeq(benwaInboxMailbox));
+ message1.setFlags(new Flags(Flag.SEEN));
+
+ message2.setUid(mapperProvider.generateMessageUid());
+ message2.setModSeq(mapperProvider.generateModSeq(benwaInboxMailbox));
+
+ sut.save(message1);
+ updatableTickingClock().setInstant(updatableTickingClock().instant().plusSeconds(1000));
+ sut.save(message2);
+
+ MailboxMessage firstMessage = sut.find(ImmutableList.of(message1.getMessageId()), FetchType.METADATA).get(0);
+ MailboxMessage secondMessage = sut.find(ImmutableList.of(message2.getMessageId()), FetchType.METADATA).get(0);
+
+ assertThat(firstMessage.getSaveDate()).isNotEqualTo(secondMessage.getSaveDate());
+ }
+
+ @Test
+ void copyInMailboxReactiveShouldSetNewSaveDate() throws MailboxException, InterruptedException {
+ message1.setUid(mapperProvider.generateMessageUid());
+ message1.setModSeq(mapperProvider.generateModSeq(benwaInboxMailbox));
+ message1.setFlags(new Flags(Flag.SEEN));
+ sut.save(message1);
+
+ MailboxMessage copy = sut.find(ImmutableList.of(message1.getMessageId()), FetchType.METADATA).get(0)
+ .copy(benwaWorkMailbox);
+ copy.setUid(mapperProvider.generateMessageUid());
+ copy.setModSeq(mapperProvider.generateModSeq(benwaWorkMailbox));
+
+ updatableTickingClock().setInstant(updatableTickingClock().instant().plus(8, ChronoUnit.DAYS));
+
+ sut.copyInMailboxReactive(copy, benwaWorkMailbox).block();
+
+ List<MailboxMessage> messages = sut.find(ImmutableList.of(message1.getMessageId()), FetchType.METADATA);
+ MailboxMessage firstMessage = messages.get(0);
+ MailboxMessage secondMessage = messages.get(1);
+
+ assertThat(firstMessage.getSaveDate()).isNotEqualTo(secondMessage.getSaveDate());
+ }
+ }
+
+
private Mailbox createMailbox(MailboxPath mailboxPath) throws MailboxException {
return mailboxMapper.create(mailboxPath, UID_VALIDITY).block();
}
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java
index 5503e4e782..f2b478d744 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java
@@ -42,6 +42,7 @@ import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.ByteContent;
+import org.apache.james.mailbox.model.Content;
import org.apache.james.mailbox.model.Mailbox;
import org.apache.james.mailbox.model.MailboxCounters;
import org.apache.james.mailbox.model.MailboxPath;
@@ -59,8 +60,10 @@ import org.apache.james.mailbox.store.mail.model.MapperProvider.Capabilities;
import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder;
import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage;
import org.apache.james.util.concurrency.ConcurrentTestRunner;
+import org.apache.james.utils.UpdatableTickingClock;
import org.junit.Assume;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import com.google.common.collect.ImmutableList;
@@ -94,6 +97,8 @@ public abstract class MessageMapperTest {
protected abstract MapperProvider createMapperProvider();
+ protected abstract UpdatableTickingClock updatableTickingClock();
+
@BeforeEach
void setUp() throws Exception {
this.mapperProvider = createMapperProvider();
@@ -1220,6 +1225,97 @@ public abstract class MessageMapperTest {
.containsOnly(message1.getUid(), message5.getUid());
}
+ @Nested
+ class SaveDateTests {
+ @Test
+ void addMessageShouldSetNewSaveDate() throws MailboxException {
+ MailboxMessage messageWithoutSaveDate = createMessage(Optional.empty());
+
+ MessageMetaData messageMetaData = messageMapper.add(benwaInboxMailbox, messageWithoutSaveDate);
+
+ assertThat(messageMetaData.getSaveDate()).isPresent();
+ }
+
+ @Test
+ void deleteMessageShouldReturnMetaDataContainsSaveDate() throws MailboxException {
+ MessageMetaData toBeDeletedMessage = messageMapper.add(benwaInboxMailbox, createMessage(Optional.empty()));
+
+ assertThat(messageMapper.deleteMessages(benwaInboxMailbox, List.of(toBeDeletedMessage.getUid()))
+ .values()
+ .stream()
+ .allMatch(messageMetaData -> messageMetaData.getSaveDate().equals(toBeDeletedMessage.getSaveDate())))
+ .isTrue();
+ }
+
+ @Test
+ void copyMessageShouldSetNewSaveDate() throws MailboxException {
+ MailboxMessage originalMessage = createMessage(Optional.of(new Date()));
+ MessageUid uid = messageMapper.add(benwaInboxMailbox, originalMessage).getUid();
+
+ updatableTickingClock().setInstant(updatableTickingClock().instant().plusSeconds(1000));
+
+ MessageMetaData copiedMessageMetaData = messageMapper.copy(benwaInboxMailbox,
+ messageMapper.findInMailbox(benwaInboxMailbox, MessageRange.one(uid), FetchType.METADATA, 1).next());
+
+ assertThat(copiedMessageMetaData.getSaveDate()).isNotEqualTo(originalMessage.getSaveDate());
+ }
+
+ @Test
+ void copyListOfMessagesShouldSetNewSaveDate() throws MailboxException {
+ MailboxMessage originalMessage = createMessage(Optional.of(new Date()));
+ MessageUid uid = messageMapper.add(benwaInboxMailbox, originalMessage).getUid();
+
+ updatableTickingClock().setInstant(updatableTickingClock().instant().plusSeconds(1000));
+
+ List<MessageMetaData> copiedMessageMetaData = messageMapper.copy(benwaInboxMailbox,
+ List.of(messageMapper.findInMailbox(benwaInboxMailbox, MessageRange.one(uid), FetchType.METADATA, 1).next()));
+
+ assertThat(copiedMessageMetaData.get(0).getSaveDate()).isNotEqualTo(originalMessage.getSaveDate());
+ }
+
+ @Test
+ void moveMessageShouldSetNewSaveDate() throws MailboxException {
+ MailboxMessage originalMessage = createMessage(Optional.of(new Date()));
+ MessageUid uid = messageMapper.add(benwaInboxMailbox, originalMessage).getUid();
+
+ updatableTickingClock().setInstant(updatableTickingClock().instant().plusSeconds(1000));
+
+ MessageMetaData movedMessageMetaData = messageMapper.move(benwaInboxMailbox,
+ messageMapper.findInMailbox(benwaInboxMailbox, MessageRange.one(uid), FetchType.METADATA, 1).next());
+
+ assertThat(movedMessageMetaData.getSaveDate()).isNotEqualTo(originalMessage.getSaveDate());
+ }
+
+ @Test
+ void moveListOfMessagesShouldSetNewSaveDate() throws MailboxException {
+ MailboxMessage originalMessage = createMessage(Optional.of(new Date()));
+ MessageUid uid = messageMapper.add(benwaInboxMailbox, originalMessage).getUid();
+
+ updatableTickingClock().setInstant(updatableTickingClock().instant().plusSeconds(1000));
+
+ List<MessageMetaData> movedMessageMetaData = messageMapper.move(benwaInboxMailbox,
+ List.of(messageMapper.findInMailbox(benwaInboxMailbox, MessageRange.one(uid), FetchType.METADATA, 1).next()));
+
+ assertThat(movedMessageMetaData.get(0).getSaveDate()).isNotEqualTo(originalMessage.getSaveDate());
+ }
+
+ private SimpleMailboxMessage createMessage(Optional<Date> saveDate) throws MailboxException {
+ Content content = new ByteContent("Subject: messagePropertiesShouldBeStoredWhenDuplicateEntries \n\nBody\n.\n".getBytes());
+ return SimpleMailboxMessage.builder()
+ .messageId(mapperProvider.generateMessageId())
+ .mailboxId(benwaInboxMailbox.getMailboxId())
+ .threadId(ThreadId.fromBaseMessageId(mapperProvider.generateMessageId()))
+ .internalDate(new Date())
+ .saveDate(saveDate)
+ .bodyStartOctet(16)
+ .size(content.size())
+ .content(content)
+ .flags(new Flags())
+ .properties(new PropertyBuilder())
+ .build();
+ }
+ }
+
private List<MessageUid> markThenPerformRetrieveMessagesMarkedForDeletion(MessageRange range) throws MailboxException {
messageMapper.updateFlags(benwaInboxMailbox, message1.getUid(), new FlagsUpdateCalculator(new Flags(Flags.Flag.DELETED), FlagsUpdateMode.REPLACE));
messageMapper.updateFlags(benwaInboxMailbox, message4.getUid(), new FlagsUpdateCalculator(new Flags(Flags.Flag.DELETED), FlagsUpdateMode.REPLACE));
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org