This is an automated email from the ASF dual-hosted git repository.
hqtran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push:
new a2c89b007b JAMES-4154 Refactor deletion callback for Postgres app
(#2886)
a2c89b007b is described below
commit a2c89b007bcf736cc1df3f143945dd0724b791a0
Author: Trần Hồng Quân <[email protected]>
AuthorDate: Fri Dec 19 13:45:46 2025 +0700
JAMES-4154 Refactor deletion callback for Postgres app (#2886)
---
.../apache/james/mailbox/events/MailboxEvents.java | 3 +-
.../mailbox/cassandra/DeleteMessageListener.java | 2 +-
.../james/event/json/MailboxEventSerializer.scala | 10 +-
.../MessageContentDeletionSerializationTest.java | 43 ++++++-
...ostgresDeletedMessageVaultDeletionCallback.java | 123 ---------------------
.../DeletedMessageVaultDeletionListener.java | 15 ++-
.../mailbox/postgres/DeleteMessageListener.java | 48 +++++---
.../PostgresMailboxSessionMapperFactory.java | 8 +-
.../postgres/DeleteMessageListenerTest.java | 2 +-
.../postgres/DeleteMessageListenerWithRLSTest.java | 2 +-
.../PostgresMailboxManagerAttachmentTest.java | 4 +-
.../postgres/PostgresMailboxManagerProvider.java | 2 +-
.../postgres/PostgresTestSystemFixture.java | 2 +-
.../james/mailbox/store/event/EventFactory.java | 32 ++++--
.../org/apache/james/PostgresJamesServerMain.java | 4 +-
.../james/modules/data/CassandraJmapModule.java | 4 +-
.../event/ContentDeletionEventBusModule.java | 29 -----
.../DistributedDeletedMessageVaultModule.java | 1 +
.../mailbox/PostgresDeletedMessageVaultModule.java | 11 +-
.../modules/mailbox/PostgresMailboxModule.java | 1 -
...stgresMemoryContentDeletionEventBusModule.java} | 47 ++++----
.../james/modules/data/PostgresDataJmapModule.java | 11 +-
...sMessageFastViewProjectionDeletionCallback.java | 44 --------
...MessageFastViewProjectionDeletionListener.java} | 11 +-
.../postgres-webadmin-integration-test/pom.xml | 6 +
...PostgresDeletedMessageVaultIntegrationTest.java | 95 +++-------------
...PostgresDeletedMessageVaultIntegrationTest.java | 66 +++++++++++
.../src/test/resources/listeners.xml | 4 +
28 files changed, 261 insertions(+), 369 deletions(-)
diff --git
a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
index d9bba5159d..a7bdcf9d41 100644
---
a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
+++
b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
@@ -537,7 +537,8 @@ public interface MailboxEvents {
}
record MessageContentDeletionEvent(EventId eventId, Username username,
MailboxId mailboxId, MessageId messageId, long size,
- Instant internalDate, boolean
hasAttachments, String headerBlobId, String bodyBlobId) implements Event {
+ Instant internalDate, boolean
hasAttachments, Optional<String> headerBlobId, Optional<String> headerContent,
+ String bodyBlobId) implements Event {
@Override
public EventId getEventId() {
diff --git
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
index f20dc5ca3e..59278aad9b 100644
---
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
+++
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/DeleteMessageListener.java
@@ -216,8 +216,8 @@ public class DeleteMessageListener implements
EventListener.ReactiveGroupEventLi
.size(message.getSize())
.instant(message.getInternalDate().toInstant())
.hasAttachments(!message.getAttachments().isEmpty())
- .headerBlobId(message.getHeaderId().asString())
.bodyBlobId(message.getBodyId().asString())
+ .headerBlobId(message.getHeaderId().asString())
.build(),
ImmutableSet.of()));
}
diff --git
a/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
b/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
index 5e428aac42..9722b2dc6e 100644
---
a/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
+++
b/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala
@@ -141,9 +141,10 @@ private object DTO {
size: Long,
internalDate: Instant,
hasAttachments: Boolean,
- headerBlobId: String,
+ headerBlobId: Option[String],
+ headerContent: Option[String],
bodyBlobId: String) extends Event {
- override def toJava: JavaEvent = new
JavaMessageContentDeletionEvent(eventId, username, mailboxId, messageId, size,
internalDate, hasAttachments, headerBlobId, bodyBlobId)
+ override def toJava: JavaEvent = new
JavaMessageContentDeletionEvent(eventId, username, mailboxId, messageId, size,
internalDate, hasAttachments, headerBlobId.toJava, headerContent.toJava,
bodyBlobId)
}
}
@@ -247,8 +248,9 @@ private object ScalaConverter {
size = event.size(),
internalDate = event.internalDate(),
hasAttachments = event.hasAttachments,
- headerBlobId = event.headerBlobId(),
- bodyBlobId = event.bodyBlobId())
+ headerBlobId = event.headerBlobId().toScala,
+ bodyBlobId = event.bodyBlobId(),
+ headerContent = event.headerContent().toScala)
def toScala(javaEvent: JavaEvent): Event = javaEvent match {
case e: JavaAdded => toScala(e)
diff --git
a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java
b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java
index 9edb6e5d2d..4ac8929cc4 100644
---
a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java
+++
b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageContentDeletionSerializationTest.java
@@ -25,6 +25,7 @@ import static
org.apache.james.event.json.SerializerFixture.EVENT_SERIALIZER;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.Instant;
+import java.util.Optional;
import org.apache.james.core.Username;
import
org.apache.james.mailbox.events.MailboxEvents.MessageContentDeletionEvent;
@@ -41,7 +42,9 @@ class MessageContentDeletionSerializationTest {
private static final long SIZE = 12345L;
private static final Instant INTERNAL_DATE =
Instant.parse("2024-12-15T08:23:45Z");
private static final boolean HAS_ATTACHMENTS = true;
- private static final String HEADER_BLOB_ID = "header-blob-id";
+ private static final Optional<String> HEADER_BLOB_ID =
Optional.of("header-blob-id");
+ private static final Optional<String> HEADER_CONTENT =
Optional.of("Header: value");
+ private static final Optional<String> EMPTY_HEADER_CONTENT =
Optional.empty();
private static final String BODY_BLOB_ID = "body-blob-id";
private static final MessageContentDeletionEvent EVENT = new
MessageContentDeletionEvent(
@@ -53,9 +56,39 @@ class MessageContentDeletionSerializationTest {
INTERNAL_DATE,
HAS_ATTACHMENTS,
HEADER_BLOB_ID,
+ HEADER_CONTENT,
+ BODY_BLOB_ID);
+
+ private static final MessageContentDeletionEvent
EVENT_WITHOUT_HEADER_CONTENT = new MessageContentDeletionEvent(
+ EVENT_ID,
+ USERNAME,
+ MAILBOX_ID,
+ MESSAGE_ID,
+ SIZE,
+ INTERNAL_DATE,
+ HAS_ATTACHMENTS,
+ HEADER_BLOB_ID,
+ EMPTY_HEADER_CONTENT,
BODY_BLOB_ID);
private static final String JSON = """
+ {
+ "MessageContentDeletionEvent": {
+ "eventId": "6e0dd59d-660e-4d9b-b22f-0354479f47b4",
+ "username": "[email protected]",
+ "size": 12345,
+ "hasAttachments": true,
+ "internalDate": "2024-12-15T08:23:45Z",
+ "mailboxId": "18",
+ "headerBlobId": "header-blob-id",
+ "messageId": "42",
+ "bodyBlobId": "body-blob-id",
+ "headerContent": "Header: value"
+ }
+ }
+ """;
+
+ private static final String JSON_WITHOUT_HEADER_CONTENT = """
{
"MessageContentDeletionEvent": {
"eventId": "6e0dd59d-660e-4d9b-b22f-0354479f47b4",
@@ -73,14 +106,14 @@ class MessageContentDeletionSerializationTest {
@Test
void messageContentDeletionEventShouldBeWellSerialized() {
- assertThatJson(EVENT_SERIALIZER.toJson(EVENT))
- .isEqualTo(JSON);
+ assertThatJson(EVENT_SERIALIZER.toJson(EVENT)).isEqualTo(JSON);
+
assertThatJson(EVENT_SERIALIZER.toJson(EVENT_WITHOUT_HEADER_CONTENT)).isEqualTo(JSON_WITHOUT_HEADER_CONTENT);
}
@Test
void messageContentDeletionEventShouldBeWellDeserialized() {
- assertThat(EVENT_SERIALIZER.fromJson(JSON).get())
- .isEqualTo(EVENT);
+ assertThat(EVENT_SERIALIZER.fromJson(JSON).get()).isEqualTo(EVENT);
+
assertThat(EVENT_SERIALIZER.fromJson(JSON_WITHOUT_HEADER_CONTENT).get()).isEqualTo(EVENT_WITHOUT_HEADER_CONTENT);
}
}
diff --git
a/mailbox/plugin/deleted-messages-vault-postgres/src/main/java/org/apache/james/vault/metadata/PostgresDeletedMessageVaultDeletionCallback.java
b/mailbox/plugin/deleted-messages-vault-postgres/src/main/java/org/apache/james/vault/metadata/PostgresDeletedMessageVaultDeletionCallback.java
deleted file mode 100644
index 224d2a492e..0000000000
---
a/mailbox/plugin/deleted-messages-vault-postgres/src/main/java/org/apache/james/vault/metadata/PostgresDeletedMessageVaultDeletionCallback.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you under the Apache License, Version 2.0 (the *
- * "License"); you may not use this file except in compliance *
- * with the License. You may obtain a copy of the License at *
- * *
- * http://www.apache.org/licenses/LICENSE-2.0 *
- * *
- * Unless required by applicable law or agreed to in writing, *
- * software distributed under the License is distributed on an *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
- * KIND, either express or implied. See the License for the *
- * specific language governing permissions and limitations *
- * under the License. *
- ****************************************************************/
-
-package org.apache.james.vault.metadata;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.SequenceInputStream;
-import java.time.Clock;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.util.Optional;
-import java.util.Set;
-
-import jakarta.inject.Inject;
-
-import org.apache.james.blob.api.BlobStore;
-import org.apache.james.core.MailAddress;
-import org.apache.james.core.MaybeSender;
-import org.apache.james.core.Username;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MessageId;
-import org.apache.james.mailbox.postgres.DeleteMessageListener;
-import org.apache.james.mailbox.postgres.mail.MessageRepresentation;
-import org.apache.james.mime4j.MimeIOException;
-import org.apache.james.mime4j.codec.DecodeMonitor;
-import org.apache.james.mime4j.dom.Message;
-import org.apache.james.mime4j.dom.address.Mailbox;
-import org.apache.james.mime4j.message.DefaultMessageBuilder;
-import org.apache.james.mime4j.stream.MimeConfig;
-import org.apache.james.server.core.Envelope;
-import org.apache.james.vault.DeletedMessage;
-import org.apache.james.vault.DeletedMessageVault;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.github.fge.lambdas.Throwing;
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Mono;
-
-public class PostgresDeletedMessageVaultDeletionCallback implements
DeleteMessageListener.DeletionCallback {
- private static final Logger LOGGER =
LoggerFactory.getLogger(PostgresDeletedMessageVaultDeletionCallback.class);
-
- private final DeletedMessageVault deletedMessageVault;
- private final BlobStore blobStore;
- private final Clock clock;
-
- @Inject
- public PostgresDeletedMessageVaultDeletionCallback(DeletedMessageVault
deletedMessageVault, BlobStore blobStore, Clock clock) {
- this.deletedMessageVault = deletedMessageVault;
- this.blobStore = blobStore;
- this.clock = clock;
- }
-
- @Override
- public Mono<Void> forMessage(MessageRepresentation message, MailboxId
mailboxId, Username owner) {
- return Mono.fromSupplier(Throwing.supplier(() ->
message.getHeaderContent().getInputStream()))
- .flatMap(headerStream -> {
- Optional<Message> mimeMessage = parseMessage(headerStream,
message.getMessageId());
- DeletedMessage deletedMessage = DeletedMessage.builder()
- .messageId(message.getMessageId())
- .originMailboxes(mailboxId)
- .user(owner)
-
.deliveryDate(ZonedDateTime.ofInstant(message.getInternalDate().toInstant(),
ZoneOffset.UTC))
- .deletionDate(ZonedDateTime.ofInstant(clock.instant(),
ZoneOffset.UTC))
- .sender(retrieveSender(mimeMessage))
- .recipients(retrieveRecipients(mimeMessage))
- .hasAttachment(!message.getAttachments().isEmpty())
- .size(message.getSize())
- .subject(mimeMessage.map(Message::getSubject))
- .build();
-
- return
Mono.from(blobStore.readReactive(blobStore.getDefaultBucketName(),
message.getBodyBlobId(), BlobStore.StoragePolicy.LOW_COST))
- .map(bodyStream -> new SequenceInputStream(headerStream,
bodyStream))
- .flatMap(bodyStream ->
Mono.from(deletedMessageVault.append(deletedMessage, bodyStream)));
- });
- }
-
- private Optional<Message> parseMessage(InputStream inputStream, MessageId
messageId) {
- DefaultMessageBuilder messageBuilder = new DefaultMessageBuilder();
- messageBuilder.setMimeEntityConfig(MimeConfig.PERMISSIVE);
- messageBuilder.setDecodeMonitor(DecodeMonitor.SILENT);
- try {
- return
Optional.ofNullable(messageBuilder.parseMessage(inputStream));
- } catch (MimeIOException e) {
- LOGGER.warn("Can not parse the message {}", messageId, e);
- return Optional.empty();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- private MaybeSender retrieveSender(Optional<Message> mimeMessage) {
- return mimeMessage
- .map(Message::getSender)
- .map(Mailbox::getAddress)
- .map(MaybeSender::getMailSender)
- .orElse(MaybeSender.nullSender());
- }
-
- private Set<MailAddress> retrieveRecipients(Optional<Message>
maybeMessage) {
- return maybeMessage.map(message -> Envelope.fromMime4JMessage(message,
Envelope.ValidationPolicy.IGNORE))
- .map(Envelope::getRecipients)
- .orElse(ImmutableSet.of());
- }
-}
diff --git
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DeletedMessageVaultDeletionListener.java
b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultDeletionListener.java
similarity index 89%
rename from
server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DeletedMessageVaultDeletionListener.java
rename to
mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultDeletionListener.java
index f80eb04e26..bfdc1cc9e0 100644
---
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DeletedMessageVaultDeletionListener.java
+++
b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/DeletedMessageVaultDeletionListener.java
@@ -17,12 +17,13 @@
* under the License. *
****************************************************************/
-package org.apache.james.modules.mailbox;
+package org.apache.james.vault;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
+import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
@@ -47,8 +48,6 @@ import org.apache.james.mime4j.dom.address.Mailbox;
import org.apache.james.mime4j.message.DefaultMessageBuilder;
import org.apache.james.mime4j.stream.MimeConfig;
import org.apache.james.server.core.Envelope;
-import org.apache.james.vault.DeletedMessage;
-import org.apache.james.vault.DeletedMessageVault;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -99,7 +98,7 @@ public class DeletedMessageVaultDeletionListener implements
EventListener.Reacti
}
public Mono<Void> forMessage(MessageContentDeletionEvent
messageContentDeletionEvent) {
- return Mono.from(blobStore.readBytes(blobStore.getDefaultBucketName(),
blobIdFactory.parse(messageContentDeletionEvent.headerBlobId()),
BlobStore.StoragePolicy.LOW_COST))
+ return fetchMessageHeaderBytes(messageContentDeletionEvent)
.flatMap(bytes -> {
Optional<Message> mimeMessage = parseMessage(new
ByteArrayInputStream(bytes), messageContentDeletionEvent.messageId());
DeletedMessage deletedMessage = DeletedMessage.builder()
@@ -121,6 +120,14 @@ public class DeletedMessageVaultDeletionListener
implements EventListener.Reacti
});
}
+ private Mono<byte[]> fetchMessageHeaderBytes(MessageContentDeletionEvent
messageContentDeletionEvent) {
+ return Mono.justOrEmpty(messageContentDeletionEvent.headerBlobId())
+ .flatMap(headerBlobId ->
Mono.from(blobStore.readBytes(blobStore.getDefaultBucketName(),
blobIdFactory.parse(headerBlobId), BlobStore.StoragePolicy.LOW_COST)))
+
.switchIfEmpty(Mono.justOrEmpty(messageContentDeletionEvent.headerContent())
+ .map(headerContent ->
headerContent.getBytes(StandardCharsets.UTF_8))
+ .switchIfEmpty(Mono.error(() -> new
IllegalArgumentException("No header content nor header blob id provided"))));
+ }
+
private Optional<Message> parseMessage(InputStream inputStream, MessageId
messageId) {
DefaultMessageBuilder messageBuilder = new DefaultMessageBuilder();
messageBuilder.setMimeEntityConfig(MimeConfig.PERMISSIVE);
diff --git
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/DeleteMessageListener.java
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/DeleteMessageListener.java
index c6fc63c868..5f31c3ba9b 100644
---
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/DeleteMessageListener.java
+++
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/DeleteMessageListener.java
@@ -19,16 +19,19 @@
package org.apache.james.mailbox.postgres;
-import java.util.Set;
-import java.util.function.Function;
+import java.nio.charset.StandardCharsets;
import jakarta.inject.Inject;
+import jakarta.inject.Named;
+import org.apache.commons.io.IOUtils;
import org.apache.james.blob.api.BlobStore;
import org.apache.james.core.Username;
import org.apache.james.events.Event;
+import org.apache.james.events.EventBus;
import org.apache.james.events.EventListener;
import org.apache.james.events.Group;
+import org.apache.james.mailbox.events.MailboxEvents;
import org.apache.james.mailbox.events.MailboxEvents.Expunged;
import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
import org.apache.james.mailbox.model.MailboxId;
@@ -38,31 +41,29 @@ import
org.apache.james.mailbox.postgres.mail.dao.PostgresAttachmentDAO;
import org.apache.james.mailbox.postgres.mail.dao.PostgresMailboxMessageDAO;
import org.apache.james.mailbox.postgres.mail.dao.PostgresMessageDAO;
import org.apache.james.mailbox.postgres.mail.dao.PostgresThreadDAO;
+import org.apache.james.mailbox.store.event.EventFactory;
import org.apache.james.util.FunctionalUtils;
import org.apache.james.util.ReactorUtils;
import org.reactivestreams.Publisher;
+import com.google.common.collect.ImmutableSet;
+
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public class DeleteMessageListener implements
EventListener.ReactiveGroupEventListener {
- @FunctionalInterface
- public interface DeletionCallback {
- Mono<Void> forMessage(MessageRepresentation messageRepresentation,
MailboxId mailboxId, Username owner);
- }
-
public static class DeleteMessageListenerGroup extends Group {
}
public static final int LOW_CONCURRENCY = 4;
+ public static final String CONTENT_DELETION = "contentDeletion";
private final BlobStore blobStore;
- private final Set<DeletionCallback> deletionCallbackList;
-
private final PostgresMessageDAO.Factory messageDAOFactory;
private final PostgresMailboxMessageDAO.Factory mailboxMessageDAOFactory;
private final PostgresAttachmentDAO.Factory attachmentDAOFactory;
private final PostgresThreadDAO.Factory threadDAOFactory;
+ private final EventBus contentDeletionEventBus;
@Inject
public DeleteMessageListener(BlobStore blobStore,
@@ -70,13 +71,13 @@ public class DeleteMessageListener implements
EventListener.ReactiveGroupEventLi
PostgresMessageDAO.Factory messageDAOFactory,
PostgresAttachmentDAO.Factory
attachmentDAOFactory,
PostgresThreadDAO.Factory threadDAOFactory,
- Set<DeletionCallback> deletionCallbackList) {
+ @Named(CONTENT_DELETION) EventBus
contentDeletionEventBus) {
this.messageDAOFactory = messageDAOFactory;
this.mailboxMessageDAOFactory = mailboxMessageDAOFactory;
this.blobStore = blobStore;
- this.deletionCallbackList = deletionCallbackList;
this.attachmentDAOFactory = attachmentDAOFactory;
this.threadDAOFactory = threadDAOFactory;
+ this.contentDeletionEventBus = contentDeletionEventBus;
}
@Override
@@ -138,17 +139,32 @@ public class DeleteMessageListener implements
EventListener.ReactiveGroupEventLi
return Mono.just(messageId)
.filterWhen(msgId -> isUnreferenced(msgId,
postgresMailboxMessageDAO))
.flatMap(msgId -> postgresMessageDAO.retrieveMessage(messageId)
- .flatMap(executeDeletionCallbacks(mailboxId, owner))
+ .flatMap(messageRepresentation ->
dispatchMessageContentDeletionEvent(mailboxId, owner, messageRepresentation))
.then(deleteBodyBlob(msgId, postgresMessageDAO))
.then(deleteAttachment(msgId, attachmentDAO))
.then(threadDAO.deleteSome(owner, msgId))
.then(postgresMessageDAO.deleteByMessageId(msgId)));
}
- private Function<MessageRepresentation, Mono<Void>>
executeDeletionCallbacks(MailboxId mailboxId, Username owner) {
- return messageRepresentation -> Flux.fromIterable(deletionCallbackList)
- .concatMap(callback -> callback.forMessage(messageRepresentation,
mailboxId, owner))
- .then();
+ private Mono<Void> dispatchMessageContentDeletionEvent(MailboxId
mailboxId, Username owner, MessageRepresentation message) {
+ return Mono.fromCallable(() ->
IOUtils.toString(message.getHeaderContent().getInputStream(),
StandardCharsets.UTF_8))
+ .subscribeOn(ReactorUtils.BLOCKING_CALL_WRAPPER)
+ .flatMap(headerContent ->
Mono.from(contentDeletionEventBus.dispatch(messageContentDeletionEvent(mailboxId,
owner, message, headerContent),
+ ImmutableSet.of())));
+ }
+
+ private MailboxEvents.MessageContentDeletionEvent
messageContentDeletionEvent(MailboxId mailboxId, Username owner,
MessageRepresentation message, String headerContent) {
+ return EventFactory.messageContentDeleted()
+ .randomEventId()
+ .user(owner)
+ .mailboxId(mailboxId)
+ .messageId(message.getMessageId())
+ .size(message.getSize())
+ .instant(message.getInternalDate().toInstant())
+ .hasAttachments(!message.getAttachments().isEmpty())
+ .bodyBlobId(message.getBodyBlobId().asString())
+ .headerContent(headerContent)
+ .build();
}
private Mono<Void> deleteBodyBlob(PostgresMessageId id, PostgresMessageDAO
postgresMessageDAO) {
diff --git
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxSessionMapperFactory.java
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxSessionMapperFactory.java
index 5685d64602..d4743b2f6a 100644
---
a/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxSessionMapperFactory.java
+++
b/mailbox/postgres/src/main/java/org/apache/james/mailbox/postgres/PostgresMailboxSessionMapperFactory.java
@@ -27,6 +27,7 @@ import org.apache.james.backends.postgres.RowLevelSecurity;
import org.apache.james.backends.postgres.utils.PostgresExecutor;
import org.apache.james.blob.api.BlobId;
import org.apache.james.blob.api.BlobStore;
+import org.apache.james.events.EventBus;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.postgres.mail.PostgresAnnotationMapper;
import org.apache.james.mailbox.postgres.mail.PostgresAttachmentMapper;
@@ -54,7 +55,7 @@ import org.apache.james.mailbox.store.mail.MessageIdMapper;
import org.apache.james.mailbox.store.mail.MessageMapper;
import org.apache.james.mailbox.store.user.SubscriptionMapper;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.annotations.VisibleForTesting;
public class PostgresMailboxSessionMapperFactory extends
MailboxSessionMapperFactory implements AttachmentMapperFactory {
@@ -145,13 +146,14 @@ public class PostgresMailboxSessionMapperFactory extends
MailboxSessionMapperFac
return createAttachmentMapper(session);
}
- protected DeleteMessageListener deleteMessageListener() {
+ @VisibleForTesting
+ protected DeleteMessageListener deleteMessageListener(EventBus
contentDeletionEventBus) {
PostgresMessageDAO.Factory postgresMessageDAOFactory = new
PostgresMessageDAO.Factory(blobIdFactory, executorFactory);
PostgresMailboxMessageDAO.Factory postgresMailboxMessageDAOFactory =
new PostgresMailboxMessageDAO.Factory(executorFactory);
PostgresAttachmentDAO.Factory attachmentDAOFactory = new
PostgresAttachmentDAO.Factory(executorFactory, blobIdFactory);
PostgresThreadDAO.Factory threadDAOFactory = new
PostgresThreadDAO.Factory(executorFactory);
return new DeleteMessageListener(blobStore,
postgresMailboxMessageDAOFactory, postgresMessageDAOFactory,
- attachmentDAOFactory, threadDAOFactory, ImmutableSet.of());
+ attachmentDAOFactory, threadDAOFactory, contentDeletionEventBus);
}
}
diff --git
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerTest.java
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerTest.java
index 453e088eff..8534477fb9 100644
---
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerTest.java
+++
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerTest.java
@@ -84,7 +84,7 @@ public class DeleteMessageListenerTest extends
DeleteMessageListenerContract {
QuotaComponents quotaComponents =
QuotaComponents.disabled(sessionProvider, mapperFactory);
MessageSearchIndex index = new SimpleMessageSearchIndex(mapperFactory,
mapperFactory, new DefaultTextExtractor(), new
UnsupportAttachmentContentLoader());
- eventBus.register(mapperFactory.deleteMessageListener());
+ eventBus.register(mapperFactory.deleteMessageListener(eventBus));
mailboxManager = new PostgresMailboxManager(mapperFactory,
sessionProvider,
messageParser, new PostgresMessageId.Factory(),
diff --git
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerWithRLSTest.java
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerWithRLSTest.java
index b2f5f67b21..be1fd7b721 100644
---
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerWithRLSTest.java
+++
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/DeleteMessageListenerWithRLSTest.java
@@ -90,7 +90,7 @@ public class DeleteMessageListenerWithRLSTest extends
DeleteMessageListenerContr
QuotaComponents quotaComponents =
QuotaComponents.disabled(sessionProvider, mapperFactory);
MessageSearchIndex index = new SimpleMessageSearchIndex(mapperFactory,
mapperFactory, new DefaultTextExtractor(), new
UnsupportAttachmentContentLoader());
- eventBus.register(mapperFactory.deleteMessageListener());
+ eventBus.register(mapperFactory.deleteMessageListener(eventBus));
mailboxManager = new PostgresMailboxManager(mapperFactory,
sessionProvider,
messageParser, new PostgresMessageId.Factory(),
diff --git
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerAttachmentTest.java
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerAttachmentTest.java
index e8beb011e3..a3dbc27696 100644
---
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerAttachmentTest.java
+++
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerAttachmentTest.java
@@ -70,8 +70,6 @@ import org.apache.james.utils.UpdatableTickingClock;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
-import com.google.common.collect.ImmutableSet;
-
public class PostgresMailboxManagerAttachmentTest extends
AbstractMailboxManagerAttachmentTest {
@RegisterExtension
@@ -110,7 +108,7 @@ public class PostgresMailboxManagerAttachmentTest extends
AbstractMailboxManager
PostgresThreadDAO.Factory threadDAOFactory = new
PostgresThreadDAO.Factory(postgresExtension.getExecutorFactory());
eventBus.register(new DeleteMessageListener(blobStore,
postgresMailboxMessageDAOFactory, postgresMessageDAOFactory,
- attachmentDAOFactory, threadDAOFactory, ImmutableSet.of()));
+ attachmentDAOFactory, threadDAOFactory, eventBus));
mailboxManager = new PostgresMailboxManager(mapperFactory,
sessionProvider,
messageParser, new PostgresMessageId.Factory(),
diff --git
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerProvider.java
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerProvider.java
index 3ffcf74a3e..3f466d365c 100644
---
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerProvider.java
+++
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresMailboxManagerProvider.java
@@ -76,7 +76,7 @@ public class PostgresMailboxManagerProvider {
QuotaComponents quotaComponents =
QuotaComponents.disabled(sessionProvider, mapperFactory);
MessageSearchIndex index = new SimpleMessageSearchIndex(mapperFactory,
mapperFactory, new DefaultTextExtractor(), new
UnsupportAttachmentContentLoader());
- eventBus.register(mapperFactory.deleteMessageListener());
+ eventBus.register(mapperFactory.deleteMessageListener(eventBus));
return new PostgresMailboxManager(mapperFactory, sessionProvider,
messageParser, new PostgresMessageId.Factory(),
diff --git
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresTestSystemFixture.java
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresTestSystemFixture.java
index b2f7569c0f..1f2b556813 100644
---
a/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresTestSystemFixture.java
+++
b/mailbox/postgres/src/test/java/org/apache/james/mailbox/postgres/PostgresTestSystemFixture.java
@@ -91,7 +91,7 @@ public class PostgresTestSystemFixture {
new UpdatableTickingClock(Instant.now()));
eventBus.register(new MailboxAnnotationListener(mapperFactory,
sessionProvider));
- eventBus.register(mapperFactory.deleteMessageListener());
+ eventBus.register(mapperFactory.deleteMessageListener(eventBus));
return postgresMailboxManager;
}
diff --git
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java
index 2c19a0b7cb..19990c73ff 100644
---
a/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java
+++
b/mailbox/store/src/main/java/org/apache/james/mailbox/store/event/EventFactory.java
@@ -213,11 +213,6 @@ public class EventFactory {
T hasAttachments(boolean hasAttachments);
}
- @FunctionalInterface
- public interface RequireHeaderBlobId<T> {
- T headerBlobId(String headerBlobId);
- }
-
@FunctionalInterface
public interface RequireBodyBlobId<T> {
T bodyBlobId(String bodyBlobId);
@@ -554,8 +549,9 @@ public class EventFactory {
private final long size;
private final Instant internalDate;
private final boolean hasAttachments;
- private final String headerBlobId;
private final String bodyBlobId;
+ private Optional<String> headerBlobId;
+ private Optional<String> headerContent;
MessageContentDeletionFinalStage(Event.EventId eventId,
Username username,
@@ -564,7 +560,6 @@ public class EventFactory {
long size,
Instant internalDate,
boolean hasAttachments,
- String headerBlobId,
String bodyBlobId) {
this.eventId = eventId;
this.username = username;
@@ -573,17 +568,29 @@ public class EventFactory {
this.size = size;
this.internalDate = internalDate;
this.hasAttachments = hasAttachments;
- this.headerBlobId = headerBlobId;
this.bodyBlobId = bodyBlobId;
+ this.headerBlobId = Optional.empty();
+ this.headerContent = Optional.empty();
+ }
+
+ public MessageContentDeletionFinalStage headerBlobId(String
headerBlobId) {
+ this.headerBlobId = Optional.ofNullable(headerBlobId);
+ return this;
+ }
+
+ public MessageContentDeletionFinalStage headerContent(String
headerContent) {
+ this.headerContent = Optional.ofNullable(headerContent);
+ return this;
}
public MailboxEvents.MessageContentDeletionEvent build() {
+ Preconditions.checkNotNull(eventId);
Preconditions.checkNotNull(username);
Preconditions.checkNotNull(mailboxId);
Preconditions.checkNotNull(messageId);
Preconditions.checkNotNull(internalDate);
- Preconditions.checkNotNull(headerBlobId);
Preconditions.checkNotNull(bodyBlobId);
+ Preconditions.checkArgument(headerBlobId.isPresent() ||
headerContent.isPresent(), "Either headerBlobId or headerContent must be
present");
return new MailboxEvents.MessageContentDeletionEvent(
eventId,
@@ -594,6 +601,7 @@ public class EventFactory {
internalDate,
hasAttachments,
headerBlobId,
+ headerContent,
bodyBlobId);
}
}
@@ -684,9 +692,9 @@ public class EventFactory {
return eventId -> user -> quotaRoot -> quotaCount -> quotaSize ->
instant -> new QuotaUsageUpdatedFinalStage(eventId, user, quotaRoot,
quotaCount, quotaSize, instant);
}
- public static
RequireEventId<RequireUser<RequireMailboxId<RequireMessageId<RequireSize<RequireInstant<RequireHasAttachments<RequireHeaderBlobId<RequireBodyBlobId<MessageContentDeletionFinalStage>>>>>>>>>
messageContentDeleted() {
- return eventId -> user -> mailboxId -> messageId -> size -> instant ->
hasAttachments -> headerBlobId -> bodyBlobId ->
- new MessageContentDeletionFinalStage(eventId, user, mailboxId,
messageId, size, instant, hasAttachments, headerBlobId, bodyBlobId);
+ public static
RequireEventId<RequireUser<RequireMailboxId<RequireMessageId<RequireSize<RequireInstant<RequireHasAttachments<RequireBodyBlobId<MessageContentDeletionFinalStage>>>>>>>>
messageContentDeleted() {
+ return eventId -> user -> mailboxId -> messageId -> size -> instant ->
hasAttachments -> bodyBlobId ->
+ new MessageContentDeletionFinalStage(eventId, user, mailboxId,
messageId, size, instant, hasAttachments, bodyBlobId);
}
public static RequireMailboxEvent<MailboxSubscribedFinalStage>
mailboxSubscribed() {
diff --git
a/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
b/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
index 0ebd94cca6..c8c0e8b041 100644
---
a/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
+++
b/server/apps/postgres-app/src/main/java/org/apache/james/PostgresJamesServerMain.java
@@ -55,6 +55,7 @@ import
org.apache.james.modules.events.PostgresDeadLetterModule;
import org.apache.james.modules.mailbox.DefaultEventModule;
import org.apache.james.modules.mailbox.PostgresDeletedMessageVaultModule;
import org.apache.james.modules.mailbox.PostgresMailboxModule;
+import
org.apache.james.modules.mailbox.PostgresMemoryContentDeletionEventBusModule;
import org.apache.james.modules.mailbox.RLSSupportPostgresMailboxModule;
import org.apache.james.modules.mailbox.TikaMailboxModule;
import org.apache.james.modules.plugins.QuotaMailingModule;
@@ -229,7 +230,8 @@ public class PostgresJamesServerMain implements
JamesServerMain {
case IN_MEMORY:
return List.of(
new DefaultEventModule(),
- new ActiveMQQueueModule());
+ new ActiveMQQueueModule(),
+ new PostgresMemoryContentDeletionEventBusModule());
case RABBITMQ:
return List.of(
Modules.override(new DefaultEventModule()).with(new
MailboxEventBusModule()),
diff --git
a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/data/CassandraJmapModule.java
b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/data/CassandraJmapModule.java
index 4a53aa0b20..b710d14515 100644
---
a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/data/CassandraJmapModule.java
+++
b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/data/CassandraJmapModule.java
@@ -42,6 +42,7 @@ import
org.apache.james.jmap.api.projections.DefaultEmailQueryViewManager;
import org.apache.james.jmap.api.projections.EmailQueryView;
import org.apache.james.jmap.api.projections.EmailQueryViewManager;
import org.apache.james.jmap.api.projections.MessageFastViewProjection;
+import
org.apache.james.jmap.api.projections.MessageFastViewProjectionDeletionListener;
import
org.apache.james.jmap.api.projections.MessageFastViewProjectionHealthCheck;
import org.apache.james.jmap.api.pushsubscription.PushDeleteUserDataTaskStep;
import org.apache.james.jmap.api.pushsubscription.PushSubscriptionRepository;
@@ -57,7 +58,6 @@ import
org.apache.james.jmap.cassandra.projections.CassandraEmailQueryView;
import
org.apache.james.jmap.cassandra.projections.CassandraEmailQueryViewDataDefinition;
import
org.apache.james.jmap.cassandra.projections.CassandraMessageFastViewProjection;
import
org.apache.james.jmap.cassandra.projections.CassandraMessageFastViewProjectionDataDefinition;
-import
org.apache.james.jmap.cassandra.projections.CassandraMessageFastViewProjectionDeletionListener;
import
org.apache.james.jmap.cassandra.pushsubscription.CassandraPushSubscriptionDataDefinition;
import
org.apache.james.jmap.cassandra.pushsubscription.CassandraPushSubscriptionRepository;
import org.apache.james.jmap.cassandra.upload.CassandraUploadRepository;
@@ -121,7 +121,7 @@ public class CassandraJmapModule extends AbstractModule {
Multibinder.newSetBinder(binder(),
EventListener.ReactiveGroupEventListener.class, Names.named(CONTENT_DELETION))
.addBinding()
- .to(CassandraMessageFastViewProjectionDeletionListener.class);
+ .to(MessageFastViewProjectionDeletionListener.class);
Multibinder.newSetBinder(binder(), UsernameChangeTaskStep.class)
.addBinding()
diff --git
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/event/ContentDeletionEventBusModule.java
b/server/container/guice/distributed/src/main/java/org/apache/james/modules/event/ContentDeletionEventBusModule.java
index 72a4cc07ae..5e14f09063 100644
---
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/event/ContentDeletionEventBusModule.java
+++
b/server/container/guice/distributed/src/main/java/org/apache/james/modules/event/ContentDeletionEventBusModule.java
@@ -31,13 +31,11 @@ import org.apache.james.backends.rabbitmq.ReceiverProvider;
import org.apache.james.backends.rabbitmq.SimpleConnectionPool;
import org.apache.james.core.healthcheck.HealthCheck;
import org.apache.james.event.json.MailboxEventSerializer;
-import org.apache.james.events.Event;
import org.apache.james.events.EventBus;
import org.apache.james.events.EventBusId;
import org.apache.james.events.EventBusReconnectionHandler;
import org.apache.james.events.EventDeadLetters;
import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
import org.apache.james.events.GroupRegistrationHandler;
import org.apache.james.events.KeyReconnectionHandler;
import org.apache.james.events.RabbitEventBusConsumerHealthCheck;
@@ -50,7 +48,6 @@ import
org.apache.james.mailbox.cassandra.DeleteMessageListener;
import org.apache.james.metrics.api.MetricFactory;
import org.apache.james.utils.InitializationOperation;
import org.apache.james.utils.InitilizationOperationBuilder;
-import org.reactivestreams.Publisher;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
@@ -60,31 +57,9 @@ import com.google.inject.multibindings.Multibinder;
import com.google.inject.multibindings.ProvidesIntoSet;
import com.google.inject.name.Names;
-import reactor.core.publisher.Mono;
import reactor.rabbitmq.Sender;
public class ContentDeletionEventBusModule extends AbstractModule {
- public static class NoopListener implements
EventListener.ReactiveGroupEventListener {
- public static class NoopListenerGroup extends Group {
-
- }
-
- @Override
- public Group getDefaultGroup() {
- return new NoopListenerGroup();
- }
-
- @Override
- public Publisher<Void> reactiveEvent(Event event) {
- return Mono.empty();
- }
-
- @Override
- public boolean isHandling(Event event) {
- return false;
- }
- }
-
public static final String CONTENT_DELETION = "contentDeletion";
@Override
@@ -102,10 +77,6 @@ public class ContentDeletionEventBusModule extends
AbstractModule {
.init(() -> {
instance.start();
contentDeletionListeners.forEach(instance::register);
-
- // workaround for Postgres app to make the content deletion
queue created and pass tests
- // TODO remove after refactoring JAMES-4154 for Postgres app
- instance.register(new NoopListener());
});
}
diff --git
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DistributedDeletedMessageVaultModule.java
b/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DistributedDeletedMessageVaultModule.java
index 319a69fd69..e39b8fa0fa 100644
---
a/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DistributedDeletedMessageVaultModule.java
+++
b/server/container/guice/distributed/src/main/java/org/apache/james/modules/mailbox/DistributedDeletedMessageVaultModule.java
@@ -24,6 +24,7 @@ import org.apache.james.events.EventListener;
import org.apache.james.mailbox.cassandra.DeleteMessageListener;
import org.apache.james.modules.vault.DeletedMessageVaultModule;
import org.apache.james.vault.DeletedMessageVault;
+import org.apache.james.vault.DeletedMessageVaultDeletionListener;
import org.apache.james.vault.blob.BlobStoreDeletedMessageVault;
import org.apache.james.vault.blob.BucketNameGenerator;
import
org.apache.james.vault.dto.DeletedMessageWithStorageInformationConverter;
diff --git
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
index a5fd44f7e6..cd39b3463e 100644
---
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
+++
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
@@ -19,17 +19,20 @@
package org.apache.james.modules.mailbox;
+import static
org.apache.james.mailbox.postgres.DeleteMessageListener.CONTENT_DELETION;
+
import org.apache.james.backends.postgres.PostgresDataDefinition;
-import org.apache.james.mailbox.postgres.DeleteMessageListener;
+import org.apache.james.events.EventListener;
import org.apache.james.modules.vault.DeletedMessageVaultModule;
+import org.apache.james.vault.DeletedMessageVaultDeletionListener;
import org.apache.james.vault.metadata.DeletedMessageMetadataVault;
import
org.apache.james.vault.metadata.PostgresDeletedMessageMetadataDataDefinition;
import org.apache.james.vault.metadata.PostgresDeletedMessageMetadataVault;
-import
org.apache.james.vault.metadata.PostgresDeletedMessageVaultDeletionCallback;
import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
public class PostgresDeletedMessageVaultModule extends AbstractModule {
@Override
@@ -43,8 +46,8 @@ public class PostgresDeletedMessageVaultModule extends
AbstractModule {
bind(DeletedMessageMetadataVault.class)
.to(PostgresDeletedMessageMetadataVault.class);
- Multibinder.newSetBinder(binder(),
DeleteMessageListener.DeletionCallback.class)
+ Multibinder.newSetBinder(binder(),
EventListener.ReactiveGroupEventListener.class, Names.named(CONTENT_DELETION))
.addBinding()
- .to(PostgresDeletedMessageVaultDeletionCallback.class);
+ .to(DeletedMessageVaultDeletionListener.class);
}
}
diff --git
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMailboxModule.java
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMailboxModule.java
index 50f6f96525..e7e9d35226 100644
---
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMailboxModule.java
+++
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMailboxModule.java
@@ -168,7 +168,6 @@ public class PostgresMailboxModule extends AbstractModule {
Multibinder.newSetBinder(binder(),
EventListener.ReactiveGroupEventListener.class)
.addBinding().to(DeleteMessageListener.class);
- Multibinder.newSetBinder(binder(),
DeleteMessageListener.DeletionCallback.class);
bind(MailboxManager.class).annotatedWith(Names.named(MAILBOXMANAGER_NAME)).to(MailboxManager.class);
bind(MailboxManagerConfiguration.class).toInstance(MailboxManagerConfiguration.DEFAULT);
diff --git
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMemoryContentDeletionEventBusModule.java
similarity index 50%
copy from
server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
copy to
server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMemoryContentDeletionEventBusModule.java
index a5fd44f7e6..19316aa1dc 100644
---
a/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresDeletedMessageVaultModule.java
+++
b/server/container/guice/mailbox-postgres/src/main/java/org/apache/james/modules/mailbox/PostgresMemoryContentDeletionEventBusModule.java
@@ -19,32 +19,39 @@
package org.apache.james.modules.mailbox;
-import org.apache.james.backends.postgres.PostgresDataDefinition;
-import org.apache.james.mailbox.postgres.DeleteMessageListener;
-import org.apache.james.modules.vault.DeletedMessageVaultModule;
-import org.apache.james.vault.metadata.DeletedMessageMetadataVault;
-import
org.apache.james.vault.metadata.PostgresDeletedMessageMetadataDataDefinition;
-import org.apache.james.vault.metadata.PostgresDeletedMessageMetadataVault;
-import
org.apache.james.vault.metadata.PostgresDeletedMessageVaultDeletionCallback;
+import static
org.apache.james.mailbox.postgres.DeleteMessageListener.CONTENT_DELETION;
+
+import java.util.Set;
+
+import jakarta.inject.Named;
+
+import org.apache.james.events.EventBus;
+import org.apache.james.events.EventListener;
+import org.apache.james.lifecycle.api.Startable;
+import org.apache.james.utils.InitializationOperation;
+import org.apache.james.utils.InitilizationOperationBuilder;
import com.google.inject.AbstractModule;
-import com.google.inject.Scopes;
import com.google.inject.multibindings.Multibinder;
+import com.google.inject.multibindings.ProvidesIntoSet;
+import com.google.inject.name.Names;
-public class PostgresDeletedMessageVaultModule extends AbstractModule {
- @Override
- protected void configure() {
- install(new DeletedMessageVaultModule());
+public class PostgresMemoryContentDeletionEventBusModule extends
AbstractModule {
+ public static class ContentDeletionListenersLoader implements Startable {
- Multibinder<PostgresDataDefinition> postgresDataDefinitions =
Multibinder.newSetBinder(binder(), PostgresDataDefinition.class);
-
postgresDataDefinitions.addBinding().toInstance(PostgresDeletedMessageMetadataDataDefinition.MODULE);
+ }
- bind(PostgresDeletedMessageMetadataVault.class).in(Scopes.SINGLETON);
- bind(DeletedMessageMetadataVault.class)
- .to(PostgresDeletedMessageMetadataVault.class);
+ @Override
+ protected void configure() {
+
bind(EventBus.class).annotatedWith(Names.named(CONTENT_DELETION)).to(EventBus.class);
+ Multibinder.newSetBinder(binder(),
EventListener.ReactiveGroupEventListener.class, Names.named(CONTENT_DELETION));
+ }
- Multibinder.newSetBinder(binder(),
DeleteMessageListener.DeletionCallback.class)
- .addBinding()
- .to(PostgresDeletedMessageVaultDeletionCallback.class);
+ @ProvidesIntoSet
+ public InitializationOperation registerListener(@Named(CONTENT_DELETION)
EventBus contentDeletionEventBus,
+ @Named(CONTENT_DELETION)
Set<EventListener.ReactiveGroupEventListener> contentDeletionListeners) {
+ return InitilizationOperationBuilder
+ .forClass(ContentDeletionListenersLoader.class)
+ .init(() ->
contentDeletionListeners.forEach(contentDeletionEventBus::register));
}
}
diff --git
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataJmapModule.java
b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataJmapModule.java
index 19ecf9a84e..ca9883e9ca 100644
---
a/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataJmapModule.java
+++
b/server/container/guice/postgres-common/src/main/java/org/apache/james/modules/data/PostgresDataJmapModule.java
@@ -19,7 +19,10 @@
package org.apache.james.modules.data;
+import static
org.apache.james.mailbox.postgres.DeleteMessageListener.CONTENT_DELETION;
+
import org.apache.james.core.healthcheck.HealthCheck;
+import org.apache.james.events.EventListener;
import org.apache.james.jmap.api.filtering.FilteringManagement;
import org.apache.james.jmap.api.filtering.FiltersDeleteUserDataTaskStep;
import
org.apache.james.jmap.api.filtering.impl.EventSourcingFilteringManagement;
@@ -29,6 +32,7 @@ import
org.apache.james.jmap.api.identity.IdentityUserDeletionTaskStep;
import org.apache.james.jmap.api.projections.EmailQueryView;
import org.apache.james.jmap.api.projections.EmailQueryViewManager;
import org.apache.james.jmap.api.projections.MessageFastViewProjection;
+import
org.apache.james.jmap.api.projections.MessageFastViewProjectionDeletionListener;
import
org.apache.james.jmap.api.projections.MessageFastViewProjectionHealthCheck;
import org.apache.james.jmap.api.pushsubscription.PushDeleteUserDataTaskStep;
import org.apache.james.jmap.api.upload.UploadRepository;
@@ -37,9 +41,7 @@ import
org.apache.james.jmap.postgres.identity.PostgresCustomIdentityDAO;
import org.apache.james.jmap.postgres.projections.PostgresEmailQueryView;
import
org.apache.james.jmap.postgres.projections.PostgresEmailQueryViewManager;
import
org.apache.james.jmap.postgres.projections.PostgresMessageFastViewProjection;
-import
org.apache.james.jmap.postgres.projections.PostgresMessageFastViewProjectionDeletionCallback;
import org.apache.james.jmap.postgres.upload.PostgresUploadRepository;
-import org.apache.james.mailbox.postgres.DeleteMessageListener;
import org.apache.james.mailbox.store.extractor.DefaultTextExtractor;
import org.apache.james.user.api.DeleteUserDataTaskStep;
import org.apache.james.user.api.UsernameChangeTaskStep;
@@ -47,6 +49,7 @@ import org.apache.james.user.api.UsernameChangeTaskStep;
import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
public class PostgresDataJmapModule extends AbstractModule {
@@ -67,9 +70,9 @@ public class PostgresDataJmapModule extends AbstractModule {
bind(PostgresMessageFastViewProjection.class).in(Scopes.SINGLETON);
bind(MessageFastViewProjection.class).to(PostgresMessageFastViewProjection.class);
- Multibinder.newSetBinder(binder(),
DeleteMessageListener.DeletionCallback.class)
+ Multibinder.newSetBinder(binder(),
EventListener.ReactiveGroupEventListener.class, Names.named(CONTENT_DELETION))
.addBinding()
- .to(PostgresMessageFastViewProjectionDeletionCallback.class);
+ .to(MessageFastViewProjectionDeletionListener.class);
bind(PostgresEmailQueryView.class).in(Scopes.SINGLETON);
bind(EmailQueryView.class).to(PostgresEmailQueryView.class);
diff --git
a/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresMessageFastViewProjectionDeletionCallback.java
b/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresMessageFastViewProjectionDeletionCallback.java
deleted file mode 100644
index 3cbacec71a..0000000000
---
a/server/data/data-jmap-postgres/src/main/java/org/apache/james/jmap/postgres/projections/PostgresMessageFastViewProjectionDeletionCallback.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you under the Apache License, Version 2.0 (the *
- * "License"); you may not use this file except in compliance *
- * with the License. You may obtain a copy of the License at *
- * *
- * http://www.apache.org/licenses/LICENSE-2.0 *
- * *
- * Unless required by applicable law or agreed to in writing, *
- * software distributed under the License is distributed on an *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
- * KIND, either express or implied. See the License for the *
- * specific language governing permissions and limitations *
- * under the License. *
- ****************************************************************/
-
-package org.apache.james.jmap.postgres.projections;
-
-import jakarta.inject.Inject;
-
-import org.apache.james.core.Username;
-import org.apache.james.jmap.api.projections.MessageFastViewProjection;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.postgres.DeleteMessageListener;
-import org.apache.james.mailbox.postgres.mail.MessageRepresentation;
-
-import reactor.core.publisher.Mono;
-
-public class PostgresMessageFastViewProjectionDeletionCallback implements
DeleteMessageListener.DeletionCallback {
- private final MessageFastViewProjection messageFastViewProjection;
-
- @Inject
- public
PostgresMessageFastViewProjectionDeletionCallback(MessageFastViewProjection
messageFastViewProjection) {
- this.messageFastViewProjection = messageFastViewProjection;
- }
-
- @Override
- public Mono<Void> forMessage(MessageRepresentation messageRepresentation,
MailboxId mailboxId, Username owner) {
- return
Mono.from(messageFastViewProjection.delete(messageRepresentation.getMessageId()));
- }
-}
diff --git
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraMessageFastViewProjectionDeletionListener.java
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionDeletionListener.java
similarity index 79%
rename from
server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraMessageFastViewProjectionDeletionListener.java
rename to
server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionDeletionListener.java
index ec5fd46e3c..3ffc9973f2 100644
---
a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/projections/CassandraMessageFastViewProjectionDeletionListener.java
+++
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/projections/MessageFastViewProjectionDeletionListener.java
@@ -17,30 +17,29 @@
* under the License. *
****************************************************************/
-package org.apache.james.jmap.cassandra.projections;
+package org.apache.james.jmap.api.projections;
import jakarta.inject.Inject;
import org.apache.james.events.Event;
import org.apache.james.events.EventListener;
import org.apache.james.events.Group;
-import org.apache.james.jmap.api.projections.MessageFastViewProjection;
import org.apache.james.mailbox.events.MailboxEvents;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
-public class CassandraMessageFastViewProjectionDeletionListener implements
EventListener.ReactiveGroupEventListener {
- public static class
CassandraMessageFastViewProjectionDeletionListenerGroup extends Group {
+public class MessageFastViewProjectionDeletionListener implements
EventListener.ReactiveGroupEventListener {
+ public static class MessageFastViewProjectionDeletionListenerGroup extends
Group {
}
- private static final Group GROUP = new
CassandraMessageFastViewProjectionDeletionListenerGroup();
+ private static final Group GROUP = new
MessageFastViewProjectionDeletionListenerGroup();
private final MessageFastViewProjection messageFastViewProjection;
@Inject
- public
CassandraMessageFastViewProjectionDeletionListener(MessageFastViewProjection
messageFastViewProjection) {
+ public MessageFastViewProjectionDeletionListener(MessageFastViewProjection
messageFastViewProjection) {
this.messageFastViewProjection = messageFastViewProjection;
}
diff --git
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/pom.xml
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/pom.xml
index aa8a06b6b3..7adc5557bb 100644
---
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/pom.xml
+++
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/pom.xml
@@ -51,6 +51,12 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>apache-james-backends-rabbitmq</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>${james.groupId}</groupId>
<artifactId>apache-james-mailbox-opensearch</artifactId>
diff --git
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/PostgresDeletedMessageVaultIntegrationTest.java
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/PostgresDeletedMessageVaultIntegrationTest.java
index e7bcb0daaa..4ea638622b 100644
---
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/PostgresDeletedMessageVaultIntegrationTest.java
+++
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/PostgresDeletedMessageVaultIntegrationTest.java
@@ -20,35 +20,19 @@
package org.apache.james.webadmin.integration.vault;
import static
org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT;
-import static org.awaitility.Durations.FIVE_HUNDRED_MILLISECONDS;
-import static org.awaitility.Durations.ONE_MINUTE;
-import org.apache.james.GuiceJamesServer;
import org.apache.james.JamesServerBuilder;
import org.apache.james.JamesServerExtension;
import org.apache.james.PostgresJamesConfiguration;
import org.apache.james.PostgresJamesServerMain;
import org.apache.james.SearchConfiguration;
import org.apache.james.backends.postgres.PostgresExtension;
-import org.apache.james.mailbox.DefaultMailboxes;
-import org.apache.james.modules.protocols.ImapGuiceProbe;
-import org.apache.james.modules.protocols.SmtpGuiceProbe;
-import org.apache.james.utils.DataProbeImpl;
-import org.apache.james.utils.SMTPMessageSender;
-import org.apache.james.utils.TestIMAPClient;
-import org.apache.james.utils.WebAdminGuiceProbe;
+import org.apache.james.modules.TestJMAPServerModule;
+import org.apache.james.modules.blobstore.BlobStoreConfiguration;
import org.apache.james.vault.VaultConfiguration;
-import org.apache.james.webadmin.WebAdminUtils;
-import org.awaitility.Awaitility;
-import org.awaitility.core.ConditionFactory;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
-import io.restassured.config.ParamConfig;
-import io.restassured.specification.RequestSpecification;
-
-class PostgresDeletedMessageVaultIntegrationTest {
+class PostgresDeletedMessageVaultIntegrationTest extends
DeletedMessageVaultIntegrationTest {
@RegisterExtension
static JamesServerExtension jamesServerExtension = new
JamesServerBuilder<PostgresJamesConfiguration>(tmpDir ->
PostgresJamesConfiguration.builder()
@@ -58,73 +42,20 @@ class PostgresDeletedMessageVaultIntegrationTest {
.usersRepository(DEFAULT)
.eventBusImpl(PostgresJamesConfiguration.EventBusImpl.IN_MEMORY)
.deletedMessageVaultConfiguration(VaultConfiguration.ENABLED_DEFAULT)
+ .blobStore(BlobStoreConfiguration.builder()
+ .postgres()
+ .disableCache()
+ .deduplication()
+ .noCryptoConfig())
.build())
- .server(PostgresJamesServerMain::createServer)
+ .server(configuration ->
PostgresJamesServerMain.createServer(configuration)
+ .overrideWith(new TestJMAPServerModule()))
.extension(PostgresExtension.empty())
- .lifeCycle(JamesServerExtension.Lifecycle.PER_CLASS)
+ .extension(new ClockExtension())
.build();
- private static final ConditionFactory AWAIT = Awaitility.await()
- .atMost(ONE_MINUTE)
- .with()
- .pollInterval(FIVE_HUNDRED_MILLISECONDS);
- private static final String DOMAIN = "james.local";
- private static final String USER = "toto@" + DOMAIN;
- private static final String PASSWORD = "123456";
- private static final String JAMES_SERVER_HOST = "127.0.0.1";
-
- private TestIMAPClient testIMAPClient;
- private SMTPMessageSender smtpMessageSender;
- private RequestSpecification webAdminApi;
-
- @BeforeEach
- void setUp(GuiceJamesServer jamesServer) throws Exception {
- this.testIMAPClient = new TestIMAPClient();
- this.smtpMessageSender = new SMTPMessageSender(DOMAIN);
- this.webAdminApi =
WebAdminUtils.spec(jamesServer.getProbe(WebAdminGuiceProbe.class).getWebAdminPort())
- .config(WebAdminUtils.defaultConfig()
- .paramConfig(new ParamConfig().replaceAllParameters()));
+ @Override
+ protected void awaitSearchUpToDate() {
- jamesServer.getProbe(DataProbeImpl.class)
- .fluent()
- .addDomain(DOMAIN)
- .addUser(USER, PASSWORD);
}
-
- @Test
- void restoreDeletedMessageShouldSucceed(GuiceJamesServer jamesServer)
throws Exception {
- // Create a message
- int imapPort =
jamesServer.getProbe(ImapGuiceProbe.class).getImapPort();
- smtpMessageSender.connect(JAMES_SERVER_HOST,
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
- .authenticate(USER, PASSWORD)
- .sendMessageWithHeaders(USER, USER, "Subject:
thisIsASubject\r\n\r\nBody");
- testIMAPClient.connect(JAMES_SERVER_HOST, imapPort)
- .login(USER, PASSWORD)
- .select(TestIMAPClient.INBOX)
- .awaitMessageCount(AWAIT, 1);
-
- // Delete the message
- testIMAPClient.setFlagsForAllMessagesInMailbox("\\Deleted");
- testIMAPClient.expunge();
- testIMAPClient.awaitNoMessage(AWAIT);
-
- // Restore the message using the Deleted message vault webadmin
endpoint
- String restoreBySubjectQuery = "{" +
- " \"combinator\": \"and\"," +
- " \"limit\": 1," +
- " \"criteria\": [" +
- " {" +
- " \"fieldName\": \"subject\"," +
- " \"operator\": \"equals\"," +
- " \"value\": \"thisIsASubject\"" +
- " }" +
- " ]" +
- "}";
-
DeletedMessagesVaultRequests.restoreMessagesForUserWithQuery(webAdminApi, USER,
restoreBySubjectQuery);
-
- // await the message to be restored
- testIMAPClient.select(DefaultMailboxes.RESTORED_MESSAGES)
- .awaitMessageCount(AWAIT, 1);
- }
-
}
diff --git
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/RabbitMQPostgresDeletedMessageVaultIntegrationTest.java
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/RabbitMQPostgresDeletedMessageVaultIntegrationTest.java
new file mode 100644
index 0000000000..7bbe7dfebb
--- /dev/null
+++
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/vault/RabbitMQPostgresDeletedMessageVaultIntegrationTest.java
@@ -0,0 +1,66 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.webadmin.integration.vault;
+
+import static
org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT;
+
+import org.apache.james.JamesServerBuilder;
+import org.apache.james.JamesServerExtension;
+import org.apache.james.PostgresJamesConfiguration;
+import org.apache.james.PostgresJamesServerMain;
+import org.apache.james.SearchConfiguration;
+import org.apache.james.backends.postgres.PostgresExtension;
+import org.apache.james.modules.RabbitMQExtension;
+import org.apache.james.modules.TestJMAPServerModule;
+import org.apache.james.modules.blobstore.BlobStoreConfiguration;
+import org.apache.james.vault.VaultConfiguration;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+class RabbitMQPostgresDeletedMessageVaultIntegrationTest extends
DeletedMessageVaultIntegrationTest {
+ @RegisterExtension
+ static RabbitMQExtension rabbitMQExtension = new RabbitMQExtension();
+
+ @RegisterExtension
+ static JamesServerExtension jamesServerExtension = new
JamesServerBuilder<PostgresJamesConfiguration>(tmpDir ->
+ PostgresJamesConfiguration.builder()
+ .workingDirectory(tmpDir)
+ .configurationFromClasspath()
+ .searchConfiguration(SearchConfiguration.scanning())
+ .usersRepository(DEFAULT)
+ .eventBusImpl(PostgresJamesConfiguration.EventBusImpl.RABBITMQ)
+
.deletedMessageVaultConfiguration(VaultConfiguration.ENABLED_DEFAULT)
+ .blobStore(BlobStoreConfiguration.builder()
+ .postgres()
+ .disableCache()
+ .deduplication()
+ .noCryptoConfig())
+ .build())
+ .server(configuration ->
PostgresJamesServerMain.createServer(configuration)
+ .overrideWith(new TestJMAPServerModule()))
+ .extension(PostgresExtension.empty())
+ .extension(new ClockExtension())
+ .extension(rabbitMQExtension)
+ .build();
+
+ @Override
+ protected void awaitSearchUpToDate() {
+
+ }
+}
diff --git
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/resources/listeners.xml
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/resources/listeners.xml
index ff2e517232..828ef9009b 100644
---
a/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/resources/listeners.xml
+++
b/server/protocols/webadmin-integration-test/postgres-webadmin-integration-test/src/test/resources/listeners.xml
@@ -46,4 +46,8 @@
<name>second</name>
</configuration>
</listener>
+ <listener>
+ <class>org.apache.james.jmap.event.PopulateEmailQueryViewListener</class>
+ <async>true</async>
+ </listener>
</listeners>
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]