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 2021/02/04 05:02:28 UTC
[james-project] 02/18: JAMES-3498 Move as is the In VM
implementation
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 c4f6a0d82af3560f07aba5889a8c8d3d5dd48d99
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Jan 25 13:47:59 2021 +0700
JAMES-3498 Move as is the In VM implementation
---
event-bus/in-vm/pom.xml | 44 +
.../listeners/SetCustomFlagOnBigMessages.java | 6 +-
.../apache/james/mailbox/events/MailboxEvents.java | 582 ------------
.../mailbox/events/MailboxIdRegistrationKey.java | 78 --
.../james/mailbox/events/MessageMoveEvent.java | 154 ----
.../mailbox/events/RetryBackoffConfiguration.java | 125 ---
.../java/org/apache/james/mailbox/EventTest.java | 2 +-
.../apache/james/mailbox/MailboxListenerTest.java | 16 +-
.../mailbox/MailboxManagerStressContract.java | 4 +-
.../apache/james/mailbox/MailboxManagerTest.java | 16 +-
.../apache/james/mailbox/MessageMoveEventTest.java | 2 +-
.../mailbox/events/ErrorHandlingContract.java | 367 --------
.../events/EventBusConcurrentTestContract.java | 240 -----
.../james/mailbox/events/EventBusContract.java | 73 --
.../james/mailbox/events/EventBusTestFixture.java | 145 ---
.../mailbox/events/EventDeadLettersContract.java | 493 -----------
.../EventDeadLettersHealthCheckContract.java | 134 ---
.../apache/james/mailbox/events/GroupContract.java | 504 -----------
.../org/apache/james/mailbox/events/GroupTest.java | 135 ---
.../james/mailbox/events/InsertionIdTest.java | 57 --
.../apache/james/mailbox/events/KeyContract.java | 458 ----------
.../events/MailboxIdRegistrationKeyTest.java | 60 --
.../events/RetryBackoffConfigurationTest.java | 141 ---
.../james/mailbox/model/MessageMovesTest.java | 2 +-
mailbox/cassandra/pom.xml | 10 +-
.../mailbox/cassandra/DeleteMessageListener.java | 4 +-
.../cassandra/MailboxOperationLoggingListener.java | 6 +-
.../cassandra/CassandraCombinationManagerTest.java | 8 +-
.../cassandra/CassandraMailboxManagerProvider.java | 8 +-
.../CassandraMessageIdManagerStorageTest.java | 8 +-
.../cassandra/CassandraTestSystemFixture.java | 8 +-
.../CassandraMailboxManagerAttachmentTest.java | 8 +-
mailbox/elasticsearch/pom.xml | 10 +-
.../mailbox/events/CassandraEventDeadLetters.java | 89 --
.../events/CassandraEventDeadLettersDAO.java | 132 ---
.../events/CassandraEventDeadLettersGroupDAO.java | 71 --
.../events/CassandraEventDeadLettersModule.java | 46 -
.../CassandraEventDeadLettersGroupTable.java | 27 -
.../tables/CassandraEventDeadLettersTable.java | 29 -
.../events/CassandraEventDeadLettersDAOTest.java | 145 ---
.../CassandraEventDeadLettersGroupDAOTest.java | 60 --
.../CassandraEventDeadLettersHealthCheckTest.java | 70 --
.../events/CassandraEventDeadLettersTest.java | 50 --
mailbox/event/event-memory/pom.xml | 79 --
.../apache/james/mailbox/events/InVMEventBus.java | 134 ---
.../mailbox/events/MemoryEventDeadLetters.java | 95 --
.../mailbox/events/delivery/EventDelivery.java | 134 ---
.../mailbox/events/delivery/InVmEventDelivery.java | 104 ---
.../james/mailbox/events/InVMEventBusTest.java | 55 --
.../MemoryEventDeadLettersHealthCheckTest.java | 59 --
.../mailbox/events/MemoryEventDeadLettersTest.java | 38 -
.../events/delivery/InVmEventDeliveryTest.java | 253 ------
mailbox/event/event-rabbitmq/pom.xml | 10 +-
.../apache/james/mailbox/events/EventBusId.java | 72 --
.../james/mailbox/events/EventDispatcher.java | 201 -----
.../james/mailbox/events/GroupConsumerRetry.java | 145 ---
.../james/mailbox/events/GroupRegistration.java | 198 -----
.../mailbox/events/GroupRegistrationHandler.java | 93 --
.../mailbox/events/KeyReconnectionHandler.java | 60 --
.../james/mailbox/events/KeyRegistration.java | 35 -
.../mailbox/events/KeyRegistrationHandler.java | 204 -----
.../mailbox/events/LocalListenerRegistry.java | 112 ---
.../mailbox/events/MailboxListenerExecutor.java | 56 --
.../james/mailbox/events/RabbitMQEventBus.java | 177 ----
.../james/mailbox/events/RegistrationBinder.java | 56 --
.../mailbox/events/RegistrationQueueName.java | 32 -
.../james/mailbox/events/RoutingKeyConverter.java | 92 --
.../james/mailbox/events/WaitDelayGenerator.java | 83 --
.../james/mailbox/events/EventBusIdTest.java | 50 --
.../mailbox/events/LocalListenerRegistryTest.java | 256 ------
.../james/mailbox/events/NetworkErrorTest.java | 89 --
...RabbitMQEventBusDeadLetterQueueUpgradeTest.java | 88 --
.../james/mailbox/events/RabbitMQEventBusTest.java | 980 ---------------------
.../mailbox/events/RoutingKeyConverterTest.java | 144 ---
.../mailbox/events/WaitDelayGeneratorTest.java | 103 ---
.../apache/james/event/json/EventSerializer.scala | 8 +-
.../james/event/json/AddedSerializationTest.java | 2 +-
.../event/json/ExpungedSerializationTest.java | 2 +-
.../event/json/FlagsUpdatedSerializationTest.java | 2 +-
.../MailboxACLUpdatedEventSerializationTest.java | 2 +-
.../event/json/MailboxAddedSerializationTest.java | 2 +-
.../json/MailboxDeletionSerializationTest.java | 2 +-
.../json/MailboxRenamedSerializationTest.java | 2 +-
.../json/MessageMoveEventSerializationTest.java | 2 +-
.../QuotaUsageUpdatedEventSerializationTest.java | 2 +-
mailbox/jpa/pom.xml | 10 +-
.../mailbox/jpa/JpaMailboxManagerProvider.java | 8 +-
mailbox/lucene/pom.xml | 10 +-
mailbox/maildir/pom.xml | 6 +-
.../maildir/MaildirMailboxManagerProvider.java | 8 +-
.../manager/InMemoryIntegrationResources.java | 8 +-
mailbox/plugin/quota-mailing/pom.xml | 10 +-
.../listeners/QuotaThresholdCrossingListener.java | 2 +-
.../QuotaThresholdListenersTestSystem.java | 8 +-
.../events/ElasticSearchQuotaMailboxListener.java | 2 +-
.../json/QuotaRatioToElasticSearchJson.java | 2 +-
.../json/QuotaRatioToElasticSearchJsonTest.java | 2 +-
.../mailbox/spamassassin/SpamAssassinListener.java | 4 +-
.../spamassassin/SpamAssassinListenerTest.java | 4 +-
mailbox/pom.xml | 1 -
mailbox/spring/pom.xml | 8 +-
.../resources/META-INF/spring/event-system.xml | 8 +-
mailbox/store/pom.xml | 2 +-
.../james/mailbox/store/StoreMailboxManager.java | 2 +-
.../james/mailbox/store/StoreMessageIdManager.java | 2 +-
.../james/mailbox/store/StoreMessageManager.java | 2 +-
.../james/mailbox/store/StoreRightManager.java | 2 +-
.../james/mailbox/store/event/EventFactory.java | 18 +-
.../store/event/MailboxAnnotationListener.java | 2 +-
.../store/quota/ListeningCurrentQuotaUpdater.java | 8 +-
.../store/search/ListeningMessageSearchIndex.java | 10 +-
.../AbstractMessageIdManagerSideEffectTest.java | 18 +-
.../mailbox/store/MessageIdManagerTestSystem.java | 2 +-
.../mailbox/store/StoreMailboxManagerTest.java | 8 +-
.../store/event/MailboxAnnotationListenerTest.java | 4 +-
.../quota/ListeningCurrentQuotaUpdaterTest.java | 6 +-
mpt/impl/imap-mailbox/cassandra/pom.xml | 8 +-
.../cassandra/host/CassandraHostSystem.java | 8 +-
mpt/impl/imap-mailbox/elasticsearch/pom.xml | 10 +-
mpt/impl/imap-mailbox/jpa/pom.xml | 2 +-
.../mpt/imapmailbox/jpa/host/JPAHostSystem.java | 8 +-
mpt/impl/imap-mailbox/lucenesearch/pom.xml | 2 +-
mpt/impl/imap-mailbox/maildir/pom.xml | 8 +-
.../maildir/host/MaildirHostSystem.java | 8 +-
.../rabbitmq/host/RabbitMQEventBusHostSystem.java | 12 +-
pom.xml | 10 +-
.../apache/james/imap/processor/IdleProcessor.java | 8 +-
.../imap/processor/base/SelectedMailboxImpl.java | 14 +-
.../processor/base/MailboxEventAnalyserTest.java | 18 +-
.../processor/base/SelectedMailboxImplTest.java | 10 +-
.../james/app/spring/JamesSpringContextTest.java | 2 +-
.../modules/mailbox/CassandraDeadLetterModule.java | 8 +-
.../modules/event/RabbitMQEventBusModule.java | 10 +-
server/container/guice/mailbox/pom.xml | 6 +-
.../james/modules/mailbox/DefaultEventModule.java | 8 +-
.../modules/mailbox/FastRetryBackoffModule.java | 2 +-
.../modules/mailbox/MemoryDeadLetterModule.java | 2 +-
.../mailbox/MailboxListenersLoaderImplTest.java | 9 +-
.../apache/james/jmap/api/change/EmailChange.java | 6 +-
.../james/jmap/api/change/MailboxChange.java | 14 +-
.../methods/integration/SetMessagesMethodTest.java | 4 +-
.../ComputeMessageFastViewProjectionListener.java | 2 +-
.../jmap/event/PopulateEmailQueryViewListener.java | 6 +-
.../jmap/event/PropagateLookupRightListener.java | 4 +-
...mputeMessageFastViewProjectionListenerTest.java | 8 +-
.../event/PopulateEmailQueryViewListenerTest.java | 8 +-
.../james/jmap/change/MailboxChangeListener.scala | 7 +-
.../jmap/change/MailboxChangeListenerTest.scala | 7 +-
.../rabbitmq/ConsistencyTasksIntegrationTest.java | 2 +-
.../RabbitMQEventDeadLettersIntegrationTest.java | 4 +-
...RabbitMQReindexingWithEventDeadLettersTest.java | 2 +-
...dminServerTaskSerializationIntegrationTest.java | 2 +-
server/protocols/webadmin/webadmin-mailbox/pom.xml | 2 +-
.../routes/EventDeadLettersRoutesTest.java | 12 +-
154 files changed, 346 insertions(+), 9044 deletions(-)
diff --git a/event-bus/in-vm/pom.xml b/event-bus/in-vm/pom.xml
index 99fc5c2..a0a178c 100644
--- a/event-bus/in-vm/pom.xml
+++ b/event-bus/in-vm/pom.xml
@@ -31,4 +31,48 @@
<name>Apache James :: Event Bus :: In VM</name>
<description>In VM (non distributed) implementation for the eventBus</description>
+ <dependencies>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>metrics-tests</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>testing-base</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>apache-james-mailbox-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>apache-james-mailbox-api</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>james-server-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>metrics-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.projectreactor</groupId>
+ <artifactId>reactor-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.awaitility</groupId>
+ <artifactId>awaitility</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
</project>
\ No newline at end of file
diff --git a/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessages.java b/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessages.java
index d541029..6c942ce 100644
--- a/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessages.java
+++ b/examples/custom-listeners/src/main/java/org/apache/james/examples/custom/listeners/SetCustomFlagOnBigMessages.java
@@ -22,15 +22,15 @@ package org.apache.james.examples.custom.listeners;
import javax.inject.Inject;
import javax.mail.Flags;
+import org.apache.james.events.Event;
import org.apache.james.events.EventListener;
+import org.apache.james.events.Group;
+import org.apache.james.events.MailboxEvents.Added;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageManager;
import org.apache.james.mailbox.MessageManager.FlagsUpdateMode;
import org.apache.james.mailbox.MessageUid;
-import org.apache.james.events.Event;
-import org.apache.james.events.Group;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.MessageRange;
import org.slf4j.Logger;
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
deleted file mode 100644
index d544e35..0000000
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxEvents.java
+++ /dev/null
@@ -1,582 +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.mailbox.events;
-
-import java.time.Instant;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.SortedMap;
-
-import org.apache.james.core.Username;
-import org.apache.james.core.quota.QuotaCountLimit;
-import org.apache.james.core.quota.QuotaCountUsage;
-import org.apache.james.core.quota.QuotaSizeLimit;
-import org.apache.james.core.quota.QuotaSizeUsage;
-import org.apache.james.events.Event;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.MessageUid;
-import org.apache.james.mailbox.acl.ACLDiff;
-import org.apache.james.mailbox.model.MailboxACL;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.MessageId;
-import org.apache.james.mailbox.model.MessageMetaData;
-import org.apache.james.mailbox.model.Quota;
-import org.apache.james.mailbox.model.QuotaRoot;
-import org.apache.james.mailbox.model.UpdatedFlags;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-public interface MailboxEvents {
-
- interface QuotaEvent extends Event {
- QuotaRoot getQuotaRoot();
- }
-
- class QuotaUsageUpdatedEvent implements QuotaEvent {
- private final EventId eventId;
- private final Username username;
- private final QuotaRoot quotaRoot;
- private final Quota<QuotaCountLimit, QuotaCountUsage> countQuota;
- private final Quota<QuotaSizeLimit, QuotaSizeUsage> sizeQuota;
- private final Instant instant;
-
- public QuotaUsageUpdatedEvent(EventId eventId, Username username, QuotaRoot quotaRoot, Quota<QuotaCountLimit, QuotaCountUsage> countQuota, Quota<QuotaSizeLimit, QuotaSizeUsage> sizeQuota, Instant instant) {
- this.eventId = eventId;
- this.username = username;
- this.quotaRoot = quotaRoot;
- this.countQuota = countQuota;
- this.sizeQuota = sizeQuota;
- this.instant = instant;
- }
-
- @Override
- public boolean isNoop() {
- return false;
- }
-
- @Override
- public Username getUsername() {
- return username;
- }
-
- public Quota<QuotaCountLimit, QuotaCountUsage> getCountQuota() {
- return countQuota;
- }
-
- public Quota<QuotaSizeLimit, QuotaSizeUsage> getSizeQuota() {
- return sizeQuota;
- }
-
- @Override
- public QuotaRoot getQuotaRoot() {
- return quotaRoot;
- }
-
- public Instant getInstant() {
- return instant;
- }
-
- @Override
- public EventId getEventId() {
- return eventId;
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof QuotaUsageUpdatedEvent) {
- QuotaUsageUpdatedEvent that = (QuotaUsageUpdatedEvent) o;
-
- return Objects.equals(this.eventId, that.eventId)
- && Objects.equals(this.username, that.username)
- && Objects.equals(this.quotaRoot, that.quotaRoot)
- && Objects.equals(this.countQuota, that.countQuota)
- && Objects.equals(this.sizeQuota, that.sizeQuota)
- && Objects.equals(this.instant, that.instant);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(eventId, username, quotaRoot, countQuota, sizeQuota, instant);
- }
-
- }
-
- /**
- * A mailbox event.
- */
- abstract class MailboxEvent implements Event {
- protected final MailboxPath path;
- protected final MailboxId mailboxId;
- protected final Username username;
- protected final MailboxSession.SessionId sessionId;
- protected final EventId eventId;
-
- public MailboxEvent(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, EventId eventId) {
- this.username = username;
- this.path = path;
- this.mailboxId = mailboxId;
- this.sessionId = sessionId;
- this.eventId = eventId;
- }
-
- /**
- * Gets the {@link Username} in which's context the {@link MailboxEvent}
- * happened
- *
- * @return user
- */
- @Override
- public Username getUsername() {
- return username;
- }
-
- @Override
- public EventId getEventId() {
- return eventId;
- }
-
- /**
- * Gets the sessionId in which's context the {@link MailboxEvent}
- * happened
- *
- * @return sessionId
- */
- public MailboxSession.SessionId getSessionId() {
- return sessionId;
- }
-
- /**
- * Return the path of the Mailbox this event belongs to.
- *
- * @return path
- */
- public MailboxPath getMailboxPath() {
- return path;
- }
-
- /**
- * Return the id of the Mailbox this event belongs to.
- *
- * @return mailboxId
- */
- public MailboxId getMailboxId() {
- return mailboxId;
- }
- }
-
- /**
- * Indicates that mailbox has been deleted.
- */
- class MailboxDeletion extends MailboxEvent {
- private final MailboxACL mailboxACL;
- private final QuotaRoot quotaRoot;
- private final QuotaCountUsage deletedMessageCount;
- private final QuotaSizeUsage totalDeletedSize;
-
- public MailboxDeletion(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxACL mailboxACL, QuotaRoot quotaRoot, QuotaCountUsage deletedMessageCount, QuotaSizeUsage totalDeletedSize,
- MailboxId mailboxId, EventId eventId) {
- super(sessionId, username, path, mailboxId, eventId);
- this.mailboxACL = mailboxACL;
- this.quotaRoot = quotaRoot;
- this.deletedMessageCount = deletedMessageCount;
- this.totalDeletedSize = totalDeletedSize;
- }
-
- @Override
- public boolean isNoop() {
- return false;
- }
-
- public MailboxACL getMailboxACL() {
- return mailboxACL;
- }
-
- public QuotaRoot getQuotaRoot() {
- return quotaRoot;
- }
-
- public QuotaCountUsage getDeletedMessageCount() {
- return deletedMessageCount;
- }
-
- public QuotaSizeUsage getTotalDeletedSize() {
- return totalDeletedSize;
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof MailboxDeletion) {
- MailboxDeletion that = (MailboxDeletion) o;
-
- return Objects.equals(this.eventId, that.eventId)
- && Objects.equals(this.sessionId, that.sessionId)
- && Objects.equals(this.username, that.username)
- && Objects.equals(this.path, that.path)
- && Objects.equals(this.mailboxACL, that.mailboxACL)
- && Objects.equals(this.mailboxId, that.mailboxId)
- && Objects.equals(this.quotaRoot, that.quotaRoot)
- && Objects.equals(this.deletedMessageCount, that.deletedMessageCount)
- && Objects.equals(this.totalDeletedSize, that.totalDeletedSize);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(eventId, sessionId, username, path, mailboxACL, mailboxId, quotaRoot, deletedMessageCount, totalDeletedSize);
- }
- }
-
- /**
- * Indicates that a mailbox has been Added.
- */
- class MailboxAdded extends MailboxEvent {
-
- public MailboxAdded(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, EventId eventId) {
- super(sessionId, username, path, mailboxId, eventId);
- }
-
- @Override
- public boolean isNoop() {
- return false;
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof MailboxAdded) {
- MailboxAdded that = (MailboxAdded) o;
-
- return Objects.equals(this.eventId, that.eventId)
- && Objects.equals(this.sessionId, that.sessionId)
- && Objects.equals(this.username, that.username)
- && Objects.equals(this.path, that.path)
- && Objects.equals(this.mailboxId, that.mailboxId);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(eventId, sessionId, username, path, mailboxId);
- }
- }
-
- /**
- * Indicates that a mailbox has been renamed.
- */
- class MailboxRenamed extends MailboxEvent {
- private final MailboxPath newPath;
-
- public MailboxRenamed(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, MailboxPath newPath, EventId eventId) {
- super(sessionId, username, path, mailboxId, eventId);
- this.newPath = newPath;
- }
-
- @Override
- public boolean isNoop() {
- return newPath.equals(path);
- }
-
- /**
- * Gets the new name for this mailbox.
- *
- * @return name, not null
- */
- public MailboxPath getNewPath() {
- return newPath;
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof MailboxRenamed) {
- MailboxRenamed that = (MailboxRenamed) o;
-
- return Objects.equals(this.eventId, that.eventId)
- && Objects.equals(this.sessionId, that.sessionId)
- && Objects.equals(this.username, that.username)
- && Objects.equals(this.path, that.path)
- && Objects.equals(this.mailboxId, that.mailboxId)
- && Objects.equals(this.newPath, that.newPath);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(eventId, sessionId, username, path, mailboxId, newPath);
- }
- }
-
-
- /**
- * A mailbox event related to updated ACL
- */
- class MailboxACLUpdated extends MailboxEvent {
- private final ACLDiff aclDiff;
-
- public MailboxACLUpdated(MailboxSession.SessionId sessionId, Username username, MailboxPath path, ACLDiff aclDiff, MailboxId mailboxId, EventId eventId) {
- super(sessionId, username, path, mailboxId, eventId);
- this.aclDiff = aclDiff;
- }
-
- public ACLDiff getAclDiff() {
- return aclDiff;
- }
-
- @Override
- public boolean isNoop() {
- return aclDiff.getNewACL().equals(aclDiff.getOldACL());
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof MailboxACLUpdated) {
- MailboxACLUpdated that = (MailboxACLUpdated) o;
-
- return Objects.equals(this.eventId, that.eventId)
- && Objects.equals(this.sessionId, that.sessionId)
- && Objects.equals(this.username, that.username)
- && Objects.equals(this.path, that.path)
- && Objects.equals(this.aclDiff, that.aclDiff)
- && Objects.equals(this.mailboxId, that.mailboxId);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(eventId, sessionId, username, path, aclDiff, mailboxId);
- }
-
- }
-
- /**
- * A mailbox event related to a message.
- */
- abstract class MessageEvent extends MailboxEvent {
-
- public MessageEvent(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, EventId eventId) {
- super(sessionId, username, path, mailboxId, eventId);
- }
-
- /**
- * Gets the message UIDs for the subject of this event.
- *
- * @return message uids
- */
- public abstract Collection<MessageUid> getUids();
- }
-
- abstract class MetaDataHoldingEvent extends MessageEvent {
-
- public MetaDataHoldingEvent(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, EventId eventId) {
- super(sessionId, username, path, mailboxId, eventId);
- }
-
- /**
- * Return the flags which were set for the affected message
- *
- * @return flags
- */
- public abstract MessageMetaData getMetaData(MessageUid uid);
-
- public ImmutableSet<MessageId> getMessageIds() {
- return getUids()
- .stream()
- .map(uid -> getMetaData(uid).getMessageId())
- .collect(Guavate.toImmutableSet());
- }
- }
-
- class Expunged extends MetaDataHoldingEvent {
- private final Map<MessageUid, MessageMetaData> expunged;
-
- public Expunged(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId, Map<MessageUid, MessageMetaData> uids, EventId eventId) {
- super(sessionId, username, path, mailboxId, eventId);
- this.expunged = ImmutableMap.copyOf(uids);
- }
-
- @Override
- public Collection<MessageUid> getUids() {
- return expunged.keySet();
- }
-
- /**
- * Return the flags which were set for the added message
- *
- * @return flags
- */
- @Override
- public MessageMetaData getMetaData(MessageUid uid) {
- return expunged.get(uid);
- }
-
- public Map<MessageUid, MessageMetaData> getExpunged() {
- return expunged;
- }
-
- @Override
- public boolean isNoop() {
- return expunged.isEmpty();
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof Expunged) {
- Expunged that = (Expunged) o;
-
- return Objects.equals(this.eventId, that.eventId)
- && Objects.equals(this.sessionId, that.sessionId)
- && Objects.equals(this.username, that.username)
- && Objects.equals(this.path, that.path)
- && Objects.equals(this.mailboxId, that.mailboxId)
- && Objects.equals(this.expunged, that.expunged);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(eventId, sessionId, username, path, mailboxId, expunged);
- }
- }
-
- /**
- * A mailbox event related to updated flags
- */
- class FlagsUpdated extends MessageEvent {
- private final List<UpdatedFlags> updatedFlags;
-
- public FlagsUpdated(MailboxSession.SessionId sessionId, Username username, MailboxPath path,
- MailboxId mailboxId, List<UpdatedFlags> updatedFlags, EventId eventId) {
- super(sessionId, username, path, mailboxId, eventId);
- this.updatedFlags = ImmutableList.copyOf(updatedFlags);
- }
-
- @Override
- public Collection<MessageUid> getUids() {
- return updatedFlags.stream()
- .map(UpdatedFlags::getUid)
- .collect(Guavate.toImmutableList());
- }
-
- public Collection<MessageId> getMessageIds() {
- return updatedFlags.stream()
- .map(UpdatedFlags::getMessageId)
- .flatMap(Optional::stream)
- .collect(Guavate.toImmutableList());
- }
-
- public List<UpdatedFlags> getUpdatedFlags() {
- return updatedFlags;
- }
-
- @Override
- public boolean isNoop() {
- return updatedFlags.isEmpty();
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof FlagsUpdated) {
- FlagsUpdated that = (FlagsUpdated) o;
-
- return Objects.equals(this.eventId, that.eventId)
- && Objects.equals(this.sessionId, that.sessionId)
- && Objects.equals(this.username, that.username)
- && Objects.equals(this.path, that.path)
- && Objects.equals(this.mailboxId, that.mailboxId)
- && Objects.equals(this.updatedFlags, that.updatedFlags);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(eventId, sessionId, username, path, mailboxId, updatedFlags);
- }
- }
-
- /**
- * A mailbox event related to added message
- */
- class Added extends MetaDataHoldingEvent {
- private final Map<MessageUid, MessageMetaData> added;
-
- public Added(MailboxSession.SessionId sessionId, Username username, MailboxPath path, MailboxId mailboxId,
- SortedMap<MessageUid, MessageMetaData> uids, EventId eventId) {
- super(sessionId, username, path, mailboxId, eventId);
- this.added = ImmutableMap.copyOf(uids);
- }
-
- /**
- * Return the flags which were set for the added message
- *
- * @return flags
- */
- public MessageMetaData getMetaData(MessageUid uid) {
- return added.get(uid);
- }
-
- @Override
- public Collection<MessageUid> getUids() {
- return added.keySet();
- }
-
- public Map<MessageUid, MessageMetaData> getAdded() {
- return added;
- }
-
- @Override
- public boolean isNoop() {
- return added.isEmpty();
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof Added) {
- Added that = (Added) o;
-
- return Objects.equals(this.eventId, that.eventId)
- && Objects.equals(this.sessionId, that.sessionId)
- && Objects.equals(this.username, that.username)
- && Objects.equals(this.path, that.path)
- && Objects.equals(this.mailboxId, that.mailboxId)
- && Objects.equals(this.added, that.added);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(eventId, sessionId, username, path, mailboxId, added);
- }
- }
-
-}
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxIdRegistrationKey.java b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxIdRegistrationKey.java
deleted file mode 100644
index cbbd20b..0000000
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MailboxIdRegistrationKey.java
+++ /dev/null
@@ -1,78 +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.mailbox.events;
-
-import java.util.Objects;
-
-import javax.inject.Inject;
-
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.mailbox.model.MailboxId;
-
-public class MailboxIdRegistrationKey implements RegistrationKey {
- public static class Factory implements RegistrationKey.Factory {
- private final MailboxId.Factory mailboxIdFactory;
-
- @Inject
- public Factory(MailboxId.Factory mailboxIdFactory) {
- this.mailboxIdFactory = mailboxIdFactory;
- }
-
- @Override
- public Class<? extends RegistrationKey> forClass() {
- return MailboxIdRegistrationKey.class;
- }
-
- @Override
- public RegistrationKey fromString(String asString) {
- return new MailboxIdRegistrationKey(mailboxIdFactory.fromString(asString));
- }
- }
-
- private final MailboxId mailboxId;
-
- public MailboxIdRegistrationKey(MailboxId mailboxId) {
- this.mailboxId = mailboxId;
- }
-
- public MailboxId getMailboxId() {
- return mailboxId;
- }
-
- @Override
- public String asString() {
- return mailboxId.serialize();
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof MailboxIdRegistrationKey) {
- MailboxIdRegistrationKey that = (MailboxIdRegistrationKey) o;
-
- return Objects.equals(this.mailboxId, that.mailboxId);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(mailboxId);
- }
-}
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MessageMoveEvent.java b/mailbox/api/src/main/java/org/apache/james/mailbox/events/MessageMoveEvent.java
deleted file mode 100644
index 69173d2..0000000
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/MessageMoveEvent.java
+++ /dev/null
@@ -1,154 +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.mailbox.events;
-
-import java.util.Collection;
-import java.util.Objects;
-import java.util.Optional;
-
-import org.apache.james.core.Username;
-import org.apache.james.events.Event;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MessageId;
-import org.apache.james.mailbox.model.MessageMoves;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-
-public class MessageMoveEvent implements Event {
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private ImmutableList.Builder<MessageId> messageIds;
- private Username username;
- private MessageMoves messageMoves;
- private Optional<EventId> eventId;
-
- private Builder() {
- messageIds = ImmutableList.builder();
- eventId = Optional.empty();
- }
-
- public Builder session(MailboxSession session) {
- this.username = session.getUser();
- return this;
- }
-
- public Builder user(Username username) {
- this.username = username;
- return this;
- }
-
- public Builder messageMoves(MessageMoves messageMoves) {
- this.messageMoves = messageMoves;
- return this;
- }
-
- public Builder messageId(MessageId messageId) {
- this.messageIds.add(messageId);
- return this;
- }
-
- public Builder eventId(EventId eventId) {
- this.eventId = Optional.of(eventId);
- return this;
- }
-
- public Builder messageId(Iterable<MessageId> messageIds) {
- this.messageIds.addAll(messageIds);
- return this;
- }
-
- public MessageMoveEvent build() {
- Preconditions.checkNotNull(username, "'user' is mandatory");
- Preconditions.checkNotNull(messageMoves, "'messageMoves' is mandatory");
-
- return new MessageMoveEvent(eventId.orElse(EventId.random()), username, messageMoves, messageIds.build());
- }
- }
-
- private final EventId eventId;
- private final Username username;
- private final MessageMoves messageMoves;
- private final Collection<MessageId> messageIds;
-
- @VisibleForTesting
- MessageMoveEvent(EventId eventId, Username username, MessageMoves messageMoves, Collection<MessageId> messageIds) {
- this.eventId = eventId;
- this.username = username;
- this.messageMoves = messageMoves;
- this.messageIds = messageIds;
- }
-
- @Override
- public boolean isNoop() {
- return messageIds.isEmpty();
- }
-
- public Collection<MessageId> getMessageIds() {
- return messageIds;
- }
-
- @Override
- public EventId getEventId() {
- return eventId;
- }
-
- @Override
- public Username getUsername() {
- return username;
- }
-
- public MessageMoves getMessageMoves() {
- return messageMoves;
- }
-
- public boolean isMoveTo(MailboxId mailboxId) {
- return messageMoves.addedMailboxIds()
- .contains(mailboxId);
- }
-
- public boolean isMoveFrom(MailboxId mailboxId) {
- return messageMoves.removedMailboxIds()
- .contains(mailboxId);
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof MessageMoveEvent) {
- MessageMoveEvent that = (MessageMoveEvent) o;
-
- return Objects.equals(this.eventId, that.eventId)
- && Objects.equals(this.username, that.username)
- && Objects.equals(this.messageMoves, that.messageMoves)
- && Objects.equals(this.messageIds, that.messageIds);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(eventId, username, messageMoves, messageIds);
- }
-}
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/events/RetryBackoffConfiguration.java b/mailbox/api/src/main/java/org/apache/james/mailbox/events/RetryBackoffConfiguration.java
deleted file mode 100644
index f90a4d4..0000000
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/events/RetryBackoffConfiguration.java
+++ /dev/null
@@ -1,125 +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.mailbox.events;
-
-import java.time.Duration;
-import java.util.Objects;
-
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
-
-public class RetryBackoffConfiguration {
-
- @FunctionalInterface
- public interface RequireMaxRetries {
- RequireFirstBackoff maxRetries(int maxRetries);
- }
-
- @FunctionalInterface
- public interface RequireFirstBackoff {
- RequireJitterFactor firstBackoff(Duration firstBackoff);
- }
-
- @FunctionalInterface
- public interface RequireJitterFactor {
- ReadyToBuild jitterFactor(double jitterFactor);
- }
-
- public static class ReadyToBuild {
- private final int maxRetries;
- private final Duration firstBackoff;
- private final double jitterFactor;
-
- private ReadyToBuild(int maxRetries, Duration firstBackoff, double jitterFactor) {
- this.maxRetries = maxRetries;
- this.firstBackoff = firstBackoff;
- this.jitterFactor = jitterFactor;
- }
-
- public RetryBackoffConfiguration build() {
- return new RetryBackoffConfiguration(maxRetries, firstBackoff, jitterFactor);
- }
- }
-
- public static RequireMaxRetries builder() {
- return maxRetries -> firstBackoff -> jitterFactor -> new ReadyToBuild(maxRetries, firstBackoff, jitterFactor);
- }
-
- static final double DEFAULT_JITTER_FACTOR = 0.5;
- static final int DEFAULT_MAX_RETRIES = 8;
- static final Duration DEFAULT_FIRST_BACKOFF = Duration.ofMillis(100);
- public static final RetryBackoffConfiguration DEFAULT = new RetryBackoffConfiguration(
- DEFAULT_MAX_RETRIES,
- DEFAULT_FIRST_BACKOFF,
- DEFAULT_JITTER_FACTOR);
-
- private final int maxRetries;
- private final Duration firstBackoff;
- private final double jitterFactor;
-
- private RetryBackoffConfiguration(int maxRetries, Duration firstBackoff, double jitterFactor) {
- Preconditions.checkArgument(!firstBackoff.isNegative(), "firstBackoff is not allowed to be negative");
- Preconditions.checkArgument(maxRetries >= 0, "maxRetries is not allowed to be negative");
- Preconditions.checkArgument(jitterFactor >= 0 && jitterFactor <= 1.0, "jitterFactor is not " +
- "allowed to be negative or greater than 1");
-
- this.maxRetries = maxRetries;
- this.firstBackoff = firstBackoff;
- this.jitterFactor = jitterFactor;
- }
-
- public int getMaxRetries() {
- return maxRetries;
- }
-
- public Duration getFirstBackoff() {
- return firstBackoff;
- }
-
- public double getJitterFactor() {
- return jitterFactor;
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof RetryBackoffConfiguration) {
- RetryBackoffConfiguration that = (RetryBackoffConfiguration) o;
-
- return Objects.equals(this.maxRetries, that.maxRetries)
- && Objects.equals(this.jitterFactor, that.jitterFactor)
- && Objects.equals(this.firstBackoff, that.firstBackoff);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(maxRetries, firstBackoff, jitterFactor);
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("maxRetries", maxRetries)
- .add("firstBackoff", firstBackoff)
- .add("jitterFactor", jitterFactor)
- .toString();
- }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/EventTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/EventTest.java
index c25f7df..1d36cd7 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/EventTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/EventTest.java
@@ -28,7 +28,7 @@ import javax.mail.Flags;
import org.apache.james.core.Username;
import org.apache.james.events.Event;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
+import org.apache.james.events.MailboxEvents.Added;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.MessageMetaData;
import org.apache.james.mailbox.model.TestId;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxListenerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxListenerTest.java
index 13fa417..5ff940d 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxListenerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxListenerTest.java
@@ -34,15 +34,15 @@ import org.apache.james.core.quota.QuotaCountUsage;
import org.apache.james.core.quota.QuotaSizeLimit;
import org.apache.james.core.quota.QuotaSizeUsage;
import org.apache.james.events.Event;
+import org.apache.james.events.MailboxEvents.Added;
+import org.apache.james.events.MailboxEvents.Expunged;
+import org.apache.james.events.MailboxEvents.FlagsUpdated;
+import org.apache.james.events.MailboxEvents.MailboxACLUpdated;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
+import org.apache.james.events.MailboxEvents.MailboxDeletion;
+import org.apache.james.events.MailboxEvents.MailboxRenamed;
+import org.apache.james.events.MailboxEvents.QuotaUsageUpdatedEvent;
import org.apache.james.mailbox.acl.ACLDiff;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
-import org.apache.james.mailbox.events.MailboxEvents.Expunged;
-import org.apache.james.mailbox.events.MailboxEvents.FlagsUpdated;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxACLUpdated;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxRenamed;
-import org.apache.james.mailbox.events.MailboxEvents.QuotaUsageUpdatedEvent;
import org.apache.james.mailbox.model.MailboxACL;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.MessageMetaData;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressContract.java
index d8667e2..bd95fd3 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressContract.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerStressContract.java
@@ -33,8 +33,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.james.core.Username;
import org.apache.james.events.EventBus;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
-import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
+import org.apache.james.events.MailboxEvents.Added;
+import org.apache.james.events.MailboxIdRegistrationKey;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.ComposedMessageId;
import org.apache.james.mailbox.model.MailboxId;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index 7a23c69..03c5a46 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -47,17 +47,17 @@ import org.apache.james.core.quota.QuotaCountUsage;
import org.apache.james.core.quota.QuotaSizeLimit;
import org.apache.james.core.quota.QuotaSizeUsage;
import org.apache.james.events.EventBus;
+import org.apache.james.events.MailboxEvents.Added;
+import org.apache.james.events.MailboxEvents.Expunged;
+import org.apache.james.events.MailboxEvents.FlagsUpdated;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
+import org.apache.james.events.MailboxEvents.MailboxDeletion;
+import org.apache.james.events.MailboxEvents.QuotaUsageUpdatedEvent;
+import org.apache.james.events.MailboxIdRegistrationKey;
+import org.apache.james.events.MessageMoveEvent;
import org.apache.james.mailbox.MailboxManager.MailboxCapabilities;
import org.apache.james.mailbox.MailboxManager.MailboxRenamedResult;
import org.apache.james.mailbox.MessageManager.AppendCommand;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
-import org.apache.james.mailbox.events.MailboxEvents.Expunged;
-import org.apache.james.mailbox.events.MailboxEvents.FlagsUpdated;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
-import org.apache.james.mailbox.events.MailboxEvents.QuotaUsageUpdatedEvent;
-import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
-import org.apache.james.mailbox.events.MessageMoveEvent;
import org.apache.james.mailbox.exception.AnnotationException;
import org.apache.james.mailbox.exception.HasEmptyMailboxNameInHierarchyException;
import org.apache.james.mailbox.exception.InboxAlreadyCreated;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MessageMoveEventTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MessageMoveEventTest.java
index 0069e62..73859f4 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MessageMoveEventTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MessageMoveEventTest.java
@@ -22,7 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.apache.james.core.Username;
-import org.apache.james.mailbox.events.MessageMoveEvent;
+import org.apache.james.events.MessageMoveEvent;
import org.apache.james.mailbox.model.MessageMoves;
import org.apache.james.mailbox.model.TestId;
import org.apache.james.mailbox.model.TestMessageId;
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/ErrorHandlingContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/ErrorHandlingContract.java
deleted file mode 100644
index 226f1bb..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/ErrorHandlingContract.java
+++ /dev/null
@@ -1,367 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.DEFAULT_FIRST_BACKOFF;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_ID;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_A;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_1;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.spy;
-
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.mailbox.util.EventCollector;
-import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Mono;
-
-interface ErrorHandlingContract extends EventBusContract {
-
- class ThrowingListener implements EventListener {
- private final List<Instant> timeElapsed;
-
- private ThrowingListener() {
- timeElapsed = new ArrayList<>();
- }
-
- @Override
- public boolean isHandling(Event event) {
- return true;
- }
-
- @Override
- public void event(Event event) {
- timeElapsed.add(Instant.now());
- throw new RuntimeException("throw to trigger reactor retry");
- }
-
- public int executionCount() {
- return timeElapsed.size();
- }
- }
-
- EventDeadLetters deadLetter();
-
- default EventCollector eventCollector() {
- return spy(new EventCollector());
- }
-
- default ThrowingListener throwingListener() {
- return new ThrowingListener();
- }
-
- @Test
- default void retryingIsNotAppliedForKeyRegistrations() {
- EventCollector eventCollector = eventCollector();
-
- doThrow(new RuntimeException())
- .when(eventCollector).event(EVENT);
-
- Mono.from(eventBus().register(eventCollector, KEY_1)).block();
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- assertThat(eventCollector.getEvents())
- .isEmpty();
- }
-
- @Test
- default void listenerShouldReceiveWhenFailsLessThanMaxRetries() {
- EventCollector eventCollector = eventCollector();
-
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(eventCollector).event(EVENT);
-
- eventBus().register(eventCollector, GROUP_A);
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(eventCollector.getEvents()).hasSize(1));
- }
-
- @Test
- default void listenerShouldReceiveWhenFailsEqualsMaxRetries() {
- EventCollector eventCollector = eventCollector();
- //do throw RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(eventCollector).event(EVENT);
-
- eventBus().register(eventCollector, GROUP_A);
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- getSpeedProfile().longWaitCondition()
- .untilAsserted(() -> assertThat(eventCollector.getEvents()).hasSize(1));
- }
-
- @Test
- default void listenerShouldNotReceiveWhenFailsGreaterThanMaxRetries() throws Exception {
- EventCollector eventCollector = eventCollector();
-
- //do throw RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(eventCollector).event(EVENT);
-
- eventBus().register(eventCollector, GROUP_A);
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- TimeUnit.SECONDS.sleep(1);
- assertThat(eventCollector.getEvents())
- .isEmpty();
- }
-
- @Test
- default void exceedingMaxRetriesShouldStopConsumingFailedEvent() throws Exception {
- ThrowingListener throwingListener = throwingListener();
-
- eventBus().register(throwingListener, GROUP_A);
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(throwingListener.executionCount()).isEqualTo(4));
- Thread.sleep(getSpeedProfile().getShortWaitTime().toMillis());
-
- assertThat(throwingListener.executionCount())
- .isEqualTo(4);
- }
-
- @Test
- default void retriesBackOffShouldDelayByExponentialGrowth() {
- ThrowingListener throwingListener = throwingListener();
-
- eventBus().register(throwingListener, GROUP_A);
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(throwingListener.executionCount()).isEqualTo(4));
- SoftAssertions.assertSoftly(softly -> {
- List<Instant> timeElapsed = throwingListener.timeElapsed;
- softly.assertThat(timeElapsed).hasSize(RETRY_BACKOFF_CONFIGURATION.getMaxRetries() + 1);
-
- long minFirstDelayAfter = DEFAULT_FIRST_BACKOFF.toMillis(); // first backOff
- long minSecondDelayAfter = DEFAULT_FIRST_BACKOFF.toMillis() / 2; // first_backOff * jitter factor (first_backOff * 0.5)
- long minThirdDelayAfter = DEFAULT_FIRST_BACKOFF.toMillis(); // first_backOff * jitter factor (first_backOff * 1)
-
- softly.assertThat(timeElapsed.get(1))
- .isAfterOrEqualTo(timeElapsed.get(0).plusMillis(minFirstDelayAfter));
-
- softly.assertThat(timeElapsed.get(2))
- .isAfterOrEqualTo(timeElapsed.get(1).plusMillis(minSecondDelayAfter));
-
- softly.assertThat(timeElapsed.get(3))
- .isAfterOrEqualTo(timeElapsed.get(2).plusMillis(minThirdDelayAfter));
- });
- }
-
- @Test
- default void retryingListenerCallingDispatchShouldNotFail() {
- AtomicBoolean firstExecution = new AtomicBoolean(true);
- AtomicBoolean successfulRetry = new AtomicBoolean(false);
- EventListener listener = event -> {
- if (event.getEventId().equals(EVENT_ID)) {
- if (firstExecution.get()) {
- firstExecution.set(false);
- throw new RuntimeException();
- }
- eventBus().dispatch(EVENT_2, NO_KEYS).block();
- successfulRetry.set(true);
- }
- };
-
- eventBus().register(listener, GROUP_A);
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- getSpeedProfile().shortWaitCondition().until(successfulRetry::get);
- }
-
- @Test
- default void deadLettersIsNotAppliedForKeyRegistrations() throws Exception {
- EventCollector eventCollector = eventCollector();
-
- //do throw RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(eventCollector).event(EVENT);
-
- Mono.from(eventBus().register(eventCollector, KEY_1)).block();
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- TimeUnit.SECONDS.sleep(1);
- SoftAssertions.assertSoftly(softly -> {
- softly.assertThat(eventCollector.getEvents()).isEmpty();
- softly.assertThat(deadLetter().groupsWithFailedEvents().toIterable())
- .isEmpty();
- });
- }
-
- @Test
- default void deadLetterShouldNotStoreWhenFailsLessThanMaxRetries() {
- EventCollector eventCollector = eventCollector();
-
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(eventCollector).event(EVENT);
-
- eventBus().register(eventCollector, new EventBusTestFixture.GroupA());
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(eventCollector.getEvents()).hasSize(1));
-
- assertThat(deadLetter().groupsWithFailedEvents().toIterable())
- .isEmpty();
- }
-
- @Test
- default void deadLetterShouldStoreWhenDispatchFailsGreaterThanMaxRetries() {
- EventCollector eventCollector = eventCollector();
- //do throw RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(eventCollector).event(EVENT);
-
- eventBus().register(eventCollector, GROUP_A);
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- getSpeedProfile().longWaitCondition()
- .untilAsserted(() -> assertThat(deadLetter().failedIds(GROUP_A)
- .flatMap(insertionId -> deadLetter().failedEvent(GROUP_A, insertionId))
- .toIterable())
- .containsOnly(EVENT));
- assertThat(eventCollector.getEvents())
- .isEmpty();
- }
-
- @Test
- default void deadLetterShouldStoreWhenRedeliverFailsGreaterThanMaxRetries() {
- EventCollector eventCollector = eventCollector();
-
- //do throw RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(eventCollector).event(EVENT);
-
- eventBus().register(eventCollector, GROUP_A);
- eventBus().reDeliver(GROUP_A, EVENT).block();
-
- getSpeedProfile().longWaitCondition()
- .untilAsserted(() ->
- assertThat(
- deadLetter()
- .failedIds(GROUP_A)
- .flatMap(insertionId -> deadLetter().failedEvent(GROUP_A, insertionId))
- .toIterable())
- .containsOnly(EVENT));
- assertThat(eventCollector.getEvents()).isEmpty();
- }
-
- @Disabled("JAMES-2907 redeliver should work as initial dispatch")
- @Test
- default void retryShouldDeliverAsManyTimesAsInitialDeliveryAttempt() {
- EventCollector eventCollector = eventCollector();
-
- //do throw RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(eventCollector).event(EVENT);
-
- eventBus().register(eventCollector, GROUP_A);
- eventBus().reDeliver(GROUP_A, EVENT).block();
-
- getSpeedProfile().longWaitCondition()
- .untilAsserted(() -> assertThat(eventCollector.getEvents()).isNotEmpty());
- }
-
- @Test
- default void redeliverShouldNotSendEventsToKeyListeners() {
- EventCollector eventCollector = eventCollector();
- EventCollector eventCollector2 = eventCollector();
-
- eventBus().register(eventCollector, GROUP_A);
- Mono.from(eventBus().register(eventCollector2, KEY_1)).block();
- eventBus().reDeliver(GROUP_A, EVENT).block();
-
- getSpeedProfile().longWaitCondition()
- .untilAsserted(() -> assertThat(eventCollector.getEvents()).hasSize(1));
- assertThat(eventCollector2.getEvents()).isEmpty();
- }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusConcurrentTestContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusConcurrentTestContract.java
deleted file mode 100644
index 8b73023..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusConcurrentTestContract.java
+++ /dev/null
@@ -1,240 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_1;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_3;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.GROUP_A;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.awaitility.Awaitility.await;
-
-import java.time.Duration;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.james.events.EventBus;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.util.concurrency.ConcurrentTestRunner;
-import org.awaitility.core.ConditionFactory;
-import org.junit.jupiter.api.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Mono;
-
-public interface EventBusConcurrentTestContract {
-
- Duration FIVE_SECONDS = Duration.ofSeconds(5);
- ConditionFactory AWAIT_CONDITION = await().timeout(new org.awaitility.Duration(5, TimeUnit.SECONDS));
-
- int THREAD_COUNT = 10;
- int OPERATION_COUNT = 30;
- int TOTAL_DISPATCH_OPERATIONS = THREAD_COUNT * OPERATION_COUNT;
-
- Set<RegistrationKey> ALL_KEYS = ImmutableSet.of(KEY_1, KEY_2, KEY_3);
-
- static EventBusTestFixture.EventListenerCountingSuccessfulExecution newCountingListener() {
- return new EventBusTestFixture.EventListenerCountingSuccessfulExecution();
- }
-
- static int totalEventsReceived(ImmutableList<EventBusTestFixture.EventListenerCountingSuccessfulExecution> allListeners) {
- return allListeners.stream()
- .mapToInt(EventBusTestFixture.EventListenerCountingSuccessfulExecution::numberOfEventCalls)
- .sum();
- }
-
- interface SingleEventBusConcurrentContract extends EventBusContract {
-
- @Test
- default void concurrentDispatchGroupShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-
- eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
- eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
- eventBus().register(countingListener3, new EventBusTestFixture.GroupC());
- int totalGlobalRegistrations = 3; // GroupA + GroupB + GroupC
-
- ConcurrentTestRunner.builder()
- .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, NO_KEYS).block())
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .runSuccessfullyWithin(FIVE_SECONDS);
-
- AWAIT_CONDITION.untilAsserted(() ->
- assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
- .isEqualTo(totalGlobalRegistrations * TOTAL_DISPATCH_OPERATIONS));
- }
-
- @Test
- default void concurrentDispatchKeyShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
- Mono.from(eventBus().register(countingListener1, KEY_1)).block();
- Mono.from(eventBus().register(countingListener2, KEY_2)).block();
- Mono.from(eventBus().register(countingListener3, KEY_3)).block();
-
- int totalKeyListenerRegistrations = 3; // KEY1 + KEY2 + KEY3
- int totalEventBus = 1;
-
- ConcurrentTestRunner.builder()
- .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, ALL_KEYS).block())
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .runSuccessfullyWithin(FIVE_SECONDS);
-
- AWAIT_CONDITION.untilAsserted(() ->
- assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
- .isEqualTo(totalKeyListenerRegistrations * totalEventBus * TOTAL_DISPATCH_OPERATIONS));
- }
-
- @Test
- default void concurrentDispatchShouldDeliverAllEventsToListenersWithSingleEventBus() throws Exception {
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-
- eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
- eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
- eventBus().register(countingListener3, new EventBusTestFixture.GroupC());
-
- int totalGlobalRegistrations = 3; // GroupA + GroupB + GroupC
- int totalEventDeliveredGlobally = totalGlobalRegistrations * TOTAL_DISPATCH_OPERATIONS;
-
- Mono.from(eventBus().register(countingListener1, KEY_1)).block();
- Mono.from(eventBus().register(countingListener2, KEY_2)).block();
- Mono.from(eventBus().register(countingListener3, KEY_3)).block();
- int totalKeyListenerRegistrations = 3; // KEY1 + KEY2 + KEY3
- int totalEventDeliveredByKeys = totalKeyListenerRegistrations * TOTAL_DISPATCH_OPERATIONS;
-
- ConcurrentTestRunner.builder()
- .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, ALL_KEYS).block())
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .runSuccessfullyWithin(FIVE_SECONDS);
-
- AWAIT_CONDITION.untilAsserted(() ->
- assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
- .isEqualTo(totalEventDeliveredGlobally + totalEventDeliveredByKeys));
- }
- }
-
- interface MultiEventBusConcurrentContract extends EventBusContract.MultipleEventBusContract {
-
- EventBus eventBus3();
-
- @Test
- default void concurrentDispatchGroupShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-
- eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
- eventBus().register(countingListener2, new EventBusTestFixture.GroupB());
- eventBus().register(countingListener3, new EventBusTestFixture.GroupC());
-
- eventBus2().register(countingListener1, new EventBusTestFixture.GroupA());
- eventBus2().register(countingListener2, new EventBusTestFixture.GroupB());
- eventBus2().register(countingListener3, new EventBusTestFixture.GroupC());
-
- int totalGlobalRegistrations = 3; // GroupA + GroupB + GroupC
-
- ConcurrentTestRunner.builder()
- .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, NO_KEYS).block())
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .runSuccessfullyWithin(FIVE_SECONDS);
-
- AWAIT_CONDITION.untilAsserted(() ->
- assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
- .isEqualTo(totalGlobalRegistrations * TOTAL_DISPATCH_OPERATIONS));
- }
-
- @Test
- default void concurrentDispatchKeyShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-
- Mono.from(eventBus().register(countingListener1, KEY_1)).block();
- Mono.from(eventBus().register(countingListener2, KEY_2)).block();
- Mono.from(eventBus().register(countingListener3, KEY_3)).block();
-
- Mono.from(eventBus2().register(countingListener1, KEY_1)).block();
- Mono.from(eventBus2().register(countingListener2, KEY_2)).block();
- Mono.from(eventBus2().register(countingListener3, KEY_3)).block();
-
- int totalKeyListenerRegistrations = 3; // KEY1 + KEY2 + KEY3
- int totalEventBus = 2; // eventBus1 + eventBus2
-
- ConcurrentTestRunner.builder()
- .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, ALL_KEYS).block())
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .runSuccessfullyWithin(FIVE_SECONDS);
-
- AWAIT_CONDITION.untilAsserted(() ->
- assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
- .isEqualTo(totalKeyListenerRegistrations * totalEventBus * TOTAL_DISPATCH_OPERATIONS));
- }
-
- @Test
- default void concurrentDispatchShouldDeliverAllEventsToListenersWithMultipleEventBus() throws Exception {
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener2 = newCountingListener();
- EventBusTestFixture.EventListenerCountingSuccessfulExecution countingListener3 = newCountingListener();
-
- eventBus2().register(countingListener1, GROUP_A);
- eventBus2().register(countingListener2, new EventBusTestFixture.GroupB());
- eventBus2().register(countingListener3, new EventBusTestFixture.GroupC());
- int totalGlobalRegistrations = 3; // GroupA + GroupB + GroupC
- int totalEventDeliveredGlobally = totalGlobalRegistrations * TOTAL_DISPATCH_OPERATIONS;
-
- Mono.from(eventBus().register(countingListener1, KEY_1)).block();
- Mono.from(eventBus().register(countingListener2, KEY_2)).block();
-
- Mono.from(eventBus2().register(countingListener1, KEY_1)).block();
- Mono.from(eventBus2().register(countingListener2, KEY_2)).block();
-
- Mono.from(eventBus3().register(countingListener3, KEY_1)).block();
- Mono.from(eventBus3().register(countingListener3, KEY_2)).block();
-
- int totalKeyListenerRegistrations = 2; // KEY1 + KEY2
- int totalEventBus = 3; // eventBus1 + eventBus2 + eventBus3
- int totalEventDeliveredByKeys = totalKeyListenerRegistrations * totalEventBus * TOTAL_DISPATCH_OPERATIONS;
-
- ConcurrentTestRunner.builder()
- .operation((threadNumber, operationNumber) -> eventBus().dispatch(EVENT, ALL_KEYS).block())
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .runSuccessfullyWithin(FIVE_SECONDS);
-
- AWAIT_CONDITION.untilAsserted(() ->
- assertThat(totalEventsReceived(ImmutableList.of(countingListener1, countingListener2, countingListener3)))
- .isEqualTo(totalEventDeliveredGlobally + totalEventDeliveredByKeys));
- }
- }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java
deleted file mode 100644
index c94c5a3..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusContract.java
+++ /dev/null
@@ -1,73 +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.mailbox.events;
-
-import static org.awaitility.Awaitility.await;
-
-import java.time.Duration;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.james.events.EventBus;
-import org.awaitility.core.ConditionFactory;
-
-public interface EventBusContract {
-
- enum EnvironmentSpeedProfile {
- SLOW(Duration.ofSeconds(2), Duration.ofSeconds(10)),
- FAST(Duration.ofMillis(200), Duration.ofSeconds(5));
-
- private final Duration shortWaitTime;
- private final Duration longWaitTime;
-
- EnvironmentSpeedProfile(Duration shortWaitTime, Duration longWaitTime) {
- this.shortWaitTime = shortWaitTime;
- this.longWaitTime = longWaitTime;
- }
-
- public Duration getShortWaitTime() {
- return shortWaitTime;
- }
-
- public Duration getLongWaitTime() {
- return longWaitTime;
- }
-
- public ConditionFactory shortWaitCondition() {
- return await().pollDelay(org.awaitility.Duration.ZERO)
- .pollInterval(org.awaitility.Duration.ONE_HUNDRED_MILLISECONDS)
- .timeout(new org.awaitility.Duration(this.getShortWaitTime().toMillis(), TimeUnit.MILLISECONDS));
- }
-
- public ConditionFactory longWaitCondition() {
- return await().pollDelay(org.awaitility.Duration.ZERO)
- .pollInterval(org.awaitility.Duration.ONE_HUNDRED_MILLISECONDS)
- .timeout(new org.awaitility.Duration(this.getLongWaitTime().toMillis(), TimeUnit.MILLISECONDS));
- }
- }
-
- EnvironmentSpeedProfile getSpeedProfile();
-
- interface MultipleEventBusContract extends EventBusContract {
-
- EventBus eventBus2();
- }
-
- EventBus eventBus();
-}
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusTestFixture.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusTestFixture.java
deleted file mode 100644
index dccec61..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventBusTestFixture.java
+++ /dev/null
@@ -1,145 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.RetryBackoffConfiguration.DEFAULT_JITTER_FACTOR;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.james.core.Username;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxEvent;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxRenamed;
-import org.apache.james.mailbox.model.MailboxConstants;
-import org.apache.james.mailbox.model.MailboxId;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.TestId;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-public interface EventBusTestFixture {
-
- class EventListenerCountingSuccessfulExecution implements EventListener {
- private final AtomicInteger calls = new AtomicInteger(0);
-
- @Override
- public boolean isHandling(Event event) {
- return true;
- }
-
- @Override
- public void event(Event event) {
- calls.incrementAndGet();
- }
-
- public int numberOfEventCalls() {
- return calls.get();
- }
- }
-
- class EventMatcherThrowingListener extends EventListenerCountingSuccessfulExecution {
- private final ImmutableSet<Event> eventsCauseThrowing;
-
- EventMatcherThrowingListener(ImmutableSet<Event> eventsCauseThrowing) {
- this.eventsCauseThrowing = eventsCauseThrowing;
- }
-
- @Override
- public boolean isHandling(Event event) {
- return true;
- }
-
- @Override
- public void event(Event event) {
- if (eventsCauseThrowing.contains(event)) {
- throw new RuntimeException("event triggers throwing");
- }
- super.event(event);
- }
- }
-
- class GroupA extends Group {
-
- }
-
- class GroupB extends Group {
-
- }
-
- class GroupC extends Group {
-
- }
-
- MailboxSession.SessionId SESSION_ID = MailboxSession.SessionId.of(42);
- Username USERNAME = Username.of("user");
- MailboxPath MAILBOX_PATH = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "mailboxName");
- TestId TEST_ID = TestId.of(18);
- Event.EventId EVENT_ID = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
- Event.EventId EVENT_ID_2 = Event.EventId.of("5a7a9f3f-5f03-44be-b457-a51e93760645");
- MailboxEvent EVENT = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, EVENT_ID);
- MailboxEvent EVENT_2 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, EVENT_ID_2);
- MailboxRenamed EVENT_UNSUPPORTED_BY_LISTENER = new MailboxRenamed(SESSION_ID, USERNAME, MAILBOX_PATH, TEST_ID, MAILBOX_PATH, EVENT_ID_2);
-
- java.time.Duration ONE_SECOND = java.time.Duration.ofSeconds(1);
- java.time.Duration FIVE_HUNDRED_MS = java.time.Duration.ofMillis(500);
- MailboxId ID_1 = TEST_ID;
- MailboxId ID_2 = TestId.of(24);
- MailboxId ID_3 = TestId.of(36);
- ImmutableSet<RegistrationKey> NO_KEYS = ImmutableSet.of();
- MailboxIdRegistrationKey KEY_1 = new MailboxIdRegistrationKey(ID_1);
- MailboxIdRegistrationKey KEY_2 = new MailboxIdRegistrationKey(ID_2);
- MailboxIdRegistrationKey KEY_3 = new MailboxIdRegistrationKey(ID_3);
- GroupA GROUP_A = new GroupA();
- GroupB GROUP_B = new GroupB();
- GroupC GROUP_C = new GroupC();
- List<Group> ALL_GROUPS = ImmutableList.of(GROUP_A, GROUP_B, GROUP_C);
-
- java.time.Duration DEFAULT_FIRST_BACKOFF = java.time.Duration.ofMillis(5);
- //Retry backoff configuration for testing with a shorter first backoff to accommodate the shorter retry interval in tests
- RetryBackoffConfiguration RETRY_BACKOFF_CONFIGURATION = RetryBackoffConfiguration.builder()
- .maxRetries(3)
- .firstBackoff(DEFAULT_FIRST_BACKOFF)
- .jitterFactor(DEFAULT_JITTER_FACTOR)
- .build();
-
- static EventListener newListener() {
- EventListener listener = mock(EventListener.class);
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
- when(listener.isHandling(any(MailboxAdded.class))).thenReturn(true);
- return listener;
- }
-
- static EventListener newAsyncListener() {
- EventListener listener = mock(EventListener.class);
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
- when(listener.isHandling(any(MailboxAdded.class))).thenReturn(true);
- return listener;
- }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersContract.java
deleted file mode 100644
index 1e8f003..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersContract.java
+++ /dev/null
@@ -1,493 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.time.Duration;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-import org.apache.james.core.Username;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.Group;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.model.MailboxConstants;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.util.concurrency.ConcurrentTestRunner;
-import org.junit.jupiter.api.Test;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
-
-interface EventDeadLettersContract {
-
- class Group0 extends Group {
-
- }
-
- class Group1 extends Group {
-
- }
-
- class Group2 extends Group {
-
- }
-
- class Group3 extends Group {
-
- }
-
- class Group4 extends Group {
-
- }
-
- class Group5 extends Group {
-
- }
-
- class Group6 extends Group {
-
- }
-
- class Group7 extends Group {
-
- }
-
- class Group8 extends Group {
-
- }
-
- class Group9 extends Group {
-
- }
-
- static ImmutableMap<Integer, Group> concurrentGroups() {
- return IntStream.range(0, CONCURRENT_GROUPS.size()).boxed()
- .collect(Guavate.toImmutableMap(Function.identity(), CONCURRENT_GROUPS::get));
- }
-
- static Event event(Event.EventId eventId) {
- return new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, eventId);
- }
-
- List<Group> CONCURRENT_GROUPS = ImmutableList.of(new Group0(), new Group1(), new Group2(), new Group3(), new Group4(), new Group5(),
- new Group6(), new Group7(), new Group8(), new Group9());
- Duration RUN_SUCCESSFULLY_IN = Duration.ofSeconds(5);
- int THREAD_COUNT = 10;
- int OPERATION_COUNT = 50;
-
- Username USERNAME = Username.of("user");
- MailboxPath MAILBOX_PATH = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "mailboxName");
- MailboxSession.SessionId SESSION_ID = MailboxSession.SessionId.of(235);
- TestId MAILBOX_ID = TestId.of(563);
- Event.EventId EVENT_ID_1 = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
- Event.EventId EVENT_ID_2 = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b5");
- Event.EventId EVENT_ID_3 = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b6");
- MailboxAdded EVENT_1 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_1);
- MailboxAdded EVENT_2 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_2);
- MailboxAdded EVENT_3 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_3);
- EventDeadLetters.InsertionId INSERTION_ID_1 = EventDeadLetters.InsertionId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b7");
- EventDeadLetters.InsertionId INSERTION_ID_2 = EventDeadLetters.InsertionId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b8");
- EventDeadLetters.InsertionId INSERTION_ID_3 = EventDeadLetters.InsertionId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b9");
-
- Group GROUP_A = new EventBusTestFixture.GroupA();
- Group GROUP_B = new EventBusTestFixture.GroupB();
- Group NULL_GROUP = null;
- Event NULL_EVENT = null;
- EventDeadLetters.InsertionId NULL_INSERTION_ID = null;
-
- EventDeadLetters eventDeadLetters();
-
- default Stream<EventDeadLetters.InsertionId> allInsertionIds() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- return eventDeadLetters.groupsWithFailedEvents()
- .flatMap(eventDeadLetters::failedIds)
- .toStream();
- }
-
- interface StoreContract extends EventDeadLettersContract {
-
- @Test
- default void storeShouldThrowWhenNullGroup() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThatThrownBy(() -> eventDeadLetters.store(NULL_GROUP, EVENT_1))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- default void storeShouldThrowWhenNullEvent() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThatThrownBy(() -> eventDeadLetters.store(GROUP_A, NULL_EVENT))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- default void storeShouldThrowWhenBothGroupAndEventAndInsertionIdAreNull() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThatThrownBy(() -> eventDeadLetters.store(NULL_GROUP, NULL_EVENT))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- default void storeShouldStoreGroupWithCorrespondingEvent() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(GROUP_A, EVENT_1).block();
- assertThat(eventDeadLetters.failedEvent(GROUP_A, insertionId).block())
- .isEqualTo(EVENT_1);
- }
-
- @Test
- default void storeShouldKeepConsistencyWhenConcurrentStore() throws Exception {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- ImmutableMap<Integer, Group> groups = concurrentGroups();
- Multimap<Integer, EventDeadLetters.InsertionId> storedInsertionIds = Multimaps.synchronizedSetMultimap(HashMultimap.create());
-
- ConcurrentTestRunner.builder()
- .operation((threadNumber, step) -> {
- Event.EventId eventId = Event.EventId.random();
- EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(groups.get(threadNumber), event(eventId)).block();
- storedInsertionIds.put(threadNumber, insertionId);
- })
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .runSuccessfullyWithin(RUN_SUCCESSFULLY_IN);
-
- groups.forEach((groupId, group) -> {
- Group storedGroup = groups.get(groupId);
- assertThat(eventDeadLetters.failedIds(storedGroup).collectList().block())
- .hasSameElementsAs(storedInsertionIds.get(groupId));
- });
- }
- }
-
- interface RemoveContract extends EventDeadLettersContract {
-
- @Test
- default void removeShouldThrowWhenGroupIsNull() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThatThrownBy(() -> eventDeadLetters.remove(NULL_GROUP, INSERTION_ID_1))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- default void removeShouldThrowWhenInsertionIdIsNull() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThatThrownBy(() -> eventDeadLetters.remove(GROUP_A, NULL_INSERTION_ID))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- default void removeShouldThrowWhenBothGroupAndInsertionIdAreNull() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThatThrownBy(() -> eventDeadLetters.remove(NULL_GROUP, NULL_INSERTION_ID))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- default void removeShouldRemoveMatched() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- eventDeadLetters.store(GROUP_A, EVENT_1).block();
- eventDeadLetters.store(GROUP_A, EVENT_2).block();
-
- eventDeadLetters.remove(GROUP_A, INSERTION_ID_1).block();
-
- assertThat(eventDeadLetters.failedEvent(GROUP_A, INSERTION_ID_1).block())
- .isNull();
- }
-
- @Test
- default void removeShouldKeepNonMatched() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- EventDeadLetters.InsertionId insertionId1 = eventDeadLetters.store(GROUP_A, EVENT_1).block();
- EventDeadLetters.InsertionId insertionId2 = eventDeadLetters.store(GROUP_A, EVENT_2).block();
- EventDeadLetters.InsertionId insertionId3 = eventDeadLetters.store(GROUP_A, EVENT_3).block();
-
- eventDeadLetters.remove(GROUP_A, insertionId1).block();
-
- assertThat(eventDeadLetters.failedIds(GROUP_A).toStream())
- .containsOnly(insertionId2, insertionId3);
- }
-
- @Test
- default void removeShouldNotThrowWhenNoInsertionIdMatched() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- eventDeadLetters.store(GROUP_A, EVENT_1).block();
-
- assertThatCode(() -> eventDeadLetters.remove(GROUP_A, INSERTION_ID_2).block())
- .doesNotThrowAnyException();
- }
-
- @Test
- default void removeShouldNotThrowWhenNoGroupMatched() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- eventDeadLetters.store(GROUP_A, EVENT_1).block();
-
- assertThatCode(() -> eventDeadLetters.remove(GROUP_B, INSERTION_ID_1).block())
- .doesNotThrowAnyException();
- }
-
- @Test
- default void removeShouldKeepConsistencyWhenConcurrentRemove() throws Exception {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- ImmutableMap<Integer, Group> groups = concurrentGroups();
- ConcurrentHashMap<Integer, EventDeadLetters.InsertionId> storedInsertionIds = new ConcurrentHashMap<>();
-
- ConcurrentTestRunner.builder()
- .operation((threadNumber, step) -> {
- int operationIndex = threadNumber * OPERATION_COUNT + step;
- Event.EventId eventId = Event.EventId.random();
- EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(groups.get(threadNumber), event(eventId)).block();
- storedInsertionIds.put(operationIndex, insertionId);
- })
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .runSuccessfullyWithin(RUN_SUCCESSFULLY_IN);
-
- ConcurrentTestRunner.builder()
- .operation((threadNumber, step) -> {
- int operationIndex = threadNumber * OPERATION_COUNT + step;
- eventDeadLetters.remove(groups.get(threadNumber), storedInsertionIds.get(operationIndex))
- .block();
- })
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .runSuccessfullyWithin(RUN_SUCCESSFULLY_IN);
-
- assertThat(allInsertionIds())
- .isEmpty();
- }
- }
-
- interface FailedEventContract extends EventDeadLettersContract {
-
- @Test
- default void failedEventShouldThrowWhenGroupIsNull() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThatThrownBy(() -> eventDeadLetters.failedEvent(NULL_GROUP, INSERTION_ID_1))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- default void failedEventShouldThrowWhenInsertionIdIsNull() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThatThrownBy(() -> eventDeadLetters.failedEvent(GROUP_A, NULL_INSERTION_ID))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- default void failedEventShouldThrowWhenBothGroupAndInsertionIdAreNull() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThatThrownBy(() -> eventDeadLetters.failedEvent(NULL_GROUP, NULL_INSERTION_ID))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- default void failedEventShouldReturnEmptyWhenNotFound() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- eventDeadLetters.store(GROUP_A, EVENT_1).block();
- eventDeadLetters.store(GROUP_A, EVENT_2).block();
-
- assertThat(eventDeadLetters.failedEvent(GROUP_A, INSERTION_ID_3).block())
- .isNull();
- }
-
- @Test
- default void failedEventShouldReturnEventWhenContains() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(GROUP_A, EVENT_1).block();
- eventDeadLetters.store(GROUP_A, EVENT_2).block();
-
- assertThat(eventDeadLetters.failedEvent(GROUP_A, insertionId).block())
- .isEqualTo(EVENT_1);
- }
-
- @Test
- default void failedEventShouldNotRemoveEvent() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- EventDeadLetters.InsertionId insertionId1 = eventDeadLetters.store(GROUP_A, EVENT_1).block();
- EventDeadLetters.InsertionId insertionId2 = eventDeadLetters.store(GROUP_A, EVENT_2).block();
- EventDeadLetters.InsertionId insertionId3 = eventDeadLetters.store(GROUP_A, EVENT_3).block();
-
- eventDeadLetters.failedEvent(GROUP_A, insertionId1).block();
-
- assertThat(allInsertionIds())
- .containsOnly(insertionId1, insertionId2, insertionId3);
- }
-
- @Test
- default void failedEventShouldNotThrowWhenNoGroupMatched() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(GROUP_A, EVENT_1).block();
-
- assertThatCode(() -> eventDeadLetters.failedEvent(GROUP_B, insertionId).block())
- .doesNotThrowAnyException();
- }
- }
-
- interface FailedEventsContract extends EventDeadLettersContract {
-
- @Test
- default void failedEventsShouldThrowWhenGroupIsNull() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThatThrownBy(() -> eventDeadLetters.failedIds(NULL_GROUP))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- default void failedEventsByGroupShouldReturnEmptyWhenNonMatch() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- eventDeadLetters.store(GROUP_A, EVENT_1).block();
- eventDeadLetters.store(GROUP_A, EVENT_2).block();
- eventDeadLetters.store(GROUP_A, EVENT_3).block();
-
- assertThat(eventDeadLetters.failedIds(GROUP_B).toStream())
- .isEmpty();
- }
-
- @Test
- default void failedEventsByGroupShouldReturnAllEventsCorrespondingToGivenGroup() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- EventDeadLetters.InsertionId insertionId = eventDeadLetters.store(GROUP_A, EVENT_1).block();
- eventDeadLetters.store(GROUP_B, EVENT_2).block();
- eventDeadLetters.store(GROUP_B, EVENT_3).block();
-
- assertThat(eventDeadLetters.failedIds(GROUP_A).toStream())
- .containsOnly(insertionId);
- }
-
- @Test
- default void failedEventsByGroupShouldNotRemoveEvents() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- EventDeadLetters.InsertionId insertionId1 = eventDeadLetters.store(GROUP_A, EVENT_1).block();
- EventDeadLetters.InsertionId insertionId2 = eventDeadLetters.store(GROUP_A, EVENT_2).block();
- EventDeadLetters.InsertionId insertionId3 = eventDeadLetters.store(GROUP_B, EVENT_3).block();
-
- eventDeadLetters.failedIds(GROUP_A).toStream();
-
- assertThat(allInsertionIds())
- .containsOnly(insertionId1, insertionId2, insertionId3);
- }
- }
-
- interface GroupsWithFailedEventsContract extends EventDeadLettersContract {
- @Test
- default void groupsWithFailedEventsShouldReturnAllStoredGroups() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
- eventDeadLetters.store(GROUP_A, EVENT_1).block();
- eventDeadLetters.store(GROUP_B, EVENT_1).block();
-
- assertThat(eventDeadLetters.groupsWithFailedEvents().collectList().block())
- .containsOnly(GROUP_A, GROUP_B);
- }
-
- @Test
- default void groupsWithFailedEventsShouldReturnEmptyWhenNoStored() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThat(eventDeadLetters.groupsWithFailedEvents().toStream()).isEmpty();
- }
- }
-
- interface ContainEventsContract extends EventDeadLettersContract {
- @Test
- default void containEventsShouldReturnFalseOnNothingStored() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
-
- assertThat(eventDeadLetters.containEvents().block()).isFalse();
- }
-
- @Test
- default void containEventsShouldReturnTrueOnStoredEvents() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
- eventDeadLetters.store(GROUP_A, EVENT_1).block();
-
- assertThat(eventDeadLetters.containEvents().block()).isTrue();
- }
-
- @Test
- default void containEventsShouldReturnFalseWhenRemoveAllStoredEvents() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
- EventDeadLetters.InsertionId insertionId1 = eventDeadLetters().store(GROUP_A, EVENT_1).block();
- EventDeadLetters.InsertionId insertionId2 = eventDeadLetters().store(GROUP_A, EVENT_2).block();
-
- assertThat(eventDeadLetters.containEvents().block()).isTrue();
-
- eventDeadLetters.remove(GROUP_A, insertionId1).block();
- eventDeadLetters.remove(GROUP_A, insertionId2).block();
-
- assertThat(eventDeadLetters.containEvents().block()).isFalse();
- }
-
- @Test
- default void containEventsShouldReturnTrueWhenRemoveSomeStoredEvents() {
- EventDeadLetters eventDeadLetters = eventDeadLetters();
- EventDeadLetters.InsertionId insertionId1 = eventDeadLetters().store(GROUP_A, EVENT_1).block();
- eventDeadLetters().store(GROUP_B, EVENT_2).block();
-
- assertThat(eventDeadLetters.containEvents().block()).isTrue();
-
- eventDeadLetters.remove(GROUP_A, insertionId1).block();
-
- assertThat(eventDeadLetters.containEvents().block()).isTrue();
- }
- }
-
- interface AllContracts extends StoreContract, RemoveContract, FailedEventContract, FailedEventsContract, GroupsWithFailedEventsContract, ContainEventsContract {
-
- }
-}
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheckContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheckContract.java
deleted file mode 100644
index 4479714..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/EventDeadLettersHealthCheckContract.java
+++ /dev/null
@@ -1,134 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.james.core.Username;
-import org.apache.james.core.healthcheck.ComponentName;
-import org.apache.james.core.healthcheck.Result;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventDeadLettersHealthCheck;
-import org.apache.james.events.Group;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.model.MailboxConstants;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.TestId;
-import org.junit.jupiter.api.Test;
-
-interface EventDeadLettersHealthCheckContract {
-
- ComponentName COMPONENT_NAME = new ComponentName("EventDeadLettersHealthCheck");
- String EXPECTED_DEGRADED_MESSAGE = "EventDeadLetters contain events. This might indicate transient failure on mailbox event processing.";
-
- Username USERNAME = Username.of("user");
- MailboxPath MAILBOX_PATH = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "mailboxName");
- MailboxSession.SessionId SESSION_ID = MailboxSession.SessionId.of(235);
- TestId MAILBOX_ID = TestId.of(563);
- Event.EventId EVENT_ID_1 = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
- Event.EventId EVENT_ID_2 = Event.EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b5");
- MailboxAdded EVENT_1 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_1);
- MailboxAdded EVENT_2 = new MailboxAdded(SESSION_ID, USERNAME, MAILBOX_PATH, MAILBOX_ID, EVENT_ID_2);
-
- Group GROUP_A = new EventBusTestFixture.GroupA();
- Group GROUP_B = new EventBusTestFixture.GroupB();
-
- EventDeadLettersHealthCheck testee();
-
- EventDeadLetters eventDeadLetters();
-
- void createErrorWhenDoingHealthCheck();
-
- void resolveErrorWhenDoingHealthCheck();
-
- @Test
- default void checkShouldReturnHealthyWhenEventDeadLetterEmpty() {
- assertThat(testee().check().block().isHealthy()).isTrue();
- assertThat(testee().check().block())
- .isEqualTo(Result.healthy(COMPONENT_NAME));
- }
-
- @Test
- default void checkShouldReturnDegradedWhenEventDeadLetterContainEvent() {
- eventDeadLetters().store(GROUP_A, EVENT_1).block();
-
- assertThat(testee().check().block().isDegraded()).isTrue();
- assertThat(testee().check().block())
- .isEqualTo(Result.degraded(COMPONENT_NAME, EXPECTED_DEGRADED_MESSAGE));
- }
-
- @Test
- default void checkShouldReturnDegradedWhenEventDeadLetterContainEvents() {
- eventDeadLetters().store(GROUP_A, EVENT_1).block();
- eventDeadLetters().store(GROUP_B, EVENT_2).block();
-
- assertThat(testee().check().block().isDegraded()).isTrue();
- assertThat(testee().check().block())
- .isEqualTo(Result.degraded(COMPONENT_NAME, EXPECTED_DEGRADED_MESSAGE));
- }
-
- @Test
- default void checkShouldReturnHealthyWhenRemovedAllEventDeadLetters() {
- EventDeadLetters.InsertionId insertionId1 = eventDeadLetters().store(GROUP_A, EVENT_1).block();
- EventDeadLetters.InsertionId insertionId2 = eventDeadLetters().store(GROUP_B, EVENT_2).block();
-
- assertThat(testee().check().block().isDegraded()).isTrue();
- assertThat(testee().check().block())
- .isEqualTo(Result.degraded(COMPONENT_NAME, EXPECTED_DEGRADED_MESSAGE));
-
- eventDeadLetters().remove(GROUP_A, insertionId1).block();
- eventDeadLetters().remove(GROUP_B, insertionId2).block();
-
- assertThat(testee().check().block().isHealthy()).isTrue();
- assertThat(testee().check().block())
- .isEqualTo(Result.healthy(COMPONENT_NAME));
- }
-
- @Test
- default void checkShouldReturnDegradedWhenRemovedSomeEventDeadLetters() {
- EventDeadLetters.InsertionId insertionId1 = eventDeadLetters().store(GROUP_A, EVENT_1).block();
- eventDeadLetters().store(GROUP_B, EVENT_2).block();
-
- assertThat(testee().check().block().isDegraded()).isTrue();
- assertThat(testee().check().block())
- .isEqualTo(Result.degraded(COMPONENT_NAME, EXPECTED_DEGRADED_MESSAGE));
-
- eventDeadLetters().remove(GROUP_A, insertionId1).block();
-
- assertThat(testee().check().block().isDegraded()).isTrue();
- assertThat(testee().check().block())
- .isEqualTo(Result.degraded(COMPONENT_NAME, EXPECTED_DEGRADED_MESSAGE));
- }
-
- @Test
- default void checkShouldReturnUnHealthyWhenEventDeadLetterError() {
- Result actualResult;
- try {
- createErrorWhenDoingHealthCheck();
- actualResult = testee().check().block();
- } finally {
- resolveErrorWhenDoingHealthCheck();
- }
-
- assertThat(actualResult.isUnHealthy()).isTrue();
- }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupContract.java
deleted file mode 100644
index fb5131d..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupContract.java
+++ /dev/null
@@ -1,504 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_ID;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_UNSUPPORTED_BY_LISTENER;
-import static org.apache.james.mailbox.events.EventBusTestFixture.FIVE_HUNDRED_MS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_A;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_B;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_C;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.ONE_SECOND;
-import static org.apache.james.mailbox.events.EventBusTestFixture.newListener;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.time.Duration;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.IntStream;
-
-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.GenericGroup;
-import org.apache.james.events.Group;
-import org.apache.james.events.GroupAlreadyRegistered;
-import org.apache.james.events.GroupRegistrationNotFound;
-import org.apache.james.events.Registration;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.TestId;
-import org.junit.jupiter.api.Test;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedMap;
-
-import reactor.core.scheduler.Schedulers;
-
-public interface GroupContract {
-
- interface SingleEventBusGroupContract extends EventBusContract {
-
- @Test
- default void groupDeliveryShouldNotExceedRate() {
- int eventCount = 50;
- AtomicInteger nbCalls = new AtomicInteger(0);
- AtomicInteger finishedExecutions = new AtomicInteger(0);
- AtomicBoolean rateExceeded = new AtomicBoolean(false);
-
- eventBus().register(new EventListener.GroupEventListener() {
- @Override
- public Group getDefaultGroup() {
- return new GenericGroup("group");
- }
-
- @Override
- public boolean isHandling(Event event) {
- return true;
- }
-
- @Override
- public void event(Event event) throws Exception {
- if (nbCalls.get() - finishedExecutions.get() > EventBus.EXECUTION_RATE) {
- rateExceeded.set(true);
- }
- nbCalls.incrementAndGet();
- Thread.sleep(Duration.ofMillis(20).toMillis());
- finishedExecutions.incrementAndGet();
-
- }
- }, GROUP_A);
-
- IntStream.range(0, eventCount)
- .forEach(i -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
- getSpeedProfile().shortWaitCondition().atMost(org.awaitility.Duration.TEN_MINUTES)
- .untilAsserted(() -> assertThat(finishedExecutions.get()).isEqualTo(eventCount));
- assertThat(rateExceeded).isFalse();
- }
-
- @Test
- default void groupNotificationShouldDeliverASingleEventToAllListenersAtTheSameTime() {
- CountDownLatch countDownLatch = new CountDownLatch(1);
- try {
- ConcurrentLinkedQueue<String> threads = new ConcurrentLinkedQueue<>();
- eventBus().register(new EventListener.GroupEventListener() {
- @Override
- public Group getDefaultGroup() {
- return new GenericGroup("groupA");
- }
-
- @Override
- public void event(Event event) throws Exception {
- threads.add(Thread.currentThread().getName());
- countDownLatch.await();
- }
- }, GROUP_A);
- eventBus().register(new EventListener.GroupEventListener() {
- @Override
- public Group getDefaultGroup() {
- return new GenericGroup("groupB");
- }
-
- @Override
- public void event(Event event) throws Exception {
- threads.add(Thread.currentThread().getName());
- countDownLatch.await();
- }
- }, GROUP_B);
- eventBus().register(new EventListener.GroupEventListener() {
- @Override
- public Group getDefaultGroup() {
- return new GenericGroup("groupC");
- }
-
- @Override
- public void event(Event event) throws Exception {
- threads.add(Thread.currentThread().getName());
- countDownLatch.await();
- }
- }, GROUP_C);
-
- eventBus().dispatch(EVENT, NO_KEYS).subscribeOn(Schedulers.elastic()).subscribe();
-
-
- getSpeedProfile().shortWaitCondition().atMost(org.awaitility.Duration.TEN_SECONDS)
- .untilAsserted(() -> assertThat(threads).hasSize(3));
- assertThat(threads).doesNotHaveDuplicates();
- } finally {
- countDownLatch.countDown();
- }
- }
-
- @Test
- default void listenersShouldBeAbleToDispatch() {
- AtomicBoolean successfulRetry = new AtomicBoolean(false);
- EventListener listener = event -> {
- if (event.getEventId().equals(EVENT_ID)) {
- eventBus().dispatch(EVENT_2, NO_KEYS)
- .subscribeOn(Schedulers.elastic())
- .block();
- successfulRetry.set(true);
- }
- };
-
- eventBus().register(listener, GROUP_A);
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- getSpeedProfile().shortWaitCondition().until(successfulRetry::get);
- }
-
- @Test
- default void registerShouldNotDispatchPastEventsForGroups() throws Exception {
- EventListener listener = newListener();
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- eventBus().register(listener, GROUP_A);
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void listenerGroupShouldReceiveEvents() throws Exception {
- EventListener listener = newListener();
-
- eventBus().register(listener, GROUP_A);
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void groupListenersShouldNotReceiveNoopEvents() throws Exception {
- EventListener listener = newListener();
-
- eventBus().register(listener, GROUP_A);
-
- Username bob = Username.of("bob");
- Added noopEvent = new Added(MailboxSession.SessionId.of(18), bob, MailboxPath.forUser(bob, "mailbox"), TestId.of(58), ImmutableSortedMap.of(), Event.EventId.random());
- eventBus().dispatch(noopEvent, NO_KEYS).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void groupListenersShouldReceiveOnlyHandledEvents() throws Exception {
- EventListener listener = newListener();
-
- eventBus().register(listener, GROUP_A);
-
- eventBus().dispatch(EVENT_UNSUPPORTED_BY_LISTENER, NO_KEYS).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void dispatchShouldNotThrowWhenAGroupListenerFails() throws Exception {
- EventListener listener = newListener();
- doThrow(new RuntimeException()).when(listener).event(any());
-
- eventBus().register(listener, GROUP_A);
-
- assertThatCode(() -> eventBus().dispatch(EVENT, NO_KEYS).block())
- .doesNotThrowAnyException();
- }
-
- @Test
- default void eachListenerGroupShouldReceiveEvents() throws Exception {
- EventListener listener = newListener();
- EventListener listener2 = newListener();
- eventBus().register(listener, GROUP_A);
- eventBus().register(listener2, GROUP_B);
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- verify(listener2, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void unregisteredGroupListenerShouldNotReceiveEvents() throws Exception {
- EventListener listener = newListener();
- Registration registration = eventBus().register(listener, GROUP_A);
-
- registration.unregister();
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void registerShouldThrowWhenAGroupIsAlreadyUsed() {
- EventListener listener = newListener();
- EventListener listener2 = newListener();
-
- eventBus().register(listener, GROUP_A);
-
- assertThatThrownBy(() -> eventBus().register(listener2, GROUP_A))
- .isInstanceOf(GroupAlreadyRegistered.class);
- }
-
- @Test
- default void registerShouldNotThrowOnAnUnregisteredGroup() {
- EventListener listener = newListener();
- EventListener listener2 = newListener();
-
- eventBus().register(listener, GROUP_A).unregister();
-
- assertThatCode(() -> eventBus().register(listener2, GROUP_A))
- .doesNotThrowAnyException();
- }
-
- @Test
- default void unregisterShouldBeIdempotentForGroups() {
- EventListener listener = newListener();
-
- Registration registration = eventBus().register(listener, GROUP_A);
- registration.unregister();
-
- assertThatCode(registration::unregister)
- .doesNotThrowAnyException();
- }
-
- @Test
- default void registerShouldAcceptAlreadyUnregisteredGroups() throws Exception {
- EventListener listener = newListener();
-
- eventBus().register(listener, GROUP_A).unregister();
- eventBus().register(listener, GROUP_A);
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void dispatchShouldCallSynchronousListener() throws Exception {
- EventListener listener = newListener();
-
- eventBus().register(listener, GROUP_A);
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void failingGroupListenersShouldNotAbortGroupDelivery() {
- EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = new EventBusTestFixture.EventMatcherThrowingListener(ImmutableSet.of(EVENT));
- eventBus().register(listener, GROUP_A);
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
- eventBus().dispatch(EVENT_2, NO_KEYS).block();
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(listener.numberOfEventCalls()).isEqualTo(1));
- }
-
- @Test
- default void allGroupListenersShouldBeExecutedWhenAGroupListenerFails() throws Exception {
- EventListener listener = newListener();
-
- EventListener failingListener = mock(EventListener.class);
- when(failingListener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
- doThrow(new RuntimeException()).when(failingListener).event(any());
-
- eventBus().register(failingListener, GROUP_A);
- eventBus().register(listener, GROUP_B);
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void allGroupListenersShouldBeExecutedWhenGenericGroups() throws Exception {
- EventListener listener1 = newListener();
- EventListener listener2 = newListener();
-
- eventBus().register(listener1, new GenericGroup("a"));
- eventBus().register(listener2, new GenericGroup("b"));
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- verify(listener1, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- verify(listener2, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void groupListenerShouldReceiveEventWhenRedeliver() throws Exception {
- EventListener listener = newListener();
-
- eventBus().register(listener, GROUP_A);
-
- eventBus().reDeliver(GROUP_A, EVENT).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void redeliverShouldNotThrowWhenAGroupListenerFails() throws Exception {
- EventListener listener = newListener();
- doThrow(new RuntimeException()).when(listener).event(any());
-
- eventBus().register(listener, GROUP_A);
-
- assertThatCode(() -> eventBus().reDeliver(GROUP_A, EVENT).block())
- .doesNotThrowAnyException();
- }
-
- @Test
- default void redeliverShouldThrowWhenGroupNotRegistered() {
- assertThatThrownBy(() -> eventBus().reDeliver(GROUP_A, EVENT).block())
- .isInstanceOf(GroupRegistrationNotFound.class);
- }
-
- @Test
- default void redeliverShouldThrowAfterGroupIsUnregistered() {
- EventListener listener = newListener();
-
- eventBus().register(listener, GROUP_A).unregister();
-
- assertThatThrownBy(() -> eventBus().reDeliver(GROUP_A, EVENT).block())
- .isInstanceOf(GroupRegistrationNotFound.class);
- }
-
- @Test
- default void redeliverShouldOnlySendEventToDefinedGroup() throws Exception {
- EventListener listener = newListener();
- EventListener listener2 = newListener();
- eventBus().register(listener, GROUP_A);
- eventBus().register(listener2, GROUP_B);
-
- eventBus().reDeliver(GROUP_A, EVENT).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- verify(listener2, after(FIVE_HUNDRED_MS.toMillis()).never()).event(any());
- }
-
- @Test
- default void groupListenersShouldNotReceiveNoopRedeliveredEvents() throws Exception {
- EventListener listener = newListener();
-
- eventBus().register(listener, GROUP_A);
-
- Username bob = Username.of("bob");
- Added noopEvent = new Added(MailboxSession.SessionId.of(18), bob, MailboxPath.forUser(bob, "mailbox"), TestId.of(58), ImmutableSortedMap.of(), Event.EventId.random());
- eventBus().reDeliver(GROUP_A, noopEvent).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never()).event(any());
- }
- }
-
- interface MultipleEventBusGroupContract extends EventBusContract.MultipleEventBusContract {
-
- @Test
- default void groupsDefinedOnlyOnSomeNodesShouldBeNotifiedWhenDispatch() throws Exception {
- EventListener mailboxListener = newListener();
-
- eventBus().register(mailboxListener, GROUP_A);
-
- eventBus2().dispatch(EVENT, NO_KEYS).block();
-
- verify(mailboxListener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void groupsDefinedOnlyOnSomeNodesShouldNotBeNotifiedWhenRedeliver() {
- EventListener mailboxListener = newListener();
-
- eventBus().register(mailboxListener, GROUP_A);
-
- assertThatThrownBy(() -> eventBus2().reDeliver(GROUP_A, EVENT).block())
- .isInstanceOf(GroupRegistrationNotFound.class);
- }
-
- @Test
- default void groupListenersShouldBeExecutedOnceWhenRedeliverInADistributedEnvironment() throws Exception {
- EventListener mailboxListener = newListener();
-
- eventBus().register(mailboxListener, GROUP_A);
- eventBus2().register(mailboxListener, GROUP_A);
-
- eventBus2().reDeliver(GROUP_A, EVENT).block();
-
- verify(mailboxListener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void groupListenersShouldBeExecutedOnceInAControlledEnvironment() throws Exception {
- EventListener mailboxListener = newListener();
-
- eventBus().register(mailboxListener, GROUP_A);
- eventBus2().register(mailboxListener, GROUP_A);
-
- eventBus2().dispatch(EVENT, NO_KEYS).block();
-
- verify(mailboxListener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void unregisterShouldStopNotificationForDistantGroups() throws Exception {
- EventListener mailboxListener = newListener();
-
- eventBus().register(mailboxListener, GROUP_A).unregister();
-
- eventBus2().dispatch(EVENT, NO_KEYS).block();
-
-
- verify(mailboxListener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void registerShouldNotDispatchPastEventsForGroupsInADistributedContext() throws Exception {
- EventListener listener = newListener();
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- eventBus2().register(listener, GROUP_A);
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
- }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupTest.java
deleted file mode 100644
index 53176df..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/GroupTest.java
+++ /dev/null
@@ -1,135 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import org.apache.james.events.GenericGroup;
-import org.apache.james.events.Group;
-import org.junit.jupiter.api.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-class GroupTest {
- static class GroupA extends Group {
-
- }
-
- static class GroupB extends Group {
-
- }
-
- static class GroupC extends GroupA {
-
- }
-
- @Test
- void shouldMatchBeanContract() {
- EqualsVerifier.forClass(Group.class)
- .usingGetClass()
- .verify();
- }
-
- @Test
- void equalsShouldReturnTrueOnSameClass() {
- assertThat(new GroupA()).isEqualTo(new GroupA());
- }
-
- @Test
- void equalsShouldReturnFalseOnDifferentClass() {
- assertThat(new GroupA()).isNotEqualTo(new GroupB());
- }
-
- @Test
- void equalsShouldReturnFalseOnSubClass() {
- assertThat(new GroupA()).isNotEqualTo(new GroupC());
- }
-
- @Test
- void equalsShouldReturnFalseOnParentClass() {
- assertThat(new GroupC()).isNotEqualTo(new GroupA());
- }
-
- @Test
- void genericGroupShouldMatchBeanContract() {
- EqualsVerifier.forClass(GenericGroup.class)
- .withRedefinedSuperclass()
- .verify();
- }
-
- @Test
- void asStringShouldReturnFqdnByDefault() {
- assertThat(new EventBusTestFixture.GroupA().asString()).isEqualTo("org.apache.james.mailbox.events.EventBusTestFixture$GroupA");
- }
-
- @Test
- void asStringShouldReturnNameWhenGenericGroup() {
- assertThat(new GenericGroup("abc").asString()).isEqualTo("org.apache.james.events.GenericGroup-abc");
- }
-
- @Test
- void deserializeShouldReturnGroupWhenGenericGroup() throws Exception {
- assertThat(Group.deserialize("org.apache.james.events.GenericGroup-abc"))
- .isEqualTo(new GenericGroup("abc"));
- }
-
- @Test
- void deserializeShouldReturnGroupWhenEmptyGenericGroup() throws Exception {
- assertThat(Group.deserialize("org.apache.james.events.GenericGroup-"))
- .isEqualTo(new GenericGroup(""));
- }
-
- @Test
- void deserializeShouldReturnGroupWhenExtendsGroup() throws Exception {
- assertThat(Group.deserialize("org.apache.james.mailbox.events.EventBusTestFixture$GroupA"))
- .isEqualTo(new EventBusTestFixture.GroupA());
- }
-
- @Test
- void deserializeShouldThrowWhenClassNotFound() {
- assertThatThrownBy(() -> Group.deserialize("org.apache.james.mailbox.events.Noone"))
- .isInstanceOf(Group.GroupDeserializationException.class);
- }
-
- @Test
- void deserializeShouldThrowWhenNotAGroup() {
- assertThatThrownBy(() -> Group.deserialize("java.lang.String"))
- .isInstanceOf(Group.GroupDeserializationException.class);
- }
-
- @Test
- void deserializeShouldThrowWhenConstructorArgumentsRequired() {
- assertThatThrownBy(() -> Group.deserialize("org.apache.james.events.GenericGroup"))
- .isInstanceOf(Group.GroupDeserializationException.class);
- }
-
- @Test
- void deserializeShouldThrowWhenNull() {
- assertThatThrownBy(() -> Group.deserialize(null))
- .isInstanceOf(Group.GroupDeserializationException.class);
- }
-
- @Test
- void deserializeShouldThrowWhenEmpty() {
- assertThatThrownBy(() -> Group.deserialize(""))
- .isInstanceOf(Group.GroupDeserializationException.class);
- }
-}
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java
deleted file mode 100644
index c951edd..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/InsertionIdTest.java
+++ /dev/null
@@ -1,57 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.util.UUID;
-
-import org.apache.james.events.EventDeadLetters;
-import org.junit.jupiter.api.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-class InsertionIdTest {
- private static final UUID UUID_1 = UUID.fromString("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
-
- @Test
- void eventIdShouldMatchBeanContract() {
- EqualsVerifier.forClass(EventDeadLetters.InsertionId.class).verify();
- }
-
- @Test
- void ofShouldDeserializeUUIDs() {
- assertThat(EventDeadLetters.InsertionId.of(UUID_1.toString()))
- .isEqualTo(EventDeadLetters.InsertionId.of(UUID_1));
- }
-
- @Test
- void ofStringShouldThrowOnNullValue() {
- assertThatThrownBy(() -> EventDeadLetters.InsertionId.of((String) null))
- .isInstanceOf(NullPointerException.class);
- }
-
- @Test
- void ofUuidShouldThrowOnNullValue() {
- assertThatThrownBy(() -> EventDeadLetters.InsertionId.of((UUID) null))
- .isInstanceOf(NullPointerException.class);
- }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/KeyContract.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/KeyContract.java
deleted file mode 100644
index 4c22d4b..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/KeyContract.java
+++ /dev/null
@@ -1,458 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_UNSUPPORTED_BY_LISTENER;
-import static org.apache.james.mailbox.events.EventBusTestFixture.FIVE_HUNDRED_MS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_1;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.ONE_SECOND;
-import static org.apache.james.mailbox.events.EventBusTestFixture.newListener;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.junit.jupiter.api.Assertions.assertTimeout;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.time.Duration;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.IntStream;
-
-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.Registration;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
-import org.apache.james.mailbox.model.MailboxPath;
-import org.apache.james.mailbox.model.TestId;
-import org.junit.jupiter.api.Test;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedMap;
-
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-
-public interface KeyContract extends EventBusContract {
-
- interface SingleEventBusKeyContract extends EventBusContract {
- @Test
- default void notificationShouldNotExceedRate() {
- int eventCount = 50;
- AtomicInteger nbCalls = new AtomicInteger(0);
- AtomicInteger finishedExecutions = new AtomicInteger(0);
- AtomicBoolean rateExceeded = new AtomicBoolean(false);
-
- Mono.from(eventBus().register(event -> {
- if (nbCalls.get() - finishedExecutions.get() > EventBus.EXECUTION_RATE) {
- rateExceeded.set(true);
- }
- nbCalls.incrementAndGet();
- Thread.sleep(Duration.ofMillis(20).toMillis());
- finishedExecutions.incrementAndGet();
-
- }, KEY_1)).block();
-
- IntStream.range(0, eventCount)
- .forEach(i -> eventBus().dispatch(EVENT, KEY_1).block());
-
- getSpeedProfile().shortWaitCondition().atMost(org.awaitility.Duration.TEN_MINUTES)
- .untilAsserted(() -> assertThat(finishedExecutions.get()).isEqualTo(eventCount));
- assertThat(rateExceeded).isFalse();
- }
-
- @Test
- default void notificationShouldDeliverASingleEventToAllListenersAtTheSameTime() {
- CountDownLatch countDownLatch = new CountDownLatch(1);
- try {
- ConcurrentLinkedQueue<String> threads = new ConcurrentLinkedQueue<>();
- Mono.from(eventBus().register(event -> {
- threads.add(Thread.currentThread().getName());
- countDownLatch.await();
- }, KEY_1)).block();
- Mono.from(eventBus().register(event -> {
- threads.add(Thread.currentThread().getName());
- countDownLatch.await();
- }, KEY_1)).block();
- Mono.from(eventBus().register(event -> {
- threads.add(Thread.currentThread().getName());
- countDownLatch.await();
- }, KEY_1)).block();
-
- eventBus().dispatch(EVENT, KEY_1).subscribeOn(Schedulers.elastic()).subscribe();
-
-
- getSpeedProfile().shortWaitCondition().atMost(org.awaitility.Duration.TEN_SECONDS)
- .untilAsserted(() -> assertThat(threads).hasSize(3));
- assertThat(threads).doesNotHaveDuplicates();
- } finally {
- countDownLatch.countDown();
- }
- }
-
-
- @Test
- default void registeredListenersShouldNotReceiveNoopEvents() throws Exception {
- EventListener listener = newListener();
-
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- Username bob = Username.of("bob");
- Added noopEvent = new Added(MailboxSession.SessionId.of(18), bob, MailboxPath.forUser(bob, "mailbox"), TestId.of(58), ImmutableSortedMap.of(), Event.EventId.random());
- eventBus().dispatch(noopEvent, KEY_1).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void registeredListenersShouldReceiveOnlyHandledEvents() throws Exception {
- EventListener listener = newListener();
-
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- eventBus().dispatch(EVENT_UNSUPPORTED_BY_LISTENER, KEY_1).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void dispatchShouldNotThrowWhenARegisteredListenerFails() throws Exception {
- EventListener listener = newListener();
- doThrow(new RuntimeException()).when(listener).event(any());
-
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- assertThatCode(() -> eventBus().dispatch(EVENT, NO_KEYS).block())
- .doesNotThrowAnyException();
- }
-
- @Test
- default void dispatchShouldNotNotifyRegisteredListenerWhenEmptyKeySet() throws Exception {
- EventListener listener = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- eventBus().dispatch(EVENT, NO_KEYS).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void dispatchShouldNotNotifyListenerRegisteredOnOtherKeys() throws Exception {
- EventListener listener = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_2)).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void dispatchShouldNotifyRegisteredListeners() throws Exception {
- EventListener listener = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void dispatchShouldNotifyLocalRegisteredListenerWithoutDelay() throws Exception {
- EventListener listener = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(listener, times(1)).event(any());
- }
-
- @Test
- default void dispatchShouldNotifyOnlyRegisteredListener() throws Exception {
- EventListener listener = newListener();
- EventListener listener2 = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
- Mono.from(eventBus().register(listener2, KEY_2)).block();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- verify(listener2, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void dispatchShouldNotifyAllListenersRegisteredOnAKey() throws Exception {
- EventListener listener = newListener();
- EventListener listener2 = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
- Mono.from(eventBus().register(listener2, KEY_1)).block();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- verify(listener2, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void registerShouldAllowDuplicatedRegistration() throws Exception {
- EventListener listener = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void unregisterShouldRemoveDoubleRegisteredListener() throws Exception {
- EventListener listener = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
- Mono.from(eventBus().register(listener, KEY_1)).block().unregister();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void registerShouldNotDispatchPastEvents() throws Exception {
- EventListener listener = newListener();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void callingAllUnregisterMethodShouldUnregisterTheListener() throws Exception {
- EventListener listener = newListener();
- Registration registration = Mono.from(eventBus().register(listener, KEY_1)).block();
- Mono.from(eventBus().register(listener, KEY_1)).block().unregister();
- registration.unregister();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void unregisterShouldHaveNotNotifyWhenCalledOnDifferentKeys() throws Exception {
- EventListener listener = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
- Mono.from(eventBus().register(listener, KEY_2)).block().unregister();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void unregisterShouldBeIdempotentForKeyRegistrations() {
- EventListener listener = newListener();
-
- Registration registration = Mono.from(eventBus().register(listener, KEY_1)).block();
- registration.unregister();
-
- assertThatCode(registration::unregister)
- .doesNotThrowAnyException();
- }
-
- @Test
- default void dispatchShouldAcceptSeveralKeys() throws Exception {
- EventListener listener = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1, KEY_2)).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void dispatchShouldCallListenerOnceWhenSeveralKeysMatching() throws Exception {
- EventListener listener = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block();
- Mono.from(eventBus().register(listener, KEY_2)).block();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1, KEY_2)).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void dispatchShouldNotNotifyUnregisteredListener() throws Exception {
- EventListener listener = newListener();
- Mono.from(eventBus().register(listener, KEY_1)).block().unregister();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
-
- @Test
- default void dispatchShouldNotifyAsynchronousListener() throws Exception {
- EventListener listener = newListener();
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- eventBus().dispatch(EVENT, KEY_1).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis())).event(EVENT);
- }
-
- @Test
- default void dispatchShouldNotBlockAsynchronousListener() throws Exception {
- EventListener listener = newListener();
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
- CountDownLatch latch = new CountDownLatch(1);
- doAnswer(invocation -> {
- latch.await();
- return null;
- }).when(listener).event(EVENT);
-
- assertTimeout(Duration.ofSeconds(2),
- () -> {
- eventBus().dispatch(EVENT, NO_KEYS).block();
- latch.countDown();
- });
- }
-
- @Test
- default void failingRegisteredListenersShouldNotAbortRegisteredDelivery() {
- EventBusTestFixture.EventListenerCountingSuccessfulExecution listener = new EventBusTestFixture.EventMatcherThrowingListener(ImmutableSet.of(EVENT));
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- eventBus().dispatch(EVENT, KEY_1).block();
- eventBus().dispatch(EVENT_2, KEY_1).block();
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(listener.numberOfEventCalls()).isEqualTo(1));
- }
-
- @Test
- default void allRegisteredListenersShouldBeExecutedWhenARegisteredListenerFails() throws Exception {
- EventListener listener = newListener();
-
- EventListener failingListener = mock(EventListener.class);
- when(failingListener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
- doThrow(new RuntimeException()).when(failingListener).event(any());
-
- Mono.from(eventBus().register(failingListener, KEY_1)).block();
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- eventBus().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(listener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
- }
-
- interface MultipleEventBusKeyContract extends MultipleEventBusContract {
-
- @Test
- default void crossEventBusRegistrationShouldBeAllowed() throws Exception {
- EventListener mailboxListener = newListener();
-
- Mono.from(eventBus().register(mailboxListener, KEY_1)).block();
-
- eventBus2().dispatch(EVENT, KEY_1).block();
-
- verify(mailboxListener, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void unregisteredDistantListenersShouldNotBeNotified() throws Exception {
- EventListener eventListener = newListener();
-
- Mono.from(eventBus().register(eventListener, KEY_1)).block().unregister();
-
- eventBus2().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- verify(eventListener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void allRegisteredListenersShouldBeDispatched() throws Exception {
- EventListener mailboxListener1 = newListener();
- EventListener mailboxListener2 = newListener();
-
- Mono.from(eventBus().register(mailboxListener1, KEY_1)).block();
- Mono.from(eventBus2().register(mailboxListener2, KEY_1)).block();
-
- eventBus2().dispatch(EVENT, KEY_1).block();
-
- verify(mailboxListener1, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- verify(mailboxListener2, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- @Test
- default void registerShouldNotDispatchPastEventsInDistributedContext() throws Exception {
- EventListener listener = newListener();
-
- eventBus2().dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
-
- Mono.from(eventBus().register(listener, KEY_1)).block();
-
- verify(listener, after(FIVE_HUNDRED_MS.toMillis()).never())
- .event(any());
- }
-
- @Test
- default void localDispatchedListenersShouldBeDispatchedWithoutDelay() throws Exception {
- EventListener mailboxListener1 = newListener();
- EventListener mailboxListener2 = newListener();
-
- Mono.from(eventBus().register(mailboxListener1, KEY_1)).block();
- Mono.from(eventBus2().register(mailboxListener2, KEY_1)).block();
-
- eventBus2().dispatch(EVENT, KEY_1).block();
-
- verify(mailboxListener2, times(1)).event(any());
- verify(mailboxListener1, timeout(ONE_SECOND.toMillis()).times(1)).event(any());
- }
-
- }
-}
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/MailboxIdRegistrationKeyTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/MailboxIdRegistrationKeyTest.java
deleted file mode 100644
index 0a361b6..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/MailboxIdRegistrationKeyTest.java
+++ /dev/null
@@ -1,60 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import org.apache.james.mailbox.model.TestId;
-import org.junit.jupiter.api.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-class MailboxIdRegistrationKeyTest {
- private static final String ID = "42";
-
- private static final MailboxIdRegistrationKey.Factory FACTORY = new MailboxIdRegistrationKey.Factory(new TestId.Factory());
-
- private static final MailboxIdRegistrationKey MAILBOX_ID_REGISTRATION_KEY = new MailboxIdRegistrationKey((TestId.of(42)));
-
- @Test
- void shouldRespectBeanContract() {
- EqualsVerifier.forClass(MailboxIdRegistrationKey.class)
- .verify();
- }
-
- @Test
- void asStringShouldReturnSerializedMailboxId() {
- assertThat(MAILBOX_ID_REGISTRATION_KEY.asString())
- .isEqualTo(ID);
- }
-
- @Test
- void fromStringShouldReturnCorrespondingRegistrationKey() {
- assertThat(FACTORY.fromString(ID))
- .isEqualTo(MAILBOX_ID_REGISTRATION_KEY);
- }
-
- @Test
- void fromStringShouldThrowOnInvalidValues() {
- assertThatThrownBy(() -> FACTORY.fromString("invalid"))
- .isInstanceOf(IllegalArgumentException.class);
- }
-}
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/events/RetryBackoffConfigurationTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/events/RetryBackoffConfigurationTest.java
deleted file mode 100644
index 0788da9..0000000
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/events/RetryBackoffConfigurationTest.java
+++ /dev/null
@@ -1,141 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.RetryBackoffConfiguration.DEFAULT_FIRST_BACKOFF;
-import static org.apache.james.mailbox.events.RetryBackoffConfiguration.DEFAULT_JITTER_FACTOR;
-import static org.apache.james.mailbox.events.RetryBackoffConfiguration.DEFAULT_MAX_RETRIES;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.time.Duration;
-
-import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-class RetryBackoffConfigurationTest {
-
- @Test
- void shouldMatchBeanContract() {
- EqualsVerifier.forClass(RetryBackoffConfiguration.class)
- .verify();
- }
-
- @Test
- void buildShouldThrowWhenNegativeFirstBackoff() {
- assertThatThrownBy(() -> RetryBackoffConfiguration.builder()
- .maxRetries(DEFAULT_MAX_RETRIES)
- .firstBackoff(Duration.ofMillis(-1000L))
- .jitterFactor(DEFAULT_JITTER_FACTOR)
- .build())
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("firstBackoff is not allowed to be negative");
- }
-
- @Test
- void buildShouldThrowWhenNegativeMaxRetries() {
- assertThatThrownBy(() -> RetryBackoffConfiguration.builder()
- .maxRetries(-6)
- .firstBackoff(DEFAULT_FIRST_BACKOFF)
- .jitterFactor(DEFAULT_JITTER_FACTOR)
- .build())
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("maxRetries is not allowed to be negative");
- }
-
- @Test
- void buildShouldThrowWhenNegativeJitterFactor() {
- assertThatThrownBy(() -> RetryBackoffConfiguration.builder()
- .maxRetries(DEFAULT_MAX_RETRIES)
- .firstBackoff(DEFAULT_FIRST_BACKOFF)
- .jitterFactor(-2.5)
- .build())
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("jitterFactor is not allowed to be negative or greater than 1");
- }
-
- @Test
- void buildShouldThrowWhenGreaterThanOneJitterFactor() {
- assertThatThrownBy(() -> RetryBackoffConfiguration.builder()
- .maxRetries(DEFAULT_MAX_RETRIES)
- .firstBackoff(DEFAULT_FIRST_BACKOFF)
- .jitterFactor(1.000001)
- .build())
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("jitterFactor is not allowed to be negative or greater than 1");
- }
-
- @Test
- void buildShouldSuccessWhenZeroFirstBackoff() {
- RetryBackoffConfiguration retryBackoff = RetryBackoffConfiguration.builder()
- .maxRetries(DEFAULT_MAX_RETRIES)
- .firstBackoff(Duration.ZERO)
- .jitterFactor(DEFAULT_JITTER_FACTOR)
- .build();
-
- assertThat(retryBackoff.getFirstBackoff().toMillis())
- .isEqualTo(0L);
- }
-
- @Test
- void buildShouldSuccessWhenZeroMaxRetries() {
- RetryBackoffConfiguration retryBackoff = RetryBackoffConfiguration.builder()
- .maxRetries(0)
- .firstBackoff(DEFAULT_FIRST_BACKOFF)
- .jitterFactor(DEFAULT_JITTER_FACTOR)
- .build();
-
- assertThat(retryBackoff.getMaxRetries())
- .isEqualTo(0L);
- }
-
- @Test
- void buildShouldSuccessWhenZeroJitterFactor() {
- RetryBackoffConfiguration retryBackoff = RetryBackoffConfiguration.builder()
- .maxRetries(DEFAULT_MAX_RETRIES)
- .firstBackoff(DEFAULT_FIRST_BACKOFF)
- .jitterFactor(0)
- .build();
-
- assertThat(retryBackoff.getJitterFactor())
- .isEqualTo(0);
- }
-
- @Test
- void buildShouldReturnCorrespondingValues() {
- RetryBackoffConfiguration retryBackoff = RetryBackoffConfiguration.builder()
- .maxRetries(5)
- .firstBackoff(Duration.ofMillis(200))
- .jitterFactor(0.6)
- .build();
-
- SoftAssertions.assertSoftly(softly -> {
- softly.assertThat(retryBackoff.getJitterFactor())
- .isEqualTo(0.6);
- softly.assertThat(retryBackoff.getMaxRetries())
- .isEqualTo(5);
- softly.assertThat(retryBackoff.getFirstBackoff())
- .isEqualTo(Duration.ofMillis(200));
- });
- }
-
-}
\ No newline at end of file
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageMovesTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageMovesTest.java
index 8787db5..1710ceb 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageMovesTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MessageMovesTest.java
@@ -19,7 +19,7 @@
package org.apache.james.mailbox.model;
-import org.apache.james.mailbox.events.MessageMoveEvent;
+import org.apache.james.events.MessageMoveEvent;
import org.junit.jupiter.api.Test;
import nl.jqno.equalsverifier.EqualsVerifier;
diff --git a/mailbox/cassandra/pom.xml b/mailbox/cassandra/pom.xml
index 385f0b6..f596178 100644
--- a/mailbox/cassandra/pom.xml
+++ b/mailbox/cassandra/pom.xml
@@ -54,11 +54,6 @@
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
- <artifactId>apache-james-mailbox-event-memory</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>${james.groupId}</groupId>
<artifactId>apache-james-mailbox-store</artifactId>
</dependency>
<dependency>
@@ -89,6 +84,11 @@
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
+ <artifactId>event-bus-in-vm</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
<artifactId>event-sourcing-core</artifactId>
</dependency>
<dependency>
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 728bd81..4b2f084 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
@@ -31,6 +31,8 @@ import org.apache.james.blob.api.BlobStore;
import org.apache.james.events.Event;
import org.apache.james.events.EventListener;
import org.apache.james.events.Group;
+import org.apache.james.events.MailboxEvents.Expunged;
+import org.apache.james.events.MailboxEvents.MailboxDeletion;
import org.apache.james.mailbox.acl.ACLDiff;
import org.apache.james.mailbox.cassandra.ids.CassandraId;
import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
@@ -50,8 +52,6 @@ import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
import org.apache.james.mailbox.cassandra.mail.MessageAttachmentRepresentation;
import org.apache.james.mailbox.cassandra.mail.MessageRepresentation;
-import org.apache.james.mailbox.events.MailboxEvents.Expunged;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
import org.apache.james.mailbox.model.MailboxACL;
import org.apache.james.mailbox.model.MessageMetaData;
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListener.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListener.java
index dcfd070..b48508f 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListener.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/MailboxOperationLoggingListener.java
@@ -26,9 +26,9 @@ import static org.apache.james.mailbox.cassandra.GhostMailbox.TYPE;
import org.apache.james.events.Event;
import org.apache.james.events.EventListener;
import org.apache.james.events.Group;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxRenamed;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
+import org.apache.james.events.MailboxEvents.MailboxDeletion;
+import org.apache.james.events.MailboxEvents.MailboxRenamed;
/**
* See https://issues.apache.org/jira/browse/MAILBOX-322 for reading about the Ghost mailbox bug.
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTest.java
index 88ef7a5..dfd49c7 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTest.java
@@ -20,11 +20,11 @@
package org.apache.james.mailbox.cassandra;
import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.store.AbstractCombinationManagerTest;
import org.apache.james.mailbox.store.CombinationManagerTestSystem;
import org.apache.james.mailbox.store.quota.NoQuotaManager;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
index e497c3f..3d2226c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
@@ -21,6 +21,10 @@ package org.apache.james.mailbox.cassandra;
import org.apache.james.backends.cassandra.CassandraCluster;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.AttachmentContentLoader;
import org.apache.james.mailbox.Authenticator;
import org.apache.james.mailbox.Authorizator;
@@ -34,10 +38,6 @@ import org.apache.james.mailbox.cassandra.quota.CassandraGlobalMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerDomainMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaManager;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.model.MessageId;
import org.apache.james.mailbox.quota.QuotaRootResolver;
import org.apache.james.mailbox.store.MailboxManagerConfiguration;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerStorageTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerStorageTest.java
index d536fd4..2d9179c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerStorageTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMessageIdManagerStorageTest.java
@@ -20,11 +20,11 @@
package org.apache.james.mailbox.cassandra;
import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.extension.PreDeletionHook;
import org.apache.james.mailbox.store.AbstractMessageIdManagerStorageTest;
import org.apache.james.mailbox.store.MessageIdManagerTestSystem;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
index 1b4f270..12c1553 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
@@ -23,6 +23,10 @@ import static org.mockito.Mockito.mock;
import org.apache.james.backends.cassandra.CassandraCluster;
import org.apache.james.events.EventBus;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.AttachmentContentLoader;
import org.apache.james.mailbox.Authenticator;
import org.apache.james.mailbox.Authorizator;
@@ -34,10 +38,6 @@ import org.apache.james.mailbox.cassandra.quota.CassandraGlobalMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerDomainMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaDao;
import org.apache.james.mailbox.cassandra.quota.CassandraPerUserMaxQuotaManager;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.quota.CurrentQuotaManager;
import org.apache.james.mailbox.quota.MaxQuotaManager;
import org.apache.james.mailbox.quota.QuotaManager;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
index d0e2910..05624f3 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
@@ -23,6 +23,10 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.AttachmentContentLoader;
import org.apache.james.mailbox.Authenticator;
import org.apache.james.mailbox.Authorizator;
@@ -33,10 +37,6 @@ import org.apache.james.mailbox.cassandra.CassandraMailboxManager;
import org.apache.james.mailbox.cassandra.CassandraMailboxSessionMapperFactory;
import org.apache.james.mailbox.cassandra.TestCassandraMailboxSessionMapperFactory;
import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.store.AbstractMailboxManagerAttachmentTest;
import org.apache.james.mailbox.store.MailboxManagerConfiguration;
import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
diff --git a/mailbox/elasticsearch/pom.xml b/mailbox/elasticsearch/pom.xml
index 607e814..f4b06b7 100644
--- a/mailbox/elasticsearch/pom.xml
+++ b/mailbox/elasticsearch/pom.xml
@@ -54,11 +54,6 @@
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
- <artifactId>apache-james-mailbox-event-memory</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>${james.groupId}</groupId>
<artifactId>apache-james-mailbox-memory</artifactId>
<scope>test</scope>
</dependency>
@@ -91,6 +86,11 @@
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
+ <artifactId>event-bus-in-vm</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
<artifactId>james-server-testing</artifactId>
<scope>test</scope>
</dependency>
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLetters.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLetters.java
deleted file mode 100644
index 77a1c5e..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLetters.java
+++ /dev/null
@@ -1,89 +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.mailbox.events;
-
-import javax.inject.Inject;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.Group;
-
-import com.google.common.base.Preconditions;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class CassandraEventDeadLetters implements EventDeadLetters {
-
- private final CassandraEventDeadLettersDAO cassandraEventDeadLettersDAO;
- private final CassandraEventDeadLettersGroupDAO cassandraEventDeadLettersGroupDAO;
-
-
- @Inject
- CassandraEventDeadLetters(CassandraEventDeadLettersDAO cassandraEventDeadLettersDAO,
- CassandraEventDeadLettersGroupDAO cassandraEventDeadLettersGroupDAO) {
- this.cassandraEventDeadLettersDAO = cassandraEventDeadLettersDAO;
- this.cassandraEventDeadLettersGroupDAO = cassandraEventDeadLettersGroupDAO;
- }
-
- @Override
- public Mono<InsertionId> store(Group registeredGroup, Event failDeliveredEvent) {
- Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
- Preconditions.checkArgument(failDeliveredEvent != null, FAIL_DELIVERED_EVENT_CANNOT_BE_NULL);
-
- InsertionId insertionId = InsertionId.random();
- return cassandraEventDeadLettersDAO.store(registeredGroup, failDeliveredEvent, insertionId)
- .then(cassandraEventDeadLettersGroupDAO.storeGroup(registeredGroup))
- .thenReturn(insertionId);
- }
-
- @Override
- public Mono<Void> remove(Group registeredGroup, InsertionId failDeliveredInsertionId) {
- Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
- Preconditions.checkArgument(failDeliveredInsertionId != null, FAIL_DELIVERED_ID_INSERTION_CANNOT_BE_NULL);
-
- return cassandraEventDeadLettersDAO.removeEvent(registeredGroup, failDeliveredInsertionId);
- }
-
- @Override
- public Mono<Event> failedEvent(Group registeredGroup, InsertionId failDeliveredInsertionId) {
- Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
- Preconditions.checkArgument(failDeliveredInsertionId != null, FAIL_DELIVERED_ID_INSERTION_CANNOT_BE_NULL);
-
- return cassandraEventDeadLettersDAO.retrieveFailedEvent(registeredGroup, failDeliveredInsertionId);
- }
-
- @Override
- public Flux<InsertionId> failedIds(Group registeredGroup) {
- Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
-
- return cassandraEventDeadLettersDAO.retrieveInsertionIdsWithGroup(registeredGroup);
- }
-
- @Override
- public Flux<Group> groupsWithFailedEvents() {
- return cassandraEventDeadLettersGroupDAO.retrieveAllGroups();
- }
-
- @Override
- public Mono<Boolean> containEvents() {
- return cassandraEventDeadLettersDAO.containEvents();
- }
-}
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAO.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAO.java
deleted file mode 100644
index 0d20d43..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAO.java
+++ /dev/null
@@ -1,132 +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.mailbox.events;
-
-import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.delete;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersTable.EVENT;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersTable.GROUP;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersTable.INSERTION_ID;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersTable.TABLE_NAME;
-
-import javax.inject.Inject;
-
-import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.Group;
-
-import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.Session;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class CassandraEventDeadLettersDAO {
- private final CassandraAsyncExecutor executor;
- private final EventSerializer eventSerializer;
- private final PreparedStatement insertStatement;
- private final PreparedStatement deleteStatement;
- private final PreparedStatement selectEventStatement;
- private final PreparedStatement selectEventIdsWithGroupStatement;
- private final PreparedStatement containEventsStatement;
-
- @Inject
- CassandraEventDeadLettersDAO(Session session, EventSerializer eventSerializer) {
- this.executor = new CassandraAsyncExecutor(session);
- this.eventSerializer = eventSerializer;
- this.insertStatement = prepareInsertStatement(session);
- this.deleteStatement = prepareDeleteStatement(session);
- this.selectEventStatement = prepareSelectEventStatement(session);
- this.selectEventIdsWithGroupStatement = prepareSelectInsertionIdsWithGroupStatement(session);
- this.containEventsStatement = prepareContainEventStatement(session);
- }
-
- private PreparedStatement prepareInsertStatement(Session session) {
- return session.prepare(insertInto(TABLE_NAME)
- .value(GROUP, bindMarker(GROUP))
- .value(INSERTION_ID, bindMarker(INSERTION_ID))
- .value(EVENT, bindMarker(EVENT)));
- }
-
- private PreparedStatement prepareDeleteStatement(Session session) {
- return session.prepare(delete()
- .from(TABLE_NAME)
- .where(eq(GROUP, bindMarker(GROUP)))
- .and(eq(INSERTION_ID, bindMarker(INSERTION_ID))));
- }
-
- private PreparedStatement prepareSelectEventStatement(Session session) {
- return session.prepare(select(EVENT)
- .from(TABLE_NAME)
- .where(eq(GROUP, bindMarker(GROUP)))
- .and(eq(INSERTION_ID, bindMarker(INSERTION_ID))));
- }
-
- private PreparedStatement prepareSelectInsertionIdsWithGroupStatement(Session session) {
- return session.prepare(select(INSERTION_ID)
- .from(TABLE_NAME)
- .where(eq(GROUP, bindMarker(GROUP))));
- }
-
- private PreparedStatement prepareContainEventStatement(Session session) {
- return session.prepare(select(EVENT)
- .from(TABLE_NAME)
- .limit(1));
- }
-
- Mono<Void> store(Group group, Event failedEvent, EventDeadLetters.InsertionId insertionId) {
- return executor.executeVoid(insertStatement.bind()
- .setString(GROUP, group.asString())
- .setUUID(INSERTION_ID, insertionId.getId())
- .setString(EVENT, eventSerializer.toJson(failedEvent)));
- }
-
- Mono<Void> removeEvent(Group group, EventDeadLetters.InsertionId failedInsertionId) {
- return executor.executeVoid(deleteStatement.bind()
- .setString(GROUP, group.asString())
- .setUUID(INSERTION_ID, failedInsertionId.getId()));
- }
-
- Mono<Event> retrieveFailedEvent(Group group, EventDeadLetters.InsertionId insertionId) {
- return executor.executeSingleRow(selectEventStatement.bind()
- .setString(GROUP, group.asString())
- .setUUID(INSERTION_ID, insertionId.getId()))
- .map(row -> deserializeEvent(row.getString(EVENT)));
- }
-
- Flux<EventDeadLetters.InsertionId> retrieveInsertionIdsWithGroup(Group group) {
- return executor.executeRows(selectEventIdsWithGroupStatement.bind()
- .setString(GROUP, group.asString()))
- .map(row -> EventDeadLetters.InsertionId.of(row.getUUID(INSERTION_ID)));
- }
-
- Mono<Boolean> containEvents() {
- return executor.executeReturnExists(containEventsStatement.bind());
- }
-
- private Event deserializeEvent(String serializedEvent) {
- return eventSerializer.fromJson(serializedEvent).get();
- }
-}
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAO.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAO.java
deleted file mode 100644
index 20b283e..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAO.java
+++ /dev/null
@@ -1,71 +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.mailbox.events;
-
-import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
-import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersGroupTable.GROUP;
-import static org.apache.james.mailbox.events.tables.CassandraEventDeadLettersGroupTable.TABLE_NAME;
-
-import javax.inject.Inject;
-
-import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
-import org.apache.james.events.Group;
-
-import com.datastax.driver.core.PreparedStatement;
-import com.datastax.driver.core.Session;
-import com.github.fge.lambdas.Throwing;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class CassandraEventDeadLettersGroupDAO {
- private final CassandraAsyncExecutor executor;
- private final PreparedStatement insertStatement;
- private final PreparedStatement selectAllStatement;
-
- @Inject
- CassandraEventDeadLettersGroupDAO(Session session) {
- this.executor = new CassandraAsyncExecutor(session);
- this.insertStatement = prepareInsertStatement(session);
- this.selectAllStatement = prepareSelectStatement(session);
- }
-
- private PreparedStatement prepareInsertStatement(Session session) {
- return session.prepare(insertInto(TABLE_NAME)
- .value(GROUP, bindMarker(GROUP)));
- }
-
- private PreparedStatement prepareSelectStatement(Session session) {
- return session.prepare(select(GROUP)
- .from(TABLE_NAME));
- }
-
- Mono<Void> storeGroup(Group group) {
- return executor.executeVoid(insertStatement.bind()
- .setString(GROUP, group.asString()));
- }
-
- Flux<Group> retrieveAllGroups() {
- return executor.executeRows(selectAllStatement.bind())
- .map(Throwing.function(row -> Group.deserialize(row.getString(GROUP))));
- }
-}
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersModule.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersModule.java
deleted file mode 100644
index 6c4095c..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/CassandraEventDeadLettersModule.java
+++ /dev/null
@@ -1,46 +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.mailbox.events;
-
-import org.apache.james.backends.cassandra.components.CassandraModule;
-import org.apache.james.backends.cassandra.utils.CassandraConstants;
-import org.apache.james.mailbox.events.tables.CassandraEventDeadLettersGroupTable;
-import org.apache.james.mailbox.events.tables.CassandraEventDeadLettersTable;
-
-import com.datastax.driver.core.DataType;
-import com.datastax.driver.core.schemabuilder.SchemaBuilder;
-
-public interface CassandraEventDeadLettersModule {
- CassandraModule MODULE = CassandraModule.builder()
- .table(CassandraEventDeadLettersTable.TABLE_NAME)
- .comment("Holds event dead letter")
- .options(options -> options
- .caching(SchemaBuilder.KeyCaching.ALL,
- SchemaBuilder.rows(CassandraConstants.DEFAULT_CACHED_ROW_PER_PARTITION)))
- .statement(statement -> statement
- .addPartitionKey(CassandraEventDeadLettersTable.GROUP, DataType.text())
- .addClusteringColumn(CassandraEventDeadLettersTable.INSERTION_ID, DataType.uuid())
- .addColumn(CassandraEventDeadLettersTable.EVENT, DataType.text()))
- .table(CassandraEventDeadLettersGroupTable.TABLE_NAME)
- .comment("Projection table for retrieving groups for all failed events")
- .statement(statement -> statement
- .addPartitionKey(CassandraEventDeadLettersGroupTable.GROUP, DataType.text()))
- .build();
-}
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersGroupTable.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersGroupTable.java
deleted file mode 100644
index b1d6219..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersGroupTable.java
+++ /dev/null
@@ -1,27 +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.mailbox.events.tables;
-
-public interface CassandraEventDeadLettersGroupTable {
-
- String TABLE_NAME = "group_table";
-
- String GROUP = "group";
-}
diff --git a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersTable.java b/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersTable.java
deleted file mode 100644
index cbf272c..0000000
--- a/mailbox/event/event-cassandra/src/main/java/org/apache/james/mailbox/events/tables/CassandraEventDeadLettersTable.java
+++ /dev/null
@@ -1,29 +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.mailbox.events.tables;
-
-public interface CassandraEventDeadLettersTable {
-
- String TABLE_NAME = "event_dead_letters";
-
- String GROUP = "group";
- String INSERTION_ID = "insertionId";
- String EVENT = "event";
-}
diff --git a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAOTest.java b/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAOTest.java
deleted file mode 100644
index 35ab39f..0000000
--- a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersDAOTest.java
+++ /dev/null
@@ -1,145 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventDeadLettersContract.EVENT_1;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.EVENT_2;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.EVENT_3;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.GROUP_A;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.GROUP_B;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.INSERTION_ID_1;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.INSERTION_ID_2;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.INSERTION_ID_3;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-class CassandraEventDeadLettersDAOTest {
-
- @RegisterExtension
- static CassandraClusterExtension cassandraClusterExtension = new CassandraClusterExtension(CassandraEventDeadLettersModule.MODULE);
-
- private CassandraEventDeadLettersDAO cassandraEventDeadLettersDAO;
-
- @BeforeEach
- void setUp(CassandraCluster cassandraCluster) {
- EventSerializer eventSerializer = new EventSerializer(new TestId.Factory(), new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
- cassandraEventDeadLettersDAO = new CassandraEventDeadLettersDAO(cassandraCluster.getConf(), eventSerializer);
- }
-
- @Test
- void removeEventShouldSucceededWhenRemoveStoredEvent() {
- cassandraEventDeadLettersDAO.store(GROUP_A, EVENT_1, INSERTION_ID_1).block();
-
- cassandraEventDeadLettersDAO.removeEvent(GROUP_A, INSERTION_ID_1).block();
-
- assertThat(cassandraEventDeadLettersDAO
- .retrieveInsertionIdsWithGroup(GROUP_A)
- .collectList().block())
- .isEmpty();
- }
-
- @Test
- void retrieveFailedEventShouldReturnEmptyWhenDefault() {
- assertThat(cassandraEventDeadLettersDAO
- .retrieveFailedEvent(GROUP_A, INSERTION_ID_1)
- .blockOptional().isPresent())
- .isFalse();
- }
-
- @Test
- void retrieveFailedEventShouldReturnStoredEvent() {
- cassandraEventDeadLettersDAO.store(GROUP_A, EVENT_1, INSERTION_ID_1).block();
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_2, INSERTION_ID_2).block();
-
- assertThat(cassandraEventDeadLettersDAO
- .retrieveFailedEvent(GROUP_B, INSERTION_ID_2)
- .blockOptional().get())
- .isEqualTo(EVENT_2);
- }
-
- @Test
- void retrieveInsertionIdsWithGroupShouldReturnEmptyWhenDefault() {
- assertThat(cassandraEventDeadLettersDAO
- .retrieveInsertionIdsWithGroup(GROUP_A)
- .collectList().block())
- .isEmpty();
- }
-
- @Test
- void retrieveInsertionIdsWithGroupShouldReturnStoredInsertionId() {
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_1).block();
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_2, INSERTION_ID_2).block();
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_3, INSERTION_ID_3).block();
-
- assertThat(cassandraEventDeadLettersDAO
- .retrieveInsertionIdsWithGroup(GROUP_B)
- .collectList().block())
- .containsOnly(INSERTION_ID_1, INSERTION_ID_2, INSERTION_ID_3);
- }
-
- @Test
- void shouldReturnTrueWhenEventStored() {
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_1).block();
- assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
- }
-
- @Test
- void shouldReturnTrueWhenNoEventStored() {
- assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isFalse();
- }
-
- @Test
- void shouldReturnTrueWhenEventsStoredAndRemovedSome() {
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_1).block();
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_2).block();
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_3).block();
-
- assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
-
- cassandraEventDeadLettersDAO.removeEvent(GROUP_B, INSERTION_ID_3).block();
-
- assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
- }
-
- @Test
- void shouldReturnFalseWhenRemovedAllEventsStored() {
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_1).block();
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_2).block();
- cassandraEventDeadLettersDAO.store(GROUP_B, EVENT_1, INSERTION_ID_3).block();
-
- assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isTrue();
-
- cassandraEventDeadLettersDAO.removeEvent(GROUP_B, INSERTION_ID_3).block();
- cassandraEventDeadLettersDAO.removeEvent(GROUP_B, INSERTION_ID_2).block();
- cassandraEventDeadLettersDAO.removeEvent(GROUP_B, INSERTION_ID_1).block();
-
- assertThat(cassandraEventDeadLettersDAO.containEvents().block()).isFalse();
- }
-
-}
diff --git a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAOTest.java b/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAOTest.java
deleted file mode 100644
index c5bc092..0000000
--- a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersGroupDAOTest.java
+++ /dev/null
@@ -1,60 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventDeadLettersContract.GROUP_A;
-import static org.apache.james.mailbox.events.EventDeadLettersContract.GROUP_B;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-public class CassandraEventDeadLettersGroupDAOTest {
-
- @RegisterExtension
- static CassandraClusterExtension cassandraClusterExtension = new CassandraClusterExtension(CassandraEventDeadLettersModule.MODULE);
-
- private static CassandraEventDeadLettersGroupDAO GROUP_DAO;
-
- @BeforeAll
- static void setUp(CassandraCluster cassandraCluster) {
- GROUP_DAO = new CassandraEventDeadLettersGroupDAO(cassandraCluster.getConf());
- }
-
- @Test
- void retrieveAllGroupsShouldReturnEmptyWhenDefault() {
- assertThat(GROUP_DAO.retrieveAllGroups()
- .collectList().block())
- .isEmpty();
- }
-
- @Test
- void retrieveAllGroupsShouldReturnStoredGroups() {
- GROUP_DAO.storeGroup(GROUP_A).block();
- GROUP_DAO.storeGroup(GROUP_B).block();
-
- assertThat(GROUP_DAO.retrieveAllGroups()
- .collectList().block())
- .containsOnly(GROUP_A, GROUP_B);
- }
-}
diff --git a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersHealthCheckTest.java b/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersHealthCheckTest.java
deleted file mode 100644
index 027ad73..0000000
--- a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersHealthCheckTest.java
+++ /dev/null
@@ -1,70 +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.mailbox.events;
-
-import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.backends.cassandra.DockerCassandra;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventDeadLettersHealthCheck;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-
-class CassandraEventDeadLettersHealthCheckTest implements EventDeadLettersHealthCheckContract {
- @RegisterExtension
- static CassandraClusterExtension cassandraClusterExtension = new CassandraClusterExtension(CassandraEventDeadLettersModule.MODULE);
- private EventDeadLettersHealthCheck testee;
- private CassandraEventDeadLetters eventDeadLetters;
- private DockerCassandra dockerCassandra;
-
- @BeforeEach
- void setUp(CassandraCluster cassandraCluster, DockerCassandra dockerCassandra) {
- EventSerializer eventSerializer = new EventSerializer(new TestId.Factory(), new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
- eventDeadLetters = new CassandraEventDeadLetters(new CassandraEventDeadLettersDAO(cassandraCluster.getConf(), eventSerializer),
- new CassandraEventDeadLettersGroupDAO(cassandraCluster.getConf()));
- testee = new EventDeadLettersHealthCheck(eventDeadLetters);
- this.dockerCassandra = dockerCassandra;
- }
-
- @Override
- public EventDeadLettersHealthCheck testee() {
- return testee;
- }
-
- @Override
- public EventDeadLetters eventDeadLetters() {
- return eventDeadLetters;
- }
-
- @Override
- public void createErrorWhenDoingHealthCheck() {
- dockerCassandra.pause();
- }
-
- @Override
- public void resolveErrorWhenDoingHealthCheck() {
- dockerCassandra.unpause();
- }
-}
diff --git a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersTest.java b/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersTest.java
deleted file mode 100644
index 7d81bcd..0000000
--- a/mailbox/event/event-cassandra/src/test/java/org/apache/james/mailbox/events/CassandraEventDeadLettersTest.java
+++ /dev/null
@@ -1,50 +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.mailbox.events;
-
-import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-class CassandraEventDeadLettersTest implements EventDeadLettersContract.AllContracts {
-
- @RegisterExtension
- static CassandraClusterExtension cassandraClusterExtension = new CassandraClusterExtension(CassandraEventDeadLettersModule.MODULE);
-
- private CassandraEventDeadLetters eventDeadLetters;
-
- @BeforeEach
- void setUp(CassandraCluster cassandraCluster) {
- EventSerializer eventSerializer = new EventSerializer(new TestId.Factory(), new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
- eventDeadLetters = new CassandraEventDeadLetters(new CassandraEventDeadLettersDAO(cassandraCluster.getConf(), eventSerializer),
- new CassandraEventDeadLettersGroupDAO(cassandraCluster.getConf()));
- }
-
- @Override
- public EventDeadLetters eventDeadLetters() {
- return eventDeadLetters;
- }
-}
diff --git a/mailbox/event/event-memory/pom.xml b/mailbox/event/event-memory/pom.xml
deleted file mode 100644
index e421778..0000000
--- a/mailbox/event/event-memory/pom.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.james</groupId>
- <artifactId>apache-james-mailbox</artifactId>
- <version>3.6.0-SNAPSHOT</version>
- <relativePath>../../pom.xml</relativePath>
- </parent>
-
- <artifactId>apache-james-mailbox-event-memory</artifactId>
- <name>Apache James :: Mailbox :: Event :: In VM implementation</name>
- <description>In VM implementation for the eventbus API</description>
-
- <dependencies>
- <dependency>
- <groupId>${james.groupId}</groupId>
- <artifactId>metrics-tests</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>${james.groupId}</groupId>
- <artifactId>testing-base</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>apache-james-mailbox-api</artifactId>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>apache-james-mailbox-api</artifactId>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>james-server-util</artifactId>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>metrics-api</artifactId>
- </dependency>
- <dependency>
- <groupId>io.projectreactor</groupId>
- <artifactId>reactor-core</artifactId>
- </dependency>
- <dependency>
- <groupId>org.awaitility</groupId>
- <artifactId>awaitility</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-core</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
-</project>
diff --git a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/InVMEventBus.java b/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/InVMEventBus.java
deleted file mode 100644
index 1e92333..0000000
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/InVMEventBus.java
+++ /dev/null
@@ -1,134 +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.mailbox.events;
-
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.inject.Inject;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.GroupAlreadyRegistered;
-import org.apache.james.events.GroupRegistrationNotFound;
-import org.apache.james.events.Registration;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.mailbox.events.delivery.EventDelivery;
-import org.apache.james.mailbox.events.delivery.EventDelivery.PermanentFailureHandler.StoreToDeadLetters;
-import org.apache.james.mailbox.events.delivery.EventDelivery.Retryer.BackoffRetryer;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class InVMEventBus implements EventBus {
-
- private final Multimap<RegistrationKey, EventListener.ReactiveEventListener> registrations;
- private final ConcurrentHashMap<Group, EventListener.ReactiveEventListener> groups;
- private final EventDelivery eventDelivery;
- private final RetryBackoffConfiguration retryBackoff;
- private final EventDeadLetters eventDeadLetters;
-
- @Inject
- public InVMEventBus(EventDelivery eventDelivery, RetryBackoffConfiguration retryBackoff, EventDeadLetters eventDeadLetters) {
- this.eventDelivery = eventDelivery;
- this.retryBackoff = retryBackoff;
- this.eventDeadLetters = eventDeadLetters;
- this.registrations = Multimaps.synchronizedSetMultimap(HashMultimap.create());
- this.groups = new ConcurrentHashMap<>();
- }
-
- @Override
- public Mono<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key) {
- registrations.put(key, listener);
- return Mono.just(() -> registrations.remove(key, listener));
- }
-
- @Override
- public Registration register(EventListener.ReactiveEventListener listener, Group group) {
- EventListener previous = groups.putIfAbsent(group, listener);
- if (previous == null) {
- return () -> groups.remove(group, listener);
- }
- throw new GroupAlreadyRegistered(group);
- }
-
- @Override
- public Mono<Void> dispatch(Event event, Set<RegistrationKey> keys) {
- if (!event.isNoop()) {
- return Flux.merge(groupDeliveries(event), keyDeliveries(event, keys))
- .then()
- .onErrorResume(throwable -> Mono.empty());
- }
- return Mono.empty();
- }
-
- @Override
- public Mono<Void> reDeliver(Group group, Event event) {
- if (!event.isNoop()) {
- return groupDelivery(event, retrieveListenerFromGroup(group), group);
- }
- return Mono.empty();
- }
-
- private EventListener.ReactiveEventListener retrieveListenerFromGroup(Group group) {
- return Optional.ofNullable(groups.get(group))
- .orElseThrow(() -> new GroupRegistrationNotFound(group));
- }
-
- private Mono<Void> keyDeliveries(Event event, Set<RegistrationKey> keys) {
- return Flux.fromIterable(registeredListenersByKeys(keys))
- .flatMap(listener -> eventDelivery.deliver(listener, event, EventDelivery.DeliveryOption.none()), EventBus.EXECUTION_RATE)
- .then();
- }
-
- private Mono<Void> groupDeliveries(Event event) {
- return Flux.fromIterable(groups.entrySet())
- .flatMap(entry -> groupDelivery(event, entry.getValue(), entry.getKey()), EventBus.EXECUTION_RATE)
- .then();
- }
-
- private Mono<Void> groupDelivery(Event event, EventListener.ReactiveEventListener mailboxListener, Group group) {
- return eventDelivery.deliver(
- mailboxListener,
- event,
- EventDelivery.DeliveryOption.of(
- BackoffRetryer.of(retryBackoff, mailboxListener),
- StoreToDeadLetters.of(group, eventDeadLetters)));
- }
-
- public Set<Group> registeredGroups() {
- return groups.keySet();
- }
-
- private Set<EventListener.ReactiveEventListener> registeredListenersByKeys(Set<RegistrationKey> keys) {
- return keys.stream()
- .flatMap(registrationKey -> registrations.get(registrationKey).stream())
- .collect(Guavate.toImmutableSet());
- }
-}
diff --git a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/MemoryEventDeadLetters.java b/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/MemoryEventDeadLetters.java
deleted file mode 100644
index b11e26f..0000000
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/MemoryEventDeadLetters.java
+++ /dev/null
@@ -1,95 +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.mailbox.events;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.Group;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.HashBasedTable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Table;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class MemoryEventDeadLetters implements EventDeadLetters {
-
- private final Table<Group, InsertionId, Event> deadLetters;
-
- public MemoryEventDeadLetters() {
- this.deadLetters = HashBasedTable.create();
- }
-
- @Override
- public Mono<InsertionId> store(Group registeredGroup, Event failDeliveredEvent) {
- Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
- Preconditions.checkArgument(failDeliveredEvent != null, FAIL_DELIVERED_EVENT_CANNOT_BE_NULL);
-
- InsertionId insertionId = InsertionId.random();
- synchronized (deadLetters) {
- deadLetters.put(registeredGroup, insertionId, failDeliveredEvent);
- return Mono.just(insertionId);
- }
- }
-
- @Override
- public Mono<Void> remove(Group registeredGroup, InsertionId failDeliveredInsertionId) {
- Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
- Preconditions.checkArgument(failDeliveredInsertionId != null, FAIL_DELIVERED_ID_INSERTION_CANNOT_BE_NULL);
-
- synchronized (deadLetters) {
- deadLetters.remove(registeredGroup, failDeliveredInsertionId);
- return Mono.empty();
- }
- }
-
- @Override
- public Mono<Event> failedEvent(Group registeredGroup, InsertionId failDeliveredInsertionId) {
- Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
- Preconditions.checkArgument(failDeliveredInsertionId != null, FAIL_DELIVERED_ID_INSERTION_CANNOT_BE_NULL);
-
- synchronized (deadLetters) {
- return Mono.justOrEmpty(deadLetters.get(registeredGroup, failDeliveredInsertionId));
- }
- }
-
- @Override
- public Flux<InsertionId> failedIds(Group registeredGroup) {
- Preconditions.checkArgument(registeredGroup != null, REGISTERED_GROUP_CANNOT_BE_NULL);
-
- synchronized (deadLetters) {
- return Flux.fromIterable(ImmutableList.copyOf(deadLetters.row(registeredGroup).keySet()));
- }
- }
-
- @Override
- public Flux<Group> groupsWithFailedEvents() {
- synchronized (deadLetters) {
- return Flux.fromIterable(ImmutableList.copyOf(deadLetters.rowKeySet()));
- }
- }
-
- @Override
- public Mono<Boolean> containEvents() {
- return Mono.just(!deadLetters.isEmpty());
- }
-}
diff --git a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/EventDelivery.java b/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/EventDelivery.java
deleted file mode 100644
index c0038ca..0000000
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/EventDelivery.java
+++ /dev/null
@@ -1,134 +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.mailbox.events.delivery;
-
-import static org.apache.james.mailbox.events.delivery.EventDelivery.PermanentFailureHandler.NO_HANDLER;
-import static org.apache.james.mailbox.events.delivery.EventDelivery.Retryer.NO_RETRYER;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.mailbox.events.RetryBackoffConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-import reactor.util.retry.Retry;
-
-public interface EventDelivery {
-
- class DeliveryOption {
- public static DeliveryOption of(Retryer retrier, PermanentFailureHandler permanentFailureHandler) {
- return new DeliveryOption(retrier, permanentFailureHandler);
- }
-
- public static DeliveryOption none() {
- return new DeliveryOption(NO_RETRYER, NO_HANDLER);
- }
-
- private final Retryer retrier;
- private final PermanentFailureHandler permanentFailureHandler;
-
- private DeliveryOption(Retryer retrier, PermanentFailureHandler permanentFailureHandler) {
- this.retrier = retrier;
- this.permanentFailureHandler = permanentFailureHandler;
- }
-
- Retryer getRetrier() {
- return retrier;
- }
-
- PermanentFailureHandler getPermanentFailureHandler() {
- return permanentFailureHandler;
- }
- }
-
-
- interface Retryer {
-
- Retryer NO_RETRYER = (executionResult, event) -> executionResult;
-
- class BackoffRetryer implements EventDelivery.Retryer {
-
- public static BackoffRetryer of(RetryBackoffConfiguration retryBackoff, EventListener mailboxListener) {
- return new BackoffRetryer(retryBackoff, mailboxListener);
- }
-
- private static final Logger LOGGER = LoggerFactory.getLogger(BackoffRetryer.class);
-
- private final RetryBackoffConfiguration retryBackoff;
- private final EventListener mailboxListener;
-
- public BackoffRetryer(RetryBackoffConfiguration retryBackoff, EventListener mailboxListener) {
- this.retryBackoff = retryBackoff;
- this.mailboxListener = mailboxListener;
- }
-
- @Override
- public Mono<Void> doRetry(Mono<Void> executionResult, Event event) {
- return executionResult
- .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()).scheduler(Schedulers.elastic()))
- .doOnError(throwable -> LOGGER.error("listener {} exceeded maximum retry({}) to handle event {}",
- mailboxListener.getClass().getCanonicalName(),
- retryBackoff.getMaxRetries(),
- event.getClass().getCanonicalName(),
- throwable))
- .then();
- }
- }
-
- Mono<Void> doRetry(Mono<Void> executionResult, Event event);
- }
-
- interface PermanentFailureHandler {
-
- PermanentFailureHandler NO_HANDLER = event -> Mono.error(new UnsupportedOperationException("doesn't handle error"));
-
- class StoreToDeadLetters implements EventDelivery.PermanentFailureHandler {
-
- public static StoreToDeadLetters of(Group group, EventDeadLetters eventDeadLetters) {
- return new StoreToDeadLetters(group, eventDeadLetters);
- }
-
- private final Group group;
- private final EventDeadLetters eventDeadLetters;
-
- private StoreToDeadLetters(Group group, EventDeadLetters eventDeadLetters) {
- this.group = group;
- this.eventDeadLetters = eventDeadLetters;
- }
-
- @Override
- public Mono<Void> handle(Event event) {
- return eventDeadLetters.store(group, event).then();
- }
- }
-
- Mono<Void> handle(Event event);
- }
-
- Mono<Void> deliver(EventListener.ReactiveEventListener listener, Event event, DeliveryOption option);
-
- default Mono<Void> deliver(EventListener listener, Event event, DeliveryOption option) {
- return deliver(EventListener.wrapReactive(listener), event, option);
- }
-}
diff --git a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/InVmEventDelivery.java b/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/InVmEventDelivery.java
deleted file mode 100644
index e8ed94c..0000000
--- a/mailbox/event/event-memory/src/main/java/org/apache/james/mailbox/events/delivery/InVmEventDelivery.java
+++ /dev/null
@@ -1,104 +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.mailbox.events.delivery;
-
-import static org.apache.james.events.EventBus.Metrics.timerName;
-import static org.apache.james.util.ReactorUtils.context;
-
-import javax.inject.Inject;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventListener;
-import org.apache.james.metrics.api.MetricFactory;
-import org.apache.james.util.MDCBuilder;
-import org.apache.james.util.MDCStructuredLogger;
-import org.apache.james.util.StructuredLogger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-
-public class InVmEventDelivery implements EventDelivery {
- private static final Logger LOGGER = LoggerFactory.getLogger(InVmEventDelivery.class);
-
- private final MetricFactory metricFactory;
-
- @Inject
- @VisibleForTesting
- public InVmEventDelivery(MetricFactory metricFactory) {
- this.metricFactory = metricFactory;
- }
-
- @Override
- public Mono<Void> deliver(EventListener.ReactiveEventListener listener, Event event, DeliveryOption option) {
- Mono<Void> executionResult = deliverByOption(listener, event, option);
-
- return waitForResultIfNeeded(listener.getExecutionMode(), executionResult);
- }
-
- private Mono<Void> waitForResultIfNeeded(EventListener.ExecutionMode executionMode, Mono<Void> executionResult) {
- if (executionMode.equals(EventListener.ExecutionMode.SYNCHRONOUS)) {
- return executionResult;
- }
- return Flux.merge(executionResult, Mono.empty())
- .publishNext()
- .onErrorResume(throwable -> Mono.empty());
- }
-
- private Mono<Void> deliverByOption(EventListener.ReactiveEventListener listener, Event event, DeliveryOption deliveryOption) {
- Mono<Void> deliveryToListener = doDeliverToListener(listener, event)
- .doOnError(throwable -> structuredLogger(event, listener)
- .log(logger -> logger.error("Error while processing listener", throwable)))
- .then();
-
- return deliveryOption.getRetrier().doRetry(deliveryToListener, event)
- .onErrorResume(throwable -> deliveryOption.getPermanentFailureHandler().handle(event))
- .then();
- }
-
- private Mono<Void> doDeliverToListener(EventListener.ReactiveEventListener mailboxListener, Event event) {
- if (mailboxListener.isHandling(event)) {
- return Mono.defer(() -> Mono.from(metricFactory.decoratePublisherWithTimerMetric(timerName(mailboxListener),
- mailboxListener.reactiveEvent(event))))
- .subscriberContext(context("deliver", buildMDC(mailboxListener, event)));
- }
- return Mono.empty();
- }
-
- private MDCBuilder buildMDC(EventListener mailboxListener, Event event) {
- return MDCBuilder.create()
- .addContext(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
- .addContext(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
- .addContext(EventBus.StructuredLoggingFields.USER, event.getUsername())
- .addContext(EventBus.StructuredLoggingFields.LISTENER_CLASS, mailboxListener.getClass());
- }
-
- private StructuredLogger structuredLogger(Event event, EventListener mailboxListener) {
- return MDCStructuredLogger.forLogger(LOGGER)
- .addField(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
- .addField(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
- .addField(EventBus.StructuredLoggingFields.USER, event.getUsername())
- .addField(EventBus.StructuredLoggingFields.LISTENER_CLASS, mailboxListener.getClass());
- }
-}
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/InVMEventBusTest.java b/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/InVMEventBusTest.java
deleted file mode 100644
index c12963f..0000000
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/InVMEventBusTest.java
+++ /dev/null
@@ -1,55 +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.mailbox.events;
-
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
-import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.junit.jupiter.api.BeforeEach;
-
-public class InVMEventBusTest implements KeyContract.SingleEventBusKeyContract, GroupContract.SingleEventBusGroupContract,
- ErrorHandlingContract {
-
- private InVMEventBus eventBus;
- private MemoryEventDeadLetters deadLetters;
-
- @BeforeEach
- void setUp() {
- deadLetters = new MemoryEventDeadLetters();
- eventBus = new InVMEventBus(
- new InVmEventDelivery(new RecordingMetricFactory()), EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION, deadLetters);
- }
-
- @Override
- public EnvironmentSpeedProfile getSpeedProfile() {
- return EnvironmentSpeedProfile.FAST;
- }
-
- @Override
- public EventBus eventBus() {
- return eventBus;
- }
-
- @Override
- public EventDeadLetters deadLetter() {
- return deadLetters;
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersHealthCheckTest.java b/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersHealthCheckTest.java
deleted file mode 100644
index 58c4e7e..0000000
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersHealthCheckTest.java
+++ /dev/null
@@ -1,59 +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.mailbox.events;
-
-import org.apache.commons.lang3.NotImplementedException;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventDeadLettersHealthCheck;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-
-public class MemoryEventDeadLettersHealthCheckTest implements EventDeadLettersHealthCheckContract {
-
- private MemoryEventDeadLetters eventDeadLetters = new MemoryEventDeadLetters();
- private EventDeadLettersHealthCheck testee = new EventDeadLettersHealthCheck(eventDeadLetters);
-
- @Override
- public EventDeadLettersHealthCheck testee() {
- return testee;
- }
-
- @Override
- public EventDeadLetters eventDeadLetters() {
- return eventDeadLetters;
- }
-
- @Override
- public void createErrorWhenDoingHealthCheck() {
- throw new NotImplementedException("We can not instrument implementation this test case.");
- }
-
- @Override
- public void resolveErrorWhenDoingHealthCheck() {
- throw new NotImplementedException("We can not instrument implementation this test case.");
- }
-
- @Override
- @Test
- @Disabled("Unable to trigger the EventDeadLetter error with memory version")
- public void checkShouldReturnUnHealthyWhenEventDeadLetterError() {
-
- }
-}
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersTest.java b/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersTest.java
deleted file mode 100644
index 43ae3df..0000000
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/MemoryEventDeadLettersTest.java
+++ /dev/null
@@ -1,38 +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.mailbox.events;
-
-import org.apache.james.events.EventDeadLetters;
-import org.junit.jupiter.api.BeforeEach;
-
-class MemoryEventDeadLettersTest implements EventDeadLettersContract.AllContracts {
-
- private MemoryEventDeadLetters eventDeadLetters;
-
- @BeforeEach
- void setUp() {
- eventDeadLetters = new MemoryEventDeadLetters();
- }
-
- @Override
- public EventDeadLetters eventDeadLetters() {
- return eventDeadLetters;
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/delivery/InVmEventDeliveryTest.java b/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/delivery/InVmEventDeliveryTest.java
deleted file mode 100644
index 72f779a..0000000
--- a/mailbox/event/event-memory/src/test/java/org/apache/james/mailbox/events/delivery/InVmEventDeliveryTest.java
+++ /dev/null
@@ -1,253 +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.mailbox.events.delivery;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EventListenerCountingSuccessfulExecution;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_A;
-import static org.apache.james.mailbox.events.delivery.EventDelivery.Retryer;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import java.time.Duration;
-
-import org.apache.james.events.EventListener;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.RetryBackoffConfiguration;
-import org.apache.james.mailbox.events.delivery.EventDelivery.DeliveryOption;
-import org.apache.james.mailbox.events.delivery.EventDelivery.PermanentFailureHandler;
-import org.apache.james.mailbox.events.delivery.EventDelivery.Retryer.BackoffRetryer;
-import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-class InVmEventDeliveryTest {
- private InVmEventDelivery inVmEventDelivery;
- private EventListenerCountingSuccessfulExecution listener;
-
- @BeforeEach
- void setUp() {
- listener = newListener();
- inVmEventDelivery = new InVmEventDelivery(new RecordingMetricFactory());
- }
-
- EventListenerCountingSuccessfulExecution newListener() {
- return spy(new EventListenerCountingSuccessfulExecution());
- }
-
- @Nested
- class SynchronousListener {
-
- @Test
- void deliverShouldDeliverEvent() {
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
- inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
- .block();
-
- assertThat(listener.numberOfEventCalls())
- .isEqualTo(1);
- }
-
- @Test
- void deliverShouldReturnSuccessSynchronousMono() {
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
- assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
- .block())
- .doesNotThrowAnyException();
- }
-
- @Test
- void deliverShouldNotDeliverWhenListenerGetException() {
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
- doThrow(new RuntimeException())
- .when(listener).event(EVENT);
-
- assertThatThrownBy(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
- .block())
- .isInstanceOf(RuntimeException.class);
-
- assertThat(listener.numberOfEventCalls())
- .isEqualTo(0);
- }
-
- @Test
- void deliverShouldReturnAnErrorMonoWhenListenerGetException() {
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.SYNCHRONOUS);
- doThrow(new RuntimeException())
- .when(listener).event(EVENT);
-
- assertThatThrownBy(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
- .block())
- .isInstanceOf(RuntimeException.class);
- }
- }
-
- @Nested
- class AsynchronousListener {
-
- @Test
- void deliverShouldDeliverEvent() {
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
- inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
- .block();
-
- assertThat(listener.numberOfEventCalls())
- .isEqualTo(1);
- }
-
- @Test
- void deliverShouldReturnSuccessSynchronousMono() {
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
- assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
- .block())
- .doesNotThrowAnyException();
- }
-
- @Test
- void deliverShouldNotFailWhenListenerGetException() {
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
- doThrow(new RuntimeException())
- .when(listener).event(EVENT);
-
- assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
- .block())
- .doesNotThrowAnyException();
- }
-
- @Test
- void deliverShouldReturnAnSuccessSyncMonoWhenListenerGetException() {
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
- doThrow(new RuntimeException())
- .when(listener).event(EVENT);
-
- assertThatCode(() -> inVmEventDelivery.deliver(listener, EVENT, DeliveryOption.none())
- .block())
- .doesNotThrowAnyException();
- }
- }
-
- @Nested
- class WithOptions {
-
- @Test
- void retryShouldWorkWhenDeliverWithRetry() {
- EventListenerCountingSuccessfulExecution listener = newListener();
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(listener).event(EVENT);
-
- inVmEventDelivery.deliver(listener, EVENT,
- DeliveryOption.of(
- BackoffRetryer.of(RetryBackoffConfiguration.DEFAULT, listener),
- PermanentFailureHandler.NO_HANDLER))
- .block();
-
- assertThat(listener.numberOfEventCalls())
- .isEqualTo(1);
- }
-
- @Test
- void failureHandlerShouldWorkWhenDeliverWithFailureHandler() {
- EventListenerCountingSuccessfulExecution listener = newListener();
- doThrow(new RuntimeException())
- .when(listener).event(EVENT);
-
- MemoryEventDeadLetters deadLetter = new MemoryEventDeadLetters();
-
- inVmEventDelivery.deliver(listener, EVENT,
- DeliveryOption.of(
- Retryer.NO_RETRYER,
- PermanentFailureHandler.StoreToDeadLetters.of(GROUP_A, deadLetter)))
- .block();
-
- assertThat(deadLetter.groupsWithFailedEvents().toStream())
- .containsOnly(GROUP_A);
- }
-
- @Test
- void failureHandlerShouldNotWorkWhenRetrySuccess() {
- EventListenerCountingSuccessfulExecution listener = newListener();
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(listener).event(EVENT);
-
- MemoryEventDeadLetters deadLetter = new MemoryEventDeadLetters();
-
- inVmEventDelivery.deliver(listener, EVENT,
- DeliveryOption.of(
- BackoffRetryer.of(RetryBackoffConfiguration.DEFAULT, listener),
- PermanentFailureHandler.StoreToDeadLetters.of(GROUP_A, deadLetter)))
- .block();
-
- SoftAssertions.assertSoftly(softy -> {
- softy.assertThat(listener.numberOfEventCalls())
- .isEqualTo(1);
- softy.assertThat(deadLetter.groupsWithFailedEvents().toStream())
- .isEmpty();
- });
- }
-
-
- @Test
- void failureHandlerShouldWorkWhenRetryFails() {
- EventListenerCountingSuccessfulExecution listener = newListener();
- //do throw RetryBackoffConfiguration.DEFAULT.DEFAULT_MAX_RETRIES + 1 times
- doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doThrow(new RuntimeException())
- .doCallRealMethod()
- .when(listener).event(EVENT);
-
- MemoryEventDeadLetters deadLetter = new MemoryEventDeadLetters();
-
- inVmEventDelivery.deliver(listener, EVENT,
- DeliveryOption.of(
- BackoffRetryer.of(RetryBackoffConfiguration.builder()
- .maxRetries(8)
- .firstBackoff(Duration.ofMillis(1))
- .jitterFactor(0.2)
- .build(), listener),
- PermanentFailureHandler.StoreToDeadLetters.of(GROUP_A, deadLetter)))
- .block();
-
- SoftAssertions.assertSoftly(softy -> {
- softy.assertThat(listener.numberOfEventCalls())
- .isEqualTo(0);
- assertThat(deadLetter.groupsWithFailedEvents().toStream())
- .containsOnly(GROUP_A);
- });
- }
- }
-}
diff --git a/mailbox/event/event-rabbitmq/pom.xml b/mailbox/event/event-rabbitmq/pom.xml
index 693abc4..cdb79b3 100644
--- a/mailbox/event/event-rabbitmq/pom.xml
+++ b/mailbox/event/event-rabbitmq/pom.xml
@@ -34,11 +34,6 @@
<dependencies>
<dependency>
<groupId>${james.groupId}</groupId>
- <artifactId>apache-james-mailbox-event-memory</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>${james.groupId}</groupId>
<artifactId>apache-james-mailbox-store</artifactId>
<scope>test</scope>
</dependency>
@@ -86,6 +81,11 @@
<artifactId>apache-james-mailbox-event-json</artifactId>
</dependency>
<dependency>
+ <groupId>${james.groupId}</groupId>
+ <artifactId>event-bus-in-vm</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>${project.groupId}</groupId>
<artifactId>metrics-api</artifactId>
</dependency>
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventBusId.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventBusId.java
deleted file mode 100644
index eb6c812..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventBusId.java
+++ /dev/null
@@ -1,72 +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.mailbox.events;
-
-import java.util.Objects;
-import java.util.UUID;
-
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
-
-public class EventBusId {
- public static EventBusId of(UUID uuid) {
- return new EventBusId(uuid);
- }
-
- public static EventBusId random() {
- return new EventBusId(UUID.randomUUID());
- }
-
- public static EventBusId of(String serialized) {
- return new EventBusId(UUID.fromString(serialized));
- }
-
- private final UUID id;
-
- private EventBusId(UUID id) {
- Preconditions.checkNotNull(id);
- this.id = id;
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof EventBusId) {
- EventBusId eventBusId = (EventBusId) o;
- return Objects.equals(this.id, eventBusId.id);
- }
- return false;
- }
-
- public String asString() {
- return id.toString();
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(id);
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("id", id)
- .toString();
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventDispatcher.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventDispatcher.java
deleted file mode 100644
index e7d1e62..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/EventDispatcher.java
+++ /dev/null
@@ -1,201 +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.mailbox.events;
-
-import static com.rabbitmq.client.MessageProperties.PERSISTENT_TEXT_PLAIN;
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DIRECT_EXCHANGE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.backends.rabbitmq.Constants.NO_ARGUMENTS;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.EVENT_BUS_ID;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_QUEUE;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.mailbox.events.RoutingKeyConverter.RoutingKey;
-import org.apache.james.util.MDCBuilder;
-import org.apache.james.util.MDCStructuredLogger;
-import org.apache.james.util.StructuredLogger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.rabbitmq.client.AMQP;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-import reactor.core.publisher.MonoProcessor;
-import reactor.rabbitmq.BindingSpecification;
-import reactor.rabbitmq.ExchangeSpecification;
-import reactor.rabbitmq.OutboundMessage;
-import reactor.rabbitmq.QueueSpecification;
-import reactor.rabbitmq.Sender;
-import reactor.util.function.Tuples;
-
-public class EventDispatcher {
- public static class DispatchingFailureGroup extends Group {
- public static DispatchingFailureGroup INSTANCE = new DispatchingFailureGroup();
- }
-
- private static final Logger LOGGER = LoggerFactory.getLogger(EventDispatcher.class);
-
- private final EventSerializer eventSerializer;
- private final Sender sender;
- private final LocalListenerRegistry localListenerRegistry;
- private final AMQP.BasicProperties basicProperties;
- private final MailboxListenerExecutor mailboxListenerExecutor;
- private final EventDeadLetters deadLetters;
-
- EventDispatcher(EventBusId eventBusId, EventSerializer eventSerializer, Sender sender,
- LocalListenerRegistry localListenerRegistry,
- MailboxListenerExecutor mailboxListenerExecutor,
- EventDeadLetters deadLetters) {
- this.eventSerializer = eventSerializer;
- this.sender = sender;
- this.localListenerRegistry = localListenerRegistry;
- this.basicProperties = new AMQP.BasicProperties.Builder()
- .headers(ImmutableMap.of(EVENT_BUS_ID, eventBusId.asString()))
- .deliveryMode(PERSISTENT_TEXT_PLAIN.getDeliveryMode())
- .priority(PERSISTENT_TEXT_PLAIN.getPriority())
- .contentType(PERSISTENT_TEXT_PLAIN.getContentType())
- .build();
- this.mailboxListenerExecutor = mailboxListenerExecutor;
- this.deadLetters = deadLetters;
- }
-
- void start() {
- Flux.concat(
- sender.declareExchange(ExchangeSpecification.exchange(MAILBOX_EVENT_EXCHANGE_NAME)
- .durable(DURABLE)
- .type(DIRECT_EXCHANGE)),
- sender.declareExchange(ExchangeSpecification.exchange(MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME)
- .durable(DURABLE)
- .type(DIRECT_EXCHANGE)),
- sender.declareQueue(QueueSpecification.queue(MAILBOX_EVENT_DEAD_LETTER_QUEUE)
- .durable(DURABLE)
- .exclusive(!EXCLUSIVE)
- .autoDelete(!AUTO_DELETE)
- .arguments(NO_ARGUMENTS)),
- sender.bind(BindingSpecification.binding()
- .exchange(MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME)
- .queue(MAILBOX_EVENT_DEAD_LETTER_QUEUE)
- .routingKey(EMPTY_ROUTING_KEY)))
- .then()
- .block();
- }
-
- Mono<Void> dispatch(Event event, Set<RegistrationKey> keys) {
- return Flux
- .concat(
- dispatchToLocalListeners(event, keys),
- dispatchToRemoteListeners(event, keys))
- .doOnError(throwable -> LOGGER.error("error while dispatching event", throwable))
- .then()
- .subscribeWith(MonoProcessor.create());
- }
-
- private Mono<Void> dispatchToLocalListeners(Event event, Set<RegistrationKey> keys) {
- return Flux.fromIterable(keys)
- .flatMap(key -> localListenerRegistry.getLocalMailboxListeners(key)
- .map(listener -> Tuples.of(key, listener)), EventBus.EXECUTION_RATE)
- .filter(pair -> pair.getT2().getExecutionMode() == EventListener.ExecutionMode.SYNCHRONOUS)
- .flatMap(pair -> executeListener(event, pair.getT2(), pair.getT1()), EventBus.EXECUTION_RATE)
- .then();
- }
-
- private Mono<Void> executeListener(Event event, EventListener.ReactiveEventListener mailboxListener, RegistrationKey registrationKey) {
- return mailboxListenerExecutor.execute(mailboxListener,
- MDCBuilder.create()
- .addContext(EventBus.StructuredLoggingFields.REGISTRATION_KEY, registrationKey),
- event)
- .onErrorResume(e -> {
- structuredLogger(event, ImmutableSet.of(registrationKey))
- .log(logger -> logger.error("Exception happens when dispatching event", e));
- return Mono.empty();
- });
- }
-
- private StructuredLogger structuredLogger(Event event, Set<RegistrationKey> keys) {
- return MDCStructuredLogger.forLogger(LOGGER)
- .addField(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
- .addField(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
- .addField(EventBus.StructuredLoggingFields.USER, event.getUsername())
- .addField(EventBus.StructuredLoggingFields.REGISTRATION_KEYS, keys);
- }
-
- private Mono<Void> dispatchToRemoteListeners(Event event, Set<RegistrationKey> keys) {
- return Mono.fromCallable(() -> serializeEvent(event))
- .flatMap(serializedEvent -> Mono.zipDelayError(
- remoteGroupsDispatch(serializedEvent, event),
- remoteKeysDispatch(serializedEvent, keys)))
- .then();
- }
-
- private Mono<Void> remoteGroupsDispatch(byte[] serializedEvent, Event event) {
- return remoteDispatch(serializedEvent, Collections.singletonList(RoutingKey.empty()))
- .doOnError(ex -> LOGGER.error(
- "cannot dispatch event of type '{}' belonging '{}' with id '{}' to remote groups, store it into dead letter",
- event.getClass().getSimpleName(),
- event.getUsername().asString(),
- event.getEventId().getId(),
- ex))
- .onErrorResume(ex -> deadLetters.store(DispatchingFailureGroup.INSTANCE, event)
- .then(Mono.error(ex)));
- }
-
- private Mono<Void> remoteKeysDispatch(byte[] serializedEvent, Set<RegistrationKey> keys) {
- return remoteDispatch(serializedEvent,
- keys.stream()
- .map(RoutingKey::of)
- .collect(Guavate.toImmutableList()));
- }
-
- private Mono<Void> remoteDispatch(byte[] serializedEvent, Collection<RoutingKey> routingKeys) {
- if (routingKeys.isEmpty()) {
- return Mono.empty();
- }
- return sender.send(toMessages(serializedEvent, routingKeys));
- }
-
- private Flux<OutboundMessage> toMessages(byte[] serializedEvent, Collection<RoutingKey> routingKeys) {
- return Flux.fromIterable(routingKeys)
- .map(routingKey -> new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME, routingKey.asString(), basicProperties, serializedEvent));
- }
-
- private byte[] serializeEvent(Event event) {
- return eventSerializer.toJson(event).getBytes(StandardCharsets.UTF_8);
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupConsumerRetry.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupConsumerRetry.java
deleted file mode 100644
index d74cc64..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupConsumerRetry.java
+++ /dev/null
@@ -1,145 +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.mailbox.events;
-
-import static com.rabbitmq.client.MessageProperties.PERSISTENT_TEXT_PLAIN;
-import static org.apache.james.backends.rabbitmq.Constants.DIRECT_EXCHANGE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
-import static org.apache.james.mailbox.events.GroupRegistration.RETRY_COUNT;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT;
-
-import java.nio.charset.StandardCharsets;
-
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.Group;
-import org.apache.james.util.MDCStructuredLogger;
-import org.apache.james.util.StructuredLogger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableMap;
-import com.rabbitmq.client.AMQP;
-
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-import reactor.rabbitmq.BindingSpecification;
-import reactor.rabbitmq.ExchangeSpecification;
-import reactor.rabbitmq.OutboundMessage;
-import reactor.rabbitmq.Sender;
-
-class GroupConsumerRetry {
-
- static class RetryExchangeName {
- static RetryExchangeName of(Group group) {
- return new RetryExchangeName(group.asString());
- }
-
- static final String MAILBOX_EVENT_RETRY_EXCHANGE_PREFIX = MAILBOX_EVENT + "-retryExchange-";
-
- private final String name;
-
- private RetryExchangeName(String name) {
- Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "Exchange name must be specified");
- this.name = name;
- }
-
- String asString() {
- return MAILBOX_EVENT_RETRY_EXCHANGE_PREFIX + name;
- }
- }
-
- private static final Logger LOGGER = LoggerFactory.getLogger(GroupConsumerRetry.class);
-
- private final Sender sender;
- private final RetryExchangeName retryExchangeName;
- private final RetryBackoffConfiguration retryBackoff;
- private final EventDeadLetters eventDeadLetters;
- private final Group group;
- private final EventSerializer eventSerializer;
-
- GroupConsumerRetry(Sender sender, Group group, RetryBackoffConfiguration retryBackoff,
- EventDeadLetters eventDeadLetters, EventSerializer eventSerializer) {
- this.sender = sender;
- this.retryExchangeName = RetryExchangeName.of(group);
- this.retryBackoff = retryBackoff;
- this.eventDeadLetters = eventDeadLetters;
- this.group = group;
- this.eventSerializer = eventSerializer;
- }
-
- Mono<Void> createRetryExchange(GroupRegistration.WorkQueueName queueName) {
- return Flux.concat(
- sender.declareExchange(ExchangeSpecification.exchange(retryExchangeName.asString())
- .durable(DURABLE)
- .type(DIRECT_EXCHANGE)),
- sender.bind(BindingSpecification.binding()
- .exchange(retryExchangeName.asString())
- .queue(queueName.asString())
- .routingKey(EMPTY_ROUTING_KEY)))
- .then();
- }
-
- Mono<Void> handleRetry(Event event, int currentRetryCount, Throwable throwable) {
- createStructuredLogger(event).log(logger -> logger.error("Exception happens when handling event after {} retries", currentRetryCount, throwable));
-
- return retryOrStoreToDeadLetter(event, currentRetryCount);
- }
-
- Mono<Void> retryOrStoreToDeadLetter(Event event, int currentRetryCount) {
- if (currentRetryCount >= retryBackoff.getMaxRetries()) {
- return eventDeadLetters.store(group, event).then();
- }
- return sendRetryMessage(event, currentRetryCount);
- }
-
- private Mono<Void> sendRetryMessage(Event event, int currentRetryCount) {
- byte[] eventAsBytes = eventSerializer.toJson(event).getBytes(StandardCharsets.UTF_8);
-
- Mono<OutboundMessage> retryMessage = Mono.just(new OutboundMessage(
- retryExchangeName.asString(),
- EMPTY_ROUTING_KEY,
- new AMQP.BasicProperties.Builder()
- .headers(ImmutableMap.of(RETRY_COUNT, currentRetryCount + 1))
- .deliveryMode(PERSISTENT_TEXT_PLAIN.getDeliveryMode())
- .priority(PERSISTENT_TEXT_PLAIN.getPriority())
- .contentType(PERSISTENT_TEXT_PLAIN.getContentType())
- .build(),
- eventAsBytes));
-
- return sender.send(retryMessage)
- .doOnError(throwable -> createStructuredLogger(event)
- .log(logger -> logger.error("Exception happens when publishing event to retry exchange, this event will be stored in deadLetter", throwable)))
- .onErrorResume(e -> eventDeadLetters.store(group, event).then());
- }
-
- private StructuredLogger createStructuredLogger(Event event) {
- return MDCStructuredLogger.forLogger(LOGGER)
- .addField(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
- .addField(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
- .addField(EventBus.StructuredLoggingFields.USER, event.getUsername())
- .addField(EventBus.StructuredLoggingFields.GROUP, group.asString());
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistration.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistration.java
deleted file mode 100644
index e07d6a7..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistration.java
+++ /dev/null
@@ -1,198 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.backends.rabbitmq.Constants.REQUEUE;
-import static org.apache.james.backends.rabbitmq.Constants.deadLetterQueue;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Predicate;
-
-import org.apache.james.backends.rabbitmq.ReactorRabbitMQChannelPool;
-import org.apache.james.backends.rabbitmq.ReceiverProvider;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.Registration;
-import org.apache.james.util.MDCBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-
-import reactor.core.Disposable;
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-import reactor.rabbitmq.AcknowledgableDelivery;
-import reactor.rabbitmq.BindingSpecification;
-import reactor.rabbitmq.ConsumeOptions;
-import reactor.rabbitmq.QueueSpecification;
-import reactor.rabbitmq.Receiver;
-import reactor.rabbitmq.Sender;
-import reactor.util.retry.Retry;
-
-class GroupRegistration implements Registration {
- static class WorkQueueName {
- static WorkQueueName of(Group group) {
- return new WorkQueueName(group);
- }
-
- static final String MAILBOX_EVENT_WORK_QUEUE_PREFIX = MAILBOX_EVENT + "-workQueue-";
-
- private final Group group;
-
- private WorkQueueName(Group group) {
- Preconditions.checkNotNull(group, "Group must be specified");
- this.group = group;
- }
-
- String asString() {
- return MAILBOX_EVENT_WORK_QUEUE_PREFIX + group.asString();
- }
- }
-
- private static final Logger LOGGER = LoggerFactory.getLogger(GroupRegistration.class);
- static final String RETRY_COUNT = "retry-count";
- static final int DEFAULT_RETRY_COUNT = 0;
-
- private final ReactorRabbitMQChannelPool channelPool;
- private final EventListener.ReactiveEventListener mailboxListener;
- private final WorkQueueName queueName;
- private final Receiver receiver;
- private final Runnable unregisterGroup;
- private final Sender sender;
- private final EventSerializer eventSerializer;
- private final GroupConsumerRetry retryHandler;
- private final WaitDelayGenerator delayGenerator;
- private final Group group;
- private final RetryBackoffConfiguration retryBackoff;
- private final MailboxListenerExecutor mailboxListenerExecutor;
- private Optional<Disposable> receiverSubscriber;
-
- GroupRegistration(ReactorRabbitMQChannelPool channelPool, Sender sender, ReceiverProvider receiverProvider, EventSerializer eventSerializer,
- EventListener.ReactiveEventListener mailboxListener, Group group, RetryBackoffConfiguration retryBackoff,
- EventDeadLetters eventDeadLetters,
- Runnable unregisterGroup, MailboxListenerExecutor mailboxListenerExecutor) {
- this.channelPool = channelPool;
- this.eventSerializer = eventSerializer;
- this.mailboxListener = mailboxListener;
- this.queueName = WorkQueueName.of(group);
- this.sender = sender;
- this.receiver = receiverProvider.createReceiver();
- this.retryBackoff = retryBackoff;
- this.mailboxListenerExecutor = mailboxListenerExecutor;
- this.receiverSubscriber = Optional.empty();
- this.unregisterGroup = unregisterGroup;
- this.retryHandler = new GroupConsumerRetry(sender, group, retryBackoff, eventDeadLetters, eventSerializer);
- this.delayGenerator = WaitDelayGenerator.of(retryBackoff);
- this.group = group;
- }
-
- GroupRegistration start() {
- receiverSubscriber = Optional
- .of(createGroupWorkQueue()
- .then(retryHandler.createRetryExchange(queueName))
- .then(Mono.fromCallable(() -> this.consumeWorkQueue()))
- .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()).scheduler(Schedulers.elastic()))
- .block());
- return this;
- }
-
- private Mono<Void> createGroupWorkQueue() {
- return channelPool.createWorkQueue(
- QueueSpecification.queue(queueName.asString())
- .durable(DURABLE)
- .exclusive(!EXCLUSIVE)
- .autoDelete(!AUTO_DELETE)
- .arguments(deadLetterQueue(MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME)),
- BindingSpecification.binding()
- .exchange(MAILBOX_EVENT_EXCHANGE_NAME)
- .queue(queueName.asString())
- .routingKey(EMPTY_ROUTING_KEY));
- }
-
- private Disposable consumeWorkQueue() {
- return receiver.consumeManualAck(queueName.asString(), new ConsumeOptions().qos(EventBus.EXECUTION_RATE))
- .publishOn(Schedulers.parallel())
- .filter(delivery -> Objects.nonNull(delivery.getBody()))
- .flatMap(this::deliver, EventBus.EXECUTION_RATE)
- .subscribe();
- }
-
- private Mono<Void> deliver(AcknowledgableDelivery acknowledgableDelivery) {
- byte[] eventAsBytes = acknowledgableDelivery.getBody();
- int currentRetryCount = getRetryCount(acknowledgableDelivery);
-
- return deserializeEvent(eventAsBytes)
- .flatMap(event -> delayGenerator.delayIfHaveTo(currentRetryCount)
- .flatMap(any -> runListener(event))
- .onErrorResume(throwable -> retryHandler.handleRetry(event, currentRetryCount, throwable))
- .then(Mono.<Void>fromRunnable(acknowledgableDelivery::ack)))
- .onErrorResume(e -> {
- LOGGER.error("Unable to process delivery for group {}", group, e);
- return Mono.fromRunnable(() -> acknowledgableDelivery.nack(!REQUEUE));
- });
- }
-
- private Mono<Event> deserializeEvent(byte[] eventAsBytes) {
- return Mono.fromCallable(() -> eventSerializer.fromJson(new String(eventAsBytes, StandardCharsets.UTF_8)).get())
- .subscribeOn(Schedulers.parallel());
- }
-
- Mono<Void> reDeliver(Event event) {
- return retryHandler.retryOrStoreToDeadLetter(event, DEFAULT_RETRY_COUNT);
- }
-
- private Mono<Void> runListener(Event event) {
- return mailboxListenerExecutor.execute(
- mailboxListener,
- MDCBuilder.create()
- .addContext(EventBus.StructuredLoggingFields.GROUP, group),
- event);
- }
-
- private int getRetryCount(AcknowledgableDelivery acknowledgableDelivery) {
- return Optional.ofNullable(acknowledgableDelivery.getProperties().getHeaders())
- .flatMap(headers -> Optional.ofNullable(headers.get(RETRY_COUNT)))
- .filter(object -> object instanceof Integer)
- .map(Integer.class::cast)
- .orElse(DEFAULT_RETRY_COUNT);
- }
-
- @Override
- public void unregister() {
- receiverSubscriber.filter(Predicate.not(Disposable::isDisposed))
- .ifPresent(Disposable::dispose);
- receiver.close();
- unregisterGroup.run();
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistrationHandler.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistrationHandler.java
deleted file mode 100644
index 950ac44..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/GroupRegistrationHandler.java
+++ /dev/null
@@ -1,93 +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.mailbox.events;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.james.backends.rabbitmq.ReactorRabbitMQChannelPool;
-import org.apache.james.backends.rabbitmq.ReceiverProvider;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.GroupAlreadyRegistered;
-import org.apache.james.events.GroupRegistrationNotFound;
-import org.apache.james.events.Registration;
-
-import reactor.rabbitmq.Sender;
-
-class GroupRegistrationHandler {
- private final Map<Group, GroupRegistration> groupRegistrations;
- private final EventSerializer eventSerializer;
- private final ReactorRabbitMQChannelPool channelPool;
- private final Sender sender;
- private final ReceiverProvider receiverProvider;
- private final RetryBackoffConfiguration retryBackoff;
- private final EventDeadLetters eventDeadLetters;
- private final MailboxListenerExecutor mailboxListenerExecutor;
-
- GroupRegistrationHandler(EventSerializer eventSerializer, ReactorRabbitMQChannelPool channelPool, Sender sender, ReceiverProvider receiverProvider,
- RetryBackoffConfiguration retryBackoff,
- EventDeadLetters eventDeadLetters, MailboxListenerExecutor mailboxListenerExecutor) {
- this.eventSerializer = eventSerializer;
- this.channelPool = channelPool;
- this.sender = sender;
- this.receiverProvider = receiverProvider;
- this.retryBackoff = retryBackoff;
- this.eventDeadLetters = eventDeadLetters;
- this.mailboxListenerExecutor = mailboxListenerExecutor;
- this.groupRegistrations = new ConcurrentHashMap<>();
- }
-
- GroupRegistration retrieveGroupRegistration(Group group) {
- return Optional.ofNullable(groupRegistrations.get(group))
- .orElseThrow(() -> new GroupRegistrationNotFound(group));
- }
-
- void stop() {
- groupRegistrations.values().forEach(GroupRegistration::unregister);
- }
-
- Registration register(EventListener.ReactiveEventListener listener, Group group) {
- return groupRegistrations
- .compute(group, (groupToRegister, oldGroupRegistration) -> {
- if (oldGroupRegistration != null) {
- throw new GroupAlreadyRegistered(group);
- }
- return newGroupRegistration(listener, groupToRegister);
- })
- .start();
- }
-
- private GroupRegistration newGroupRegistration(EventListener.ReactiveEventListener listener, Group group) {
- return new GroupRegistration(
- channelPool, sender,
- receiverProvider,
- eventSerializer,
- listener,
- group,
- retryBackoff,
- eventDeadLetters,
- () -> groupRegistrations.remove(group),
- mailboxListenerExecutor);
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyReconnectionHandler.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyReconnectionHandler.java
deleted file mode 100644
index a8162d0..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyReconnectionHandler.java
+++ /dev/null
@@ -1,60 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.mailbox.events.KeyRegistrationHandler.EVENTBUS_QUEUE_NAME_PREFIX;
-import static org.apache.james.mailbox.events.KeyRegistrationHandler.QUEUE_ARGUMENTS;
-
-import javax.inject.Inject;
-
-import org.apache.james.backends.rabbitmq.SimpleConnectionPool;
-import org.reactivestreams.Publisher;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.rabbitmq.client.Channel;
-import com.rabbitmq.client.Connection;
-
-import reactor.core.publisher.Mono;
-
-public class KeyReconnectionHandler implements SimpleConnectionPool.ReconnectionHandler {
- private static final Logger LOGGER = LoggerFactory.getLogger(KeyReconnectionHandler.class);
-
- private final EventBusId eventBusId;
-
- @Inject
- public KeyReconnectionHandler(EventBusId eventBusId) {
- this.eventBusId = eventBusId;
- }
-
- @Override
- public Publisher<Void> handleReconnection(Connection connection) {
- return Mono.fromRunnable(() -> {
- try (Channel channel = connection.createChannel()) {
- channel.queueDeclare(EVENTBUS_QUEUE_NAME_PREFIX + eventBusId.asString(), DURABLE, !EXCLUSIVE, AUTO_DELETE, QUEUE_ARGUMENTS);
- } catch (Exception e) {
- LOGGER.error("Error recovering connection", e);
- }
- });
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistration.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistration.java
deleted file mode 100644
index be1f399..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistration.java
+++ /dev/null
@@ -1,35 +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.mailbox.events;
-
-import org.apache.james.events.Registration;
-
-class KeyRegistration implements Registration {
- private final Runnable unregister;
-
- KeyRegistration(Runnable unregister) {
- this.unregister = unregister;
- }
-
- @Override
- public void unregister() {
- unregister.run();
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistrationHandler.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistrationHandler.java
deleted file mode 100644
index 0731ca8..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/KeyRegistrationHandler.java
+++ /dev/null
@@ -1,204 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.EVENT_BUS_ID;
-
-import java.nio.charset.StandardCharsets;
-import java.time.Duration;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Predicate;
-
-import org.apache.james.backends.rabbitmq.ReceiverProvider;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Registration;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.util.MDCBuilder;
-import org.apache.james.util.MDCStructuredLogger;
-import org.apache.james.util.StructuredLogger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableMap;
-import com.rabbitmq.client.AMQP;
-import com.rabbitmq.client.Delivery;
-
-import reactor.core.Disposable;
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-import reactor.rabbitmq.ConsumeOptions;
-import reactor.rabbitmq.QueueSpecification;
-import reactor.rabbitmq.Receiver;
-import reactor.rabbitmq.Sender;
-import reactor.util.retry.Retry;
-
-class KeyRegistrationHandler {
- private static final Logger LOGGER = LoggerFactory.getLogger(KeyRegistrationHandler.class);
- static final String EVENTBUS_QUEUE_NAME_PREFIX = "eventbus-";
- private static final Duration EXPIRATION_TIMEOUT = Duration.ofMinutes(30);
- static final Map<String, Object> QUEUE_ARGUMENTS = ImmutableMap.of("x-expires", EXPIRATION_TIMEOUT.toMillis());
-
- private static final Duration TOPOLOGY_CHANGES_TIMEOUT = Duration.ofMinutes(1);
-
- private final EventBusId eventBusId;
- private final LocalListenerRegistry localListenerRegistry;
- private final EventSerializer eventSerializer;
- private final Sender sender;
- private final RoutingKeyConverter routingKeyConverter;
- private final Receiver receiver;
- private final RegistrationQueueName registrationQueue;
- private final RegistrationBinder registrationBinder;
- private final MailboxListenerExecutor mailboxListenerExecutor;
- private final RetryBackoffConfiguration retryBackoff;
- private Optional<Disposable> receiverSubscriber;
-
- KeyRegistrationHandler(EventBusId eventBusId, EventSerializer eventSerializer,
- Sender sender, ReceiverProvider receiverProvider,
- RoutingKeyConverter routingKeyConverter, LocalListenerRegistry localListenerRegistry,
- MailboxListenerExecutor mailboxListenerExecutor, RetryBackoffConfiguration retryBackoff) {
- this.eventBusId = eventBusId;
- this.eventSerializer = eventSerializer;
- this.sender = sender;
- this.routingKeyConverter = routingKeyConverter;
- this.localListenerRegistry = localListenerRegistry;
- this.receiver = receiverProvider.createReceiver();
- this.mailboxListenerExecutor = mailboxListenerExecutor;
- this.retryBackoff = retryBackoff;
- this.registrationQueue = new RegistrationQueueName(EVENTBUS_QUEUE_NAME_PREFIX + eventBusId.asString());
- this.registrationBinder = new RegistrationBinder(sender, registrationQueue);
- this.receiverSubscriber = Optional.empty();
-
- }
-
- void start() {
- declareQueue();
-
- receiverSubscriber = Optional.of(receiver.consumeAutoAck(registrationQueue.asString(), new ConsumeOptions().qos(EventBus.EXECUTION_RATE))
- .subscribeOn(Schedulers.parallel())
- .flatMap(this::handleDelivery, EventBus.EXECUTION_RATE)
- .subscribe());
- }
-
- @VisibleForTesting
- void declareQueue() {
- declareQueue(sender);
- }
-
- private void declareQueue(Sender sender) {
- sender.declareQueue(
- QueueSpecification.queue(EVENTBUS_QUEUE_NAME_PREFIX + eventBusId.asString())
- .durable(DURABLE)
- .exclusive(!EXCLUSIVE)
- .autoDelete(AUTO_DELETE)
- .arguments(QUEUE_ARGUMENTS))
- .timeout(TOPOLOGY_CHANGES_TIMEOUT)
- .map(AMQP.Queue.DeclareOk::getQueue)
- .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()))
- .block();
- }
-
- void stop() {
- sender.delete(QueueSpecification.queue(registrationQueue.asString()))
- .timeout(TOPOLOGY_CHANGES_TIMEOUT)
- .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()).scheduler(Schedulers.elastic()))
- .block();
- receiverSubscriber.filter(Predicate.not(Disposable::isDisposed))
- .ifPresent(Disposable::dispose);
- receiver.close();
- }
-
- Mono<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key) {
- LocalListenerRegistry.LocalRegistration registration = localListenerRegistry.addListener(key, listener);
-
- return registerIfNeeded(key, registration)
- .thenReturn(new KeyRegistration(() -> {
- if (registration.unregister().lastListenerRemoved()) {
- registrationBinder.unbind(key)
- .timeout(TOPOLOGY_CHANGES_TIMEOUT)
- .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()).scheduler(Schedulers.elastic()))
- .subscribeOn(Schedulers.elastic())
- .block();
- }
- }));
- }
-
- private Mono<Void> registerIfNeeded(RegistrationKey key, LocalListenerRegistry.LocalRegistration registration) {
- if (registration.isFirstListener()) {
- return registrationBinder.bind(key)
- .timeout(TOPOLOGY_CHANGES_TIMEOUT)
- .retryWhen(Retry.backoff(retryBackoff.getMaxRetries(), retryBackoff.getFirstBackoff()).jitter(retryBackoff.getJitterFactor()).scheduler(Schedulers.elastic()));
- }
- return Mono.empty();
- }
-
- private Mono<Void> handleDelivery(Delivery delivery) {
- if (delivery.getBody() == null) {
- return Mono.empty();
- }
-
- String serializedEventBusId = delivery.getProperties().getHeaders().get(EVENT_BUS_ID).toString();
- EventBusId eventBusId = EventBusId.of(serializedEventBusId);
-
- String routingKey = delivery.getEnvelope().getRoutingKey();
- RegistrationKey registrationKey = routingKeyConverter.toRegistrationKey(routingKey);
- Event event = toEvent(delivery);
-
- return localListenerRegistry.getLocalMailboxListeners(registrationKey)
- .filter(listener -> !isLocalSynchronousListeners(eventBusId, listener))
- .flatMap(listener -> executeListener(listener, event, registrationKey), EventBus.EXECUTION_RATE)
- .then();
- }
-
- private Mono<Void> executeListener(EventListener.ReactiveEventListener listener, Event event, RegistrationKey key) {
- MDCBuilder mdcBuilder = MDCBuilder.create()
- .addContext(EventBus.StructuredLoggingFields.REGISTRATION_KEY, key);
-
- return mailboxListenerExecutor.execute(listener, mdcBuilder, event)
- .doOnError(e -> structuredLogger(event, key)
- .log(logger -> logger.error("Exception happens when handling event", e)))
- .onErrorResume(e -> Mono.empty())
- .then();
- }
-
- private boolean isLocalSynchronousListeners(EventBusId eventBusId, EventListener listener) {
- return eventBusId.equals(this.eventBusId) &&
- listener.getExecutionMode().equals(EventListener.ExecutionMode.SYNCHRONOUS);
- }
-
- private Event toEvent(Delivery delivery) {
- return eventSerializer.fromJson(new String(delivery.getBody(), StandardCharsets.UTF_8)).get();
- }
-
- private StructuredLogger structuredLogger(Event event, RegistrationKey key) {
- return MDCStructuredLogger.forLogger(LOGGER)
- .addField(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
- .addField(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
- .addField(EventBus.StructuredLoggingFields.USER, event.getUsername())
- .addField(EventBus.StructuredLoggingFields.REGISTRATION_KEY, key);
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/LocalListenerRegistry.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/LocalListenerRegistry.java
deleted file mode 100644
index 468bde6..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/LocalListenerRegistry.java
+++ /dev/null
@@ -1,112 +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.mailbox.events;
-
-import static com.google.common.base.Predicates.not;
-
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Supplier;
-
-import org.apache.james.events.EventListener;
-import org.apache.james.events.RegistrationKey;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Flux;
-
-class LocalListenerRegistry {
-
- interface RemovalStatus {
- boolean lastListenerRemoved();
- }
-
- public static class LocalRegistration {
- private final boolean firstListener;
- private final Supplier<RemovalStatus> unregister;
-
- public LocalRegistration(boolean firstListener, Supplier<RemovalStatus> unregister) {
- this.firstListener = firstListener;
- this.unregister = unregister;
- }
-
- public boolean isFirstListener() {
- return firstListener;
- }
-
- public RemovalStatus unregister() {
- return unregister.get();
- }
- }
-
- private final ConcurrentHashMap<RegistrationKey, ImmutableSet<EventListener.ReactiveEventListener>> listenersByKey;
-
- LocalListenerRegistry() {
- this.listenersByKey = new ConcurrentHashMap<>();
- }
-
- LocalRegistration addListener(RegistrationKey registrationKey, EventListener.ReactiveEventListener listener) {
- AtomicBoolean firstListener = new AtomicBoolean(false);
- listenersByKey.compute(registrationKey, (key, listeners) ->
- Optional.ofNullable(listeners)
- .map(set -> ImmutableSet.<EventListener.ReactiveEventListener>builder().addAll(set).add(listener).build())
- .orElseGet(() -> {
- firstListener.set(true);
- return ImmutableSet.of(listener);
- })
- );
- return new LocalRegistration(firstListener.get(), () -> removeListener(registrationKey, listener));
- }
-
- LocalRegistration addListener(RegistrationKey registrationKey, EventListener listener) {
- return addListener(registrationKey, EventListener.wrapReactive(listener));
- }
-
- private RemovalStatus removeListener(RegistrationKey registrationKey, EventListener.ReactiveEventListener listener) {
- AtomicBoolean lastListenerRemoved = new AtomicBoolean(false);
- listenersByKey.compute(registrationKey, (key, listeners) -> {
- boolean listenersContainRequested = Optional.ofNullable(listeners).orElse(ImmutableSet.of()).contains(listener);
- if (listenersContainRequested) {
- ImmutableSet<EventListener.ReactiveEventListener> remainingListeners = removeListenerFromSet(listener, listeners);
- if (remainingListeners.isEmpty()) {
- lastListenerRemoved.set(true);
- return null;
- }
- return remainingListeners;
- }
- return listeners;
- });
- return lastListenerRemoved::get;
- }
-
- private ImmutableSet<EventListener.ReactiveEventListener> removeListenerFromSet(EventListener listener, ImmutableSet<EventListener.ReactiveEventListener> listeners) {
- ImmutableSet<EventListener.ReactiveEventListener> remainingListeners = listeners.stream().filter(not(listener::equals)).collect(Guavate.toImmutableSet());
- if (remainingListeners.isEmpty()) {
- return ImmutableSet.of();
- }
- return remainingListeners;
- }
-
- Flux<EventListener.ReactiveEventListener> getLocalMailboxListeners(RegistrationKey registrationKey) {
- return Flux.fromIterable(listenersByKey.getOrDefault(registrationKey, ImmutableSet.of()));
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/MailboxListenerExecutor.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/MailboxListenerExecutor.java
deleted file mode 100644
index f35dc77..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/MailboxListenerExecutor.java
+++ /dev/null
@@ -1,56 +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.mailbox.events;
-
-import static org.apache.james.events.EventBus.Metrics.timerName;
-
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventListener;
-import org.apache.james.metrics.api.MetricFactory;
-import org.apache.james.util.MDCBuilder;
-import org.apache.james.util.ReactorUtils;
-
-import reactor.core.publisher.Mono;
-
-class MailboxListenerExecutor {
- private final MetricFactory metricFactory;
-
- MailboxListenerExecutor(MetricFactory metricFactory) {
- this.metricFactory = metricFactory;
- }
-
- Mono<Void> execute(EventListener.ReactiveEventListener listener, MDCBuilder mdcBuilder, Event event) {
- if (listener.isHandling(event)) {
- return Mono.from(metricFactory.decoratePublisherWithTimerMetric(timerName(listener),
- Mono.from(listener.reactiveEvent(event))
- .subscriberContext(ReactorUtils.context("MailboxListenerExecutor", mdc(listener, mdcBuilder, event)))));
- }
- return Mono.empty();
- }
-
- private MDCBuilder mdc(EventListener listener, MDCBuilder mdcBuilder, Event event) {
- return mdcBuilder
- .addContext(EventBus.StructuredLoggingFields.EVENT_ID, event.getEventId())
- .addContext(EventBus.StructuredLoggingFields.EVENT_CLASS, event.getClass())
- .addContext(EventBus.StructuredLoggingFields.USER, event.getUsername())
- .addContext(EventBus.StructuredLoggingFields.LISTENER_CLASS, listener.getClass());
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RabbitMQEventBus.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RabbitMQEventBus.java
deleted file mode 100644
index 14c4804..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RabbitMQEventBus.java
+++ /dev/null
@@ -1,177 +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.mailbox.events;
-
-import java.util.Set;
-
-import javax.annotation.PreDestroy;
-import javax.inject.Inject;
-
-import org.apache.james.backends.rabbitmq.ReactorRabbitMQChannelPool;
-import org.apache.james.backends.rabbitmq.ReceiverProvider;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.Registration;
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.lifecycle.api.Startable;
-import org.apache.james.metrics.api.MetricFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Mono;
-import reactor.rabbitmq.Sender;
-
-public class RabbitMQEventBus implements EventBus, Startable {
- private static final Set<RegistrationKey> NO_KEY = ImmutableSet.of();
- private static final String NOT_RUNNING_ERROR_MESSAGE = "Event Bus is not running";
- static final String MAILBOX_EVENT = "mailboxEvent";
- static final String MAILBOX_EVENT_DEAD_LETTER_QUEUE = MAILBOX_EVENT + "-dead-letter-queue";
- static final String MAILBOX_EVENT_EXCHANGE_NAME = MAILBOX_EVENT + "-exchange";
- static final String MAILBOX_EVENT_DEAD_LETTER_EXCHANGE_NAME = MAILBOX_EVENT + "-dead-letter-exchange";
- static final String EVENT_BUS_ID = "eventBusId";
-
- private final EventSerializer eventSerializer;
- private final RoutingKeyConverter routingKeyConverter;
- private final RetryBackoffConfiguration retryBackoff;
- private final EventBusId eventBusId;
- private final EventDeadLetters eventDeadLetters;
- private final MailboxListenerExecutor mailboxListenerExecutor;
- private final Sender sender;
- private final ReceiverProvider receiverProvider;
- private final ReactorRabbitMQChannelPool channelPool;
-
- private volatile boolean isRunning;
- private volatile boolean isStopping;
- private GroupRegistrationHandler groupRegistrationHandler;
- private KeyRegistrationHandler keyRegistrationHandler;
- private EventDispatcher eventDispatcher;
-
- @Inject
- public RabbitMQEventBus(Sender sender, ReceiverProvider receiverProvider, EventSerializer eventSerializer,
- RetryBackoffConfiguration retryBackoff,
- RoutingKeyConverter routingKeyConverter,
- EventDeadLetters eventDeadLetters, MetricFactory metricFactory, ReactorRabbitMQChannelPool channelPool,
- EventBusId eventBusId) {
- this.sender = sender;
- this.receiverProvider = receiverProvider;
- this.mailboxListenerExecutor = new MailboxListenerExecutor(metricFactory);
- this.channelPool = channelPool;
- this.eventBusId = eventBusId;
- this.eventSerializer = eventSerializer;
- this.routingKeyConverter = routingKeyConverter;
- this.retryBackoff = retryBackoff;
- this.eventDeadLetters = eventDeadLetters;
- this.isRunning = false;
- this.isStopping = false;
- }
-
- public void start() {
- if (!isRunning && !isStopping) {
-
- LocalListenerRegistry localListenerRegistry = new LocalListenerRegistry();
- keyRegistrationHandler = new KeyRegistrationHandler(eventBusId, eventSerializer, sender, receiverProvider, routingKeyConverter, localListenerRegistry, mailboxListenerExecutor, retryBackoff);
- groupRegistrationHandler = new GroupRegistrationHandler(eventSerializer, channelPool, sender, receiverProvider, retryBackoff, eventDeadLetters, mailboxListenerExecutor);
- eventDispatcher = new EventDispatcher(eventBusId, eventSerializer, sender, localListenerRegistry, mailboxListenerExecutor, eventDeadLetters);
-
- eventDispatcher.start();
- keyRegistrationHandler.start();
- isRunning = true;
- }
- }
-
- @VisibleForTesting
- void startWithoutStartingKeyRegistrationHandler() {
- if (!isRunning && !isStopping) {
-
- LocalListenerRegistry localListenerRegistry = new LocalListenerRegistry();
- keyRegistrationHandler = new KeyRegistrationHandler(eventBusId, eventSerializer, sender, receiverProvider, routingKeyConverter, localListenerRegistry, mailboxListenerExecutor, retryBackoff);
- groupRegistrationHandler = new GroupRegistrationHandler(eventSerializer, channelPool, sender, receiverProvider, retryBackoff, eventDeadLetters, mailboxListenerExecutor);
- eventDispatcher = new EventDispatcher(eventBusId, eventSerializer, sender, localListenerRegistry, mailboxListenerExecutor, eventDeadLetters);
-
- keyRegistrationHandler.declareQueue();
-
- eventDispatcher.start();
- isRunning = true;
- }
- }
-
- @VisibleForTesting
- void startKeyRegistrationHandler() {
- keyRegistrationHandler.start();
- }
-
- @PreDestroy
- public void stop() {
- if (isRunning && !isStopping) {
- isStopping = true;
- isRunning = false;
- groupRegistrationHandler.stop();
- keyRegistrationHandler.stop();
- }
- }
-
- @Override
- public Mono<Registration> register(EventListener.ReactiveEventListener listener, RegistrationKey key) {
- Preconditions.checkState(isRunning, NOT_RUNNING_ERROR_MESSAGE);
- return keyRegistrationHandler.register(listener, key);
- }
-
- @Override
- public Registration register(EventListener.ReactiveEventListener listener, Group group) {
- Preconditions.checkState(isRunning, NOT_RUNNING_ERROR_MESSAGE);
- return groupRegistrationHandler.register(listener, group);
- }
-
- @Override
- public Mono<Void> dispatch(Event event, Set<RegistrationKey> key) {
- Preconditions.checkState(isRunning, NOT_RUNNING_ERROR_MESSAGE);
- if (!event.isNoop()) {
- return eventDispatcher.dispatch(event, key);
- }
- return Mono.empty();
- }
-
- @Override
- public Mono<Void> reDeliver(Group group, Event event) {
- Preconditions.checkState(isRunning, NOT_RUNNING_ERROR_MESSAGE);
- if (!event.isNoop()) {
- /*
- if the eventBus.dispatch() gets error while dispatching an event (rabbitMQ network outage maybe),
- which means all the group consumers will not be receiving that event.
-
- We store the that event in the dead letter and expecting in the future, it will be dispatched
- again not only for a specific consumer but all.
-
- That's why it is special, and we need to check event type before processing further.
- */
- if (group instanceof EventDispatcher.DispatchingFailureGroup) {
- return eventDispatcher.dispatch(event, NO_KEY);
- }
- return groupRegistrationHandler.retrieveGroupRegistration(group).reDeliver(event);
- }
- return Mono.empty();
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationBinder.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationBinder.java
deleted file mode 100644
index 88fa692..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationBinder.java
+++ /dev/null
@@ -1,56 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
-
-import org.apache.james.events.RegistrationKey;
-
-import reactor.core.publisher.Mono;
-import reactor.rabbitmq.BindingSpecification;
-import reactor.rabbitmq.Sender;
-
-class RegistrationBinder {
- private final Sender sender;
- private final RegistrationQueueName registrationQueue;
-
- RegistrationBinder(Sender sender, RegistrationQueueName registrationQueue) {
- this.sender = sender;
- this.registrationQueue = registrationQueue;
- }
-
- Mono<Void> bind(RegistrationKey key) {
- return sender.bind(bindingSpecification(key))
- .then();
- }
-
- Mono<Void> unbind(RegistrationKey key) {
- return sender.unbind(bindingSpecification(key))
- .then();
- }
-
- private BindingSpecification bindingSpecification(RegistrationKey key) {
- RoutingKeyConverter.RoutingKey routingKey = RoutingKeyConverter.RoutingKey.of(key);
- return BindingSpecification.binding()
- .exchange(MAILBOX_EVENT_EXCHANGE_NAME)
- .queue(registrationQueue.asString())
- .routingKey(routingKey.asString());
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationQueueName.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationQueueName.java
deleted file mode 100644
index 33c837b..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RegistrationQueueName.java
+++ /dev/null
@@ -1,32 +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.mailbox.events;
-
-class RegistrationQueueName {
- private final String queueName;
-
- RegistrationQueueName(String queueName) {
- this.queueName = queueName;
- }
-
- String asString() {
- return queueName;
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RoutingKeyConverter.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RoutingKeyConverter.java
deleted file mode 100644
index 755ef27..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/RoutingKeyConverter.java
+++ /dev/null
@@ -1,92 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-
-import javax.inject.Inject;
-
-import org.apache.james.events.RegistrationKey;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-public class RoutingKeyConverter {
- private static final String SEPARATOR = ":";
-
- static class RoutingKey {
-
- static RoutingKey empty() {
- return new RoutingKey(Optional.empty());
- }
-
- static RoutingKey of(RegistrationKey key) {
- return new RoutingKey(Optional.of(key));
- }
-
- private final Optional<RegistrationKey> registrationKey;
-
- private RoutingKey(Optional<RegistrationKey> registrationKey) {
- this.registrationKey = registrationKey;
- }
-
- String asString() {
- return registrationKey.map(key -> key.getClass().getName() + SEPARATOR + key.asString())
- .orElse(EMPTY_ROUTING_KEY);
- }
- }
-
- @VisibleForTesting
- static RoutingKeyConverter forFactories(RegistrationKey.Factory... factories) {
- return new RoutingKeyConverter(ImmutableSet.copyOf(factories));
- }
-
- private final Set<RegistrationKey.Factory> factories;
-
- @Inject
- public RoutingKeyConverter(Set<RegistrationKey.Factory> factories) {
- this.factories = factories;
- }
-
- RegistrationKey toRegistrationKey(String routingKey) {
- return toRegistrationKey(Splitter.on(SEPARATOR).splitToList(routingKey));
- }
-
- private RegistrationKey toRegistrationKey(List<String> parts) {
- Preconditions.checkArgument(parts.size() >= 2, "Routing key needs to match the 'classFQDN:value' pattern");
-
- String registrationClass = parts.get(0);
- String value = Joiner.on(SEPARATOR).join(Iterables.skip(parts, 1));
-
- return factories.stream()
- .filter(factory -> factory.forClass().getName().equals(registrationClass))
- .findAny()
- .orElseThrow(() -> new IllegalArgumentException("No factory for " + registrationClass))
- .fromString(value);
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/WaitDelayGenerator.java b/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/WaitDelayGenerator.java
deleted file mode 100644
index 9f2c0fd..0000000
--- a/mailbox/event/event-rabbitmq/src/main/java/org/apache/james/mailbox/events/WaitDelayGenerator.java
+++ /dev/null
@@ -1,83 +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.mailbox.events;
-
-import java.security.SecureRandom;
-import java.time.Duration;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.primitives.Ints;
-
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-
-class WaitDelayGenerator {
-
- static WaitDelayGenerator of(RetryBackoffConfiguration retryBackoff) {
- return new WaitDelayGenerator(retryBackoff);
- }
-
- private static Duration randomBetween(Duration base, Duration jitter) {
- Preconditions.checkArgument(!jitter.isNegative(), "jitter value should always be positive");
- if (jitter.isZero()) {
- return base;
- }
- long maxJitterAsMillis = jitter.toMillis();
- long jitterAsMillis = SECURE_RANDOM.nextInt(Ints.checkedCast(maxJitterAsMillis * 2)) / 2;
- return base.plusMillis(jitterAsMillis);
- }
-
- private static final SecureRandom SECURE_RANDOM = new SecureRandom();
-
- private final RetryBackoffConfiguration retryBackoff;
-
- private WaitDelayGenerator(RetryBackoffConfiguration retryBackoff) {
- this.retryBackoff = retryBackoff;
- }
-
- Mono<Integer> delayIfHaveTo(int retryCount) {
- Mono<Integer> countRetryMono = Mono.just(retryCount);
- if (!shouldDelay(retryCount)) {
- return countRetryMono;
- }
-
- return countRetryMono
- .delayElement(generateDelay(retryCount), Schedulers.elastic());
- }
-
- @VisibleForTesting
- Duration generateDelay(int retryCount) {
- if (!shouldDelay(retryCount)) {
- return Duration.ZERO;
- }
- long exponentialFactor = Double.valueOf(Math.pow(2, retryCount - 1)).longValue();
- Duration minDelay = retryBackoff.getFirstBackoff().multipliedBy(exponentialFactor);
- Duration jitterDelay = retryBackoff.getFirstBackoff()
- .multipliedBy(Double.valueOf(retryBackoff.getJitterFactor() * 100).intValue())
- .dividedBy(100);
-
- return randomBetween(minDelay, jitterDelay);
- }
-
- private boolean shouldDelay(int retryCount) {
- return retryCount >= 1 && retryCount <= retryBackoff.getMaxRetries();
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/EventBusIdTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/EventBusIdTest.java
deleted file mode 100644
index 7c6920b..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/EventBusIdTest.java
+++ /dev/null
@@ -1,50 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.util.UUID;
-
-import org.junit.jupiter.api.Test;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-class EventBusIdTest {
-
- private static final UUID UUID_1 = UUID.fromString("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
-
- @Test
- void eventBusIdShouldMatchBeanContract() {
- EqualsVerifier.forClass(EventBusId.class);
- }
-
- @Test
- void ofShouldDeserializeUUIDs() {
- assertThat(EventBusId.of(UUID_1.toString()))
- .isEqualTo(EventBusId.of(UUID_1));
- }
-
- @Test
- void asStringShouldReturnWrappedValue() {
- assertThat(EventBusId.of(UUID_1).asString())
- .isEqualTo("6e0dd59d-660e-4d9b-b22f-0354479f47b4");
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/LocalListenerRegistryTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/LocalListenerRegistryTest.java
deleted file mode 100644
index aa54521..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/LocalListenerRegistryTest.java
+++ /dev/null
@@ -1,256 +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.mailbox.events;
-
-import static org.apache.james.events.EventListener.wrapReactive;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.time.Duration;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.james.events.EventListener;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.util.concurrency.ConcurrentTestRunner;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-
-class LocalListenerRegistryTest {
- private static final MailboxIdRegistrationKey KEY_1 = new MailboxIdRegistrationKey(TestId.of(42));
-
- private LocalListenerRegistry testee;
-
- @BeforeEach
- void setUp() {
- testee = new LocalListenerRegistry();
- }
-
- @Test
- void getLocalMailboxListenersShouldReturnEmptyWhenNone() {
- assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
- .isEmpty();
- }
-
- @Test
- void getLocalMailboxListenersShouldReturnPreviouslyAddedListener() {
- EventListener listener = event -> { };
- testee.addListener(KEY_1, listener);
-
- assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
- .containsOnly(wrapReactive(listener));
- }
-
- @Test
- void getLocalMailboxListenersShouldReturnPreviouslyAddedListeners() {
- EventListener listener1 = event -> { };
- EventListener listener2 = event -> { };
- testee.addListener(KEY_1, listener1);
- testee.addListener(KEY_1, listener2);
-
- assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
- .containsOnly(wrapReactive(listener1), wrapReactive(listener2));
- }
-
- @Test
- void getLocalMailboxListenersShouldNotReturnRemovedListeners() {
- EventListener listener1 = event -> { };
- EventListener listener2 = event -> { };
- testee.addListener(KEY_1, listener1);
- LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener2);
-
- registration.unregister();
-
- assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
- .containsOnly(wrapReactive(listener1));
- }
-
- @Test
- void addListenerShouldReturnFirstListenerWhenNoPreviouslyRegisteredListeners() {
- EventListener listener = event -> { };
-
- assertThat(testee.addListener(KEY_1, listener).isFirstListener()).isTrue();
- }
-
- @Test
- void addListenerShouldNotReturnFirstListenerWhenPreviouslyRegisteredListeners() {
- EventListener listener = event -> { };
- EventListener listener2 = event -> { };
-
- testee.addListener(KEY_1, listener);
-
- assertThat(testee.addListener(KEY_1, listener2).isFirstListener()).isFalse();
- }
-
- @Test
- void removeListenerShouldNotReturnLastListenerRemovedWhenSeveralListener() {
- EventListener listener = event -> { };
- EventListener listener2 = event -> { };
-
- LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener);
- testee.addListener(KEY_1, listener2);
-
- assertThat(registration.unregister().lastListenerRemoved()).isFalse();
- }
-
- @Test
- void removeListenerShouldReturnLastListenerRemovedWhenOneListener() {
- EventListener listener = event -> { };
-
-
- LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener);
-
- assertThat(registration.unregister().lastListenerRemoved()).isTrue();
- }
-
- @Nested
- class ConcurrentTest {
- private final Duration oneSecond = Duration.ofSeconds(1);
-
- @Test
- void getLocalMailboxListenersShouldReturnPreviousAddedListener() throws Exception {
- EventListener listener = event -> { };
-
- ConcurrentTestRunner.builder()
- .operation((threadNumber, operationNumber) -> testee.addListener(KEY_1, listener))
- .threadCount(10)
- .operationCount(10)
- .runSuccessfullyWithin(oneSecond);
-
- assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
- .containsOnly(wrapReactive(listener));
- }
-
- @Test
- void getLocalMailboxListenersShouldReturnAllPreviousAddedListeners() throws Exception {
- EventListener listener1 = event -> { };
- EventListener listener2 = event -> { };
- EventListener listener3 = event -> { };
-
- ConcurrentTestRunner.builder()
- .randomlyDistributedOperations(
- (threadNumber, operationNumber) -> testee.addListener(KEY_1, listener1),
- (threadNumber, operationNumber) -> testee.addListener(KEY_1, listener2),
- (threadNumber, operationNumber) -> testee.addListener(KEY_1, listener3))
- .threadCount(6)
- .operationCount(10)
- .runSuccessfullyWithin(oneSecond);
-
- assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
- .containsOnly(wrapReactive(listener1), wrapReactive(listener2), wrapReactive(listener3));
- }
-
- @Test
- void getLocalMailboxListenersShouldReturnEmptyWhenRemoveAddedListener() throws Exception {
- EventListener listener1 = event -> { };
-
- LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener1);
-
- ConcurrentTestRunner.builder()
- .operation(((threadNumber, operationNumber) -> registration.unregister()))
- .threadCount(10)
- .operationCount(10)
- .runSuccessfullyWithin(oneSecond);
-
- assertThat(testee.getLocalMailboxListeners(KEY_1).collectList().block())
- .isEmpty();
- }
-
- @Test
- void addListenerOnlyReturnIsFirstListenerForEmptyRegistry() throws Exception {
- EventListener listener1 = event -> { };
- EventListener listener2 = event -> { };
- EventListener listener3 = event -> { };
-
- AtomicInteger firstListenerCount = new AtomicInteger(0);
-
- ConcurrentTestRunner.builder()
- .randomlyDistributedOperations((threadNumber, operationNumber) -> {
- LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener1);
- if (registration.isFirstListener()) {
- firstListenerCount.incrementAndGet();
- }
- },
- (threadNumber, operationNumber) -> {
- LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener2);
- if (registration.isFirstListener()) {
- firstListenerCount.incrementAndGet();
- }
- },
- (threadNumber, operationNumber) -> {
- LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener3);
- if (registration.isFirstListener()) {
- firstListenerCount.incrementAndGet();
- }
- })
- .threadCount(6)
- .operationCount(10)
- .runSuccessfullyWithin(oneSecond);
-
- assertThat(firstListenerCount.get()).isEqualTo(1);
- }
-
- @Test
- void removeListenerOnlyReturnLastListenerRemovedForEmptyRegistry() throws Exception {
- EventListener listener1 = event -> { };
- AtomicInteger lastListenerRemoved = new AtomicInteger(0);
-
- LocalListenerRegistry.LocalRegistration registration = testee.addListener(KEY_1, listener1);
- ConcurrentTestRunner.builder()
- .operation(((threadNumber, operationNumber) -> {
- if (registration.unregister().lastListenerRemoved()) {
- lastListenerRemoved.incrementAndGet();
- }
- }))
- .threadCount(10)
- .operationCount(10)
- .runSuccessfullyWithin(oneSecond);
-
- assertThat(lastListenerRemoved.get()).isEqualTo(1);
- }
-
- @Test
- void iterationShouldPerformOnASnapshotOfListenersSet() {
- EventListener listener1 = event -> { };
- EventListener listener2 = event -> { };
- EventListener listener3 = event -> { };
- EventListener listener4 = event -> { };
- EventListener listener5 = event -> { };
-
- testee.addListener(KEY_1, listener1);
- testee.addListener(KEY_1, listener2);
- testee.addListener(KEY_1, listener3);
- testee.addListener(KEY_1, listener4);
- LocalListenerRegistry.LocalRegistration registration5 = testee.addListener(KEY_1, listener5);
-
- Mono<List<EventListener.ReactiveEventListener>> listeners = testee.getLocalMailboxListeners(KEY_1)
- .publishOn(Schedulers.elastic())
- .delayElements(Duration.ofMillis(100))
- .collectList();
-
- registration5.unregister();
-
- assertThat(listeners.block(Duration.ofSeconds(10))).hasSize(5);
- }
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/NetworkErrorTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/NetworkErrorTest.java
deleted file mode 100644
index fd551ec..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/NetworkErrorTest.java
+++ /dev/null
@@ -1,89 +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.mailbox.events;
-
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_A;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION;
-import static org.apache.james.mailbox.events.EventBusTestFixture.newListener;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.verify;
-
-import org.apache.james.backends.rabbitmq.RabbitMQExtension;
-import org.apache.james.backends.rabbitmq.RabbitMQFixture;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.EventListener;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-class NetworkErrorTest {
- @RegisterExtension
- static RabbitMQExtension rabbitMQExtension = RabbitMQExtension.singletonRabbitMQ()
- .isolationPolicy(RabbitMQExtension.IsolationPolicy.WEAK);
-
- private RabbitMQEventBus eventBus;
-
- @BeforeEach
- void setUp() {
- MemoryEventDeadLetters memoryEventDeadLetters = new MemoryEventDeadLetters();
-
- TestId.Factory mailboxIdFactory = new TestId.Factory();
- EventSerializer eventSerializer = new EventSerializer(mailboxIdFactory, new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
- RoutingKeyConverter routingKeyConverter = RoutingKeyConverter.forFactories(new MailboxIdRegistrationKey.Factory(mailboxIdFactory));
-
- eventBus = new RabbitMQEventBus(rabbitMQExtension.getSender(), rabbitMQExtension.getReceiverProvider(),
- eventSerializer, RETRY_BACKOFF_CONFIGURATION, routingKeyConverter,
- memoryEventDeadLetters, new RecordingMetricFactory(), rabbitMQExtension.getRabbitChannelPool(),
- EventBusId.random());
-
- eventBus.start();
- }
-
- @AfterEach
- void tearDown() {
- eventBus.stop();
- }
-
- @Test
- void dispatchShouldWorkAfterNetworkIssuesForOldRegistration() {
- EventListener listener = newListener();
- eventBus.register(listener, GROUP_A);
-
- rabbitMQExtension.getRabbitMQ().pause();
-
- assertThatThrownBy(() -> eventBus.dispatch(EVENT, NO_KEYS).block())
- .isInstanceOf(IllegalStateException.class)
- .hasMessageContaining("Retries exhausted");
-
- rabbitMQExtension.getRabbitMQ().unpause();
-
- eventBus.dispatch(EVENT, NO_KEYS).block();
- RabbitMQFixture.awaitAtMostThirtySeconds
- .untilAsserted(() -> verify(listener).event(EVENT));
- }
-
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusDeadLetterQueueUpgradeTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusDeadLetterQueueUpgradeTest.java
deleted file mode 100644
index 9ed6dad..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusDeadLetterQueueUpgradeTest.java
+++ /dev/null
@@ -1,88 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.mailbox.events.EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION;
-import static org.assertj.core.api.Assertions.assertThatCode;
-
-import org.apache.james.backends.rabbitmq.RabbitMQExtension;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.mailbox.events.EventBusTestFixture.GroupA;
-import org.apache.james.mailbox.events.GroupRegistration.WorkQueueName;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.apache.james.mailbox.util.EventCollector;
-import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-import reactor.rabbitmq.QueueSpecification;
-
-class RabbitMQEventBusDeadLetterQueueUpgradeTest {
- @RegisterExtension
- static RabbitMQExtension rabbitMQExtension = RabbitMQExtension.singletonRabbitMQ()
- .isolationPolicy(RabbitMQExtension.IsolationPolicy.WEAK);
-
- private RabbitMQEventBus eventBus;
-
- @BeforeEach
- void setUp() {
- MemoryEventDeadLetters memoryEventDeadLetters = new MemoryEventDeadLetters();
-
- TestId.Factory mailboxIdFactory = new TestId.Factory();
- EventSerializer eventSerializer = new EventSerializer(mailboxIdFactory, new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
- RoutingKeyConverter routingKeyConverter = RoutingKeyConverter.forFactories(new MailboxIdRegistrationKey.Factory(mailboxIdFactory));
-
- eventBus = new RabbitMQEventBus(rabbitMQExtension.getSender(), rabbitMQExtension.getReceiverProvider(),
- eventSerializer, RETRY_BACKOFF_CONFIGURATION, routingKeyConverter,
- memoryEventDeadLetters, new RecordingMetricFactory(), rabbitMQExtension.getRabbitChannelPool(),
- EventBusId.random());
-
- eventBus.start();
- }
-
- @AfterEach
- void tearDown() {
- eventBus.stop();
- }
-
- @Test
- void eventBusShouldStartWhenDeadLetterUpgradeWasNotPerformed() {
- GroupA registeredGroup = new GroupA();
- WorkQueueName workQueueName = WorkQueueName.of(registeredGroup);
-
- rabbitMQExtension.getSender()
- .declareQueue(QueueSpecification.queue(workQueueName.asString())
- .durable(DURABLE)
- .exclusive(!EXCLUSIVE)
- .autoDelete(!AUTO_DELETE))
- .block();
-
- assertThatCode(eventBus::start).doesNotThrowAnyException();
- assertThatCode(() -> eventBus.register(new EventCollector(), registeredGroup)).doesNotThrowAnyException();
- }
-
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusTest.java
deleted file mode 100644
index a167ca9..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RabbitMQEventBusTest.java
+++ /dev/null
@@ -1,980 +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.mailbox.events;
-
-import static org.apache.james.backends.rabbitmq.Constants.AUTO_DELETE;
-import static org.apache.james.backends.rabbitmq.Constants.DIRECT_EXCHANGE;
-import static org.apache.james.backends.rabbitmq.Constants.DURABLE;
-import static org.apache.james.backends.rabbitmq.Constants.EMPTY_ROUTING_KEY;
-import static org.apache.james.backends.rabbitmq.Constants.EXCLUSIVE;
-import static org.apache.james.backends.rabbitmq.Constants.NO_ARGUMENTS;
-import static org.apache.james.mailbox.events.EventBusConcurrentTestContract.newCountingListener;
-import static org.apache.james.mailbox.events.EventBusTestFixture.ALL_GROUPS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT;
-import static org.apache.james.mailbox.events.EventBusTestFixture.EVENT_2;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_A;
-import static org.apache.james.mailbox.events.EventBusTestFixture.GROUP_B;
-import static org.apache.james.mailbox.events.EventBusTestFixture.KEY_1;
-import static org.apache.james.mailbox.events.EventBusTestFixture.NO_KEYS;
-import static org.apache.james.mailbox.events.EventBusTestFixture.newAsyncListener;
-import static org.apache.james.mailbox.events.EventBusTestFixture.newListener;
-import static org.apache.james.mailbox.events.GroupRegistration.WorkQueueName.MAILBOX_EVENT_WORK_QUEUE_PREFIX;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_DEAD_LETTER_QUEUE;
-import static org.apache.james.mailbox.events.RabbitMQEventBus.MAILBOX_EVENT_EXCHANGE_NAME;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatCode;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.awaitility.Awaitility.await;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.Closeable;
-import java.nio.charset.StandardCharsets;
-import java.time.Duration;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-import org.apache.james.backends.rabbitmq.RabbitMQExtension;
-import org.apache.james.backends.rabbitmq.RabbitMQExtension.DockerRestartPolicy;
-import org.apache.james.backends.rabbitmq.RabbitMQFixture;
-import org.apache.james.backends.rabbitmq.RabbitMQManagementAPI;
-import org.apache.james.backends.rabbitmq.ReceiverProvider;
-import org.apache.james.event.json.EventSerializer;
-import org.apache.james.events.Event;
-import org.apache.james.events.EventBus;
-import org.apache.james.events.EventDeadLetters;
-import org.apache.james.events.EventListener;
-import org.apache.james.events.Group;
-import org.apache.james.events.GroupRegistrationNotFound;
-import org.apache.james.mailbox.events.EventBusTestFixture.EventListenerCountingSuccessfulExecution;
-import org.apache.james.mailbox.events.EventBusTestFixture.GroupA;
-import org.apache.james.mailbox.events.EventDispatcher.DispatchingFailureGroup;
-import org.apache.james.mailbox.events.RoutingKeyConverter.RoutingKey;
-import org.apache.james.mailbox.model.TestId;
-import org.apache.james.mailbox.model.TestMessageId;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.apache.james.mailbox.util.EventCollector;
-import org.apache.james.metrics.tests.RecordingMetricFactory;
-import org.apache.james.util.concurrency.ConcurrentTestRunner;
-import org.assertj.core.data.Percentage;
-import org.awaitility.Awaitility;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-import org.mockito.stubbing.Answer;
-
-import com.google.common.collect.ImmutableSet;
-
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-import reactor.rabbitmq.BindingSpecification;
-import reactor.rabbitmq.ExchangeSpecification;
-import reactor.rabbitmq.OutboundMessage;
-import reactor.rabbitmq.QueueSpecification;
-import reactor.rabbitmq.Receiver;
-import reactor.rabbitmq.Sender;
-
-class RabbitMQEventBusTest implements GroupContract.SingleEventBusGroupContract, GroupContract.MultipleEventBusGroupContract,
- KeyContract.SingleEventBusKeyContract, KeyContract.MultipleEventBusKeyContract,
- ErrorHandlingContract {
-
- @RegisterExtension
- static RabbitMQExtension rabbitMQExtension = RabbitMQExtension.singletonRabbitMQ()
- .isolationPolicy(RabbitMQExtension.IsolationPolicy.WEAK);
-
- private RabbitMQEventBus eventBus;
- private RabbitMQEventBus eventBus2;
- private RabbitMQEventBus eventBus3;
- private RabbitMQEventBus eventBusWithKeyHandlerNotStarted;
- private EventSerializer eventSerializer;
- private RoutingKeyConverter routingKeyConverter;
- private MemoryEventDeadLetters memoryEventDeadLetters;
-
- @Override
- public EnvironmentSpeedProfile getSpeedProfile() {
- return EnvironmentSpeedProfile.SLOW;
- }
-
- @BeforeEach
- void setUp() {
- memoryEventDeadLetters = new MemoryEventDeadLetters();
-
- TestId.Factory mailboxIdFactory = new TestId.Factory();
- eventSerializer = new EventSerializer(mailboxIdFactory, new TestMessageId.Factory(), new DefaultUserQuotaRootResolver.DefaultQuotaRootDeserializer());
- routingKeyConverter = RoutingKeyConverter.forFactories(new MailboxIdRegistrationKey.Factory(mailboxIdFactory));
-
- eventBus = newEventBus();
- eventBus2 = newEventBus();
- eventBus3 = newEventBus();
- eventBusWithKeyHandlerNotStarted = newEventBus();
-
- eventBus.start();
- eventBus2.start();
- eventBus3.start();
- eventBusWithKeyHandlerNotStarted.startWithoutStartingKeyRegistrationHandler();
- }
-
- @AfterEach
- void tearDown() {
- eventBus.stop();
- eventBus2.stop();
- eventBus3.stop();
- eventBusWithKeyHandlerNotStarted.stop();
- ALL_GROUPS.stream()
- .map(GroupRegistration.WorkQueueName::of)
- .forEach(queueName -> rabbitMQExtension.getSender().delete(QueueSpecification.queue(queueName.asString())).block());
- rabbitMQExtension.getSender()
- .delete(ExchangeSpecification.exchange(MAILBOX_EVENT_EXCHANGE_NAME))
- .block();
- }
-
- private RabbitMQEventBus newEventBus() {
- return newEventBus(rabbitMQExtension.getSender(), rabbitMQExtension.getReceiverProvider());
- }
-
- private RabbitMQEventBus newEventBus(Sender sender, ReceiverProvider receiverProvider) {
- return new RabbitMQEventBus(sender, receiverProvider, eventSerializer,
- EventBusTestFixture.RETRY_BACKOFF_CONFIGURATION, routingKeyConverter,
- memoryEventDeadLetters, new RecordingMetricFactory(),
- rabbitMQExtension.getRabbitChannelPool(), EventBusId.random());
- }
-
- @Override
- public EventBus eventBus() {
- return eventBus;
- }
-
- @Override
- public EventBus eventBus2() {
- return eventBus2;
- }
-
- @Override
- public EventDeadLetters deadLetter() {
- return memoryEventDeadLetters;
- }
-
- @Override
- @Test
- @Disabled("This test is failing by design as the different registration keys are handled by distinct messages")
- public void dispatchShouldCallListenerOnceWhenSeveralKeysMatching() {
-
- }
-
- @Test
- void eventProcessingShouldNotCrashOnInvalidMessage() {
- EventCollector listener = new EventCollector();
- EventBusTestFixture.GroupA registeredGroup = new EventBusTestFixture.GroupA();
- eventBus.register(listener, registeredGroup);
-
- String emptyRoutingKey = "";
- rabbitMQExtension.getSender()
- .send(Mono.just(new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME,
- emptyRoutingKey,
- "BAD_PAYLOAD!".getBytes(StandardCharsets.UTF_8))))
- .block();
-
- eventBus.dispatch(EVENT, NO_KEYS).block();
- await()
- .timeout(org.awaitility.Duration.TEN_SECONDS).untilAsserted(() ->
- assertThat(listener.getEvents()).containsOnly(EVENT));
- }
-
- @Test
- void eventProcessingShouldNotCrashOnInvalidMessages() {
- EventCollector listener = new EventCollector();
- EventBusTestFixture.GroupA registeredGroup = new EventBusTestFixture.GroupA();
- eventBus.register(listener, registeredGroup);
-
- String emptyRoutingKey = "";
- IntStream.range(0, 10).forEach(i -> rabbitMQExtension.getSender()
- .send(Mono.just(new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME,
- emptyRoutingKey,
- "BAD_PAYLOAD!".getBytes(StandardCharsets.UTF_8))))
- .block());
-
- eventBus.dispatch(EVENT, NO_KEYS).block();
- await()
- .timeout(org.awaitility.Duration.TEN_SECONDS).untilAsserted(() ->
- assertThat(listener.getEvents()).containsOnly(EVENT));
- }
-
- @Test
- void eventProcessingShouldStoreInvalidMessagesInDeadLetterQueue() {
- EventCollector listener = new EventCollector();
- EventBusTestFixture.GroupA registeredGroup = new EventBusTestFixture.GroupA();
- eventBus.register(listener, registeredGroup);
-
- String emptyRoutingKey = "";
- rabbitMQExtension.getSender()
- .send(Mono.just(new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME,
- emptyRoutingKey,
- "BAD_PAYLOAD!".getBytes(StandardCharsets.UTF_8))))
- .block();
-
- AtomicInteger deadLetteredCount = new AtomicInteger();
- rabbitMQExtension.getRabbitChannelPool()
- .createReceiver()
- .consumeAutoAck(MAILBOX_EVENT_DEAD_LETTER_QUEUE)
- .doOnNext(next -> deadLetteredCount.incrementAndGet())
- .subscribeOn(Schedulers.elastic())
- .subscribe();
-
- Awaitility.await().atMost(org.awaitility.Duration.TEN_SECONDS)
- .untilAsserted(() -> assertThat(deadLetteredCount.get()).isEqualTo(1));
- }
-
- @Test
- void registrationShouldNotCrashOnInvalidMessage() {
- EventCollector listener = new EventCollector();
- Mono.from(eventBus.register(listener, KEY_1)).block();
-
- rabbitMQExtension.getSender()
- .send(Mono.just(new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME,
- RoutingKey.of(KEY_1).asString(),
- "BAD_PAYLOAD!".getBytes(StandardCharsets.UTF_8))))
- .block();
-
- eventBus.dispatch(EVENT, KEY_1).block();
- await().timeout(org.awaitility.Duration.TEN_SECONDS)
- .untilAsserted(() -> assertThat(listener.getEvents()).containsOnly(EVENT));
- }
-
- @Test
- void registrationShouldNotCrashOnInvalidMessages() {
- EventCollector listener = new EventCollector();
- Mono.from(eventBus.register(listener, KEY_1)).block();
-
- IntStream.range(0, 100)
- .forEach(i -> rabbitMQExtension.getSender()
- .send(Mono.just(new OutboundMessage(MAILBOX_EVENT_EXCHANGE_NAME,
- RoutingKey.of(KEY_1).asString(),
- "BAD_PAYLOAD!".getBytes(StandardCharsets.UTF_8))))
- .block());
-
- eventBus.dispatch(EVENT, KEY_1).block();
- await().timeout(org.awaitility.Duration.TEN_SECONDS)
- .untilAsserted(() -> assertThat(listener.getEvents()).containsOnly(EVENT));
- }
-
- @Test
- void deserializeEventCollectorGroup() throws Exception {
- assertThat(Group.deserialize("org.apache.james.mailbox.util.EventCollector$EventCollectorGroup"))
- .isEqualTo(new EventCollector.EventCollectorGroup());
- }
-
- @Test
- void registerGroupShouldCreateRetryExchange() throws Exception {
- EventListener listener = newListener();
- EventBusTestFixture.GroupA registeredGroup = new EventBusTestFixture.GroupA();
- eventBus.register(listener, registeredGroup);
-
- GroupConsumerRetry.RetryExchangeName retryExchangeName = GroupConsumerRetry.RetryExchangeName.of(registeredGroup);
- assertThat(rabbitMQExtension.managementAPI().listExchanges())
- .anyMatch(exchange -> exchange.getName().equals(retryExchangeName.asString()));
- }
-
- @Nested
- class ConcurrentTest implements EventBusConcurrentTestContract.MultiEventBusConcurrentContract,
- EventBusConcurrentTestContract.SingleEventBusConcurrentContract {
-
- @Override
- public EnvironmentSpeedProfile getSpeedProfile() {
- return EnvironmentSpeedProfile.SLOW;
- }
-
- @Test
- void rabbitMQEventBusShouldHandleBulksGracefully() throws Exception {
- EventListenerCountingSuccessfulExecution countingListener1 = newCountingListener();
- eventBus().register(countingListener1, new EventBusTestFixture.GroupA());
- int totalGlobalRegistrations = 1; // GroupA
-
- int threadCount = 10;
- int operationCount = 10000;
- int totalDispatchOperations = threadCount * operationCount;
- eventBus = (RabbitMQEventBus) eventBus();
- ConcurrentTestRunner.builder()
- .operation((threadNumber, operationNumber) -> eventBus.dispatch(EVENT, NO_KEYS).block())
- .threadCount(threadCount)
- .operationCount(operationCount)
- .runSuccessfullyWithin(Duration.ofMinutes(3));
-
- await()
- .pollInterval(org.awaitility.Duration.FIVE_SECONDS)
- .timeout(org.awaitility.Duration.TEN_MINUTES).untilAsserted(() ->
- assertThat(countingListener1.numberOfEventCalls()).isEqualTo((totalGlobalRegistrations * totalDispatchOperations)));
- }
-
- @Override
- public EventBus eventBus3() {
- return eventBus3;
- }
-
- @Override
- public EventBus eventBus2() {
- return eventBus2;
- }
-
- @Override
- public EventBus eventBus() {
- return eventBus;
- }
- }
-
- @Nested
- class AtLeastOnceTest {
-
- @Test
- void inProcessingEventShouldBeReDispatchedToAnotherEventBusWhenOneIsDown() {
- EventListenerCountingSuccessfulExecution eventBusListener = spy(new EventListenerCountingSuccessfulExecution());
- EventListenerCountingSuccessfulExecution eventBus2Listener = spy(new EventListenerCountingSuccessfulExecution());
- EventListenerCountingSuccessfulExecution eventBus3Listener = spy(new EventListenerCountingSuccessfulExecution());
- Answer<?> callEventAndSleepForever = invocation -> {
- invocation.callRealMethod();
- TimeUnit.SECONDS.sleep(Long.MAX_VALUE);
- return null;
- };
-
- doAnswer(callEventAndSleepForever).when(eventBusListener).event(any());
- doAnswer(callEventAndSleepForever).when(eventBus2Listener).event(any());
-
- eventBus.register(eventBusListener, GROUP_A);
- eventBus2.register(eventBus2Listener, GROUP_A);
- eventBus3.register(eventBus3Listener, GROUP_A);
-
- eventBus.dispatch(EVENT, NO_KEYS).block();
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(eventBusListener.numberOfEventCalls()).isEqualTo(1));
- eventBus.stop();
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(eventBus2Listener.numberOfEventCalls()).isEqualTo(1));
- eventBus2.stop();
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(eventBus3Listener.numberOfEventCalls()).isEqualTo(1));
- }
- }
-
- @Nested
- class PublishingTest {
- private static final String MAILBOX_WORK_QUEUE_NAME = MAILBOX_EVENT + "-workQueue";
-
- @BeforeEach
- void setUp() {
- Sender sender = rabbitMQExtension.getSender();
-
- sender.declareQueue(QueueSpecification.queue(MAILBOX_WORK_QUEUE_NAME)
- .durable(DURABLE)
- .exclusive(!EXCLUSIVE)
- .autoDelete(!AUTO_DELETE)
- .arguments(NO_ARGUMENTS))
- .block();
- sender.bind(BindingSpecification.binding()
- .exchange(MAILBOX_EVENT_EXCHANGE_NAME)
- .queue(MAILBOX_WORK_QUEUE_NAME)
- .routingKey(EMPTY_ROUTING_KEY))
- .block();
- }
-
- @Test
- void dispatchShouldPublishSerializedEventToRabbitMQ() {
- eventBus.dispatch(EVENT, NO_KEYS).block();
-
- assertThat(dequeueEvent()).isEqualTo(EVENT);
- }
-
- @Test
- void dispatchShouldPublishSerializedEventToRabbitMQWhenNotBlocking() {
- eventBus.dispatch(EVENT, NO_KEYS).block();
-
- assertThat(dequeueEvent()).isEqualTo(EVENT);
- }
-
- private Event dequeueEvent() {
- try (Receiver receiver = rabbitMQExtension.getReceiverProvider().createReceiver()) {
- byte[] eventInBytes = receiver.consumeAutoAck(MAILBOX_WORK_QUEUE_NAME)
- .blockFirst()
- .getBody();
-
- return eventSerializer.fromJson(new String(eventInBytes, StandardCharsets.UTF_8))
- .get();
- }
- }
- }
-
- @Nested
- class LifeCycleTest {
- private static final int THREAD_COUNT = 10;
- private static final int OPERATION_COUNT = 100000;
-
- private RabbitMQManagementAPI rabbitManagementAPI;
-
- @BeforeEach
- void setUp() throws Exception {
- rabbitManagementAPI = rabbitMQExtension.managementAPI();
- }
-
- @AfterEach
- void tearDown() {
- rabbitMQExtension.getRabbitMQ().unpause();
- }
-
- @Nested
- class SingleEventBus {
-
- @Nested
- class DispatchingWhenNetWorkIssue {
-
- @RegisterExtension
- RabbitMQExtension rabbitMQNetWorkIssueExtension = RabbitMQExtension.defaultRabbitMQ()
- .restartPolicy(DockerRestartPolicy.PER_TEST)
- .isolationPolicy(RabbitMQExtension.IsolationPolicy.WEAK);
-
- private RabbitMQEventBus rabbitMQEventBusWithNetWorkIssue;
-
- @BeforeEach
- void beforeEach() {
- rabbitMQEventBusWithNetWorkIssue = newEventBus(rabbitMQNetWorkIssueExtension.getSender(), rabbitMQNetWorkIssueExtension.getReceiverProvider());
- }
-
- @Test
- void dispatchShouldWorkAfterNetworkIssuesForOldRegistrationAndKey() {
- rabbitMQEventBusWithNetWorkIssue.start();
- EventListener listener = newListener();
- Mono.from(rabbitMQEventBusWithNetWorkIssue.register(listener, KEY_1)).block();
-
- rabbitMQNetWorkIssueExtension.getRabbitMQ().pause();
-
- assertThatThrownBy(() -> rabbitMQEventBusWithNetWorkIssue.dispatch(EVENT, NO_KEYS).block())
- .isInstanceOf(IllegalStateException.class)
- .hasMessageContaining("Retries exhausted");
-
- rabbitMQNetWorkIssueExtension.getRabbitMQ().unpause();
-
- rabbitMQEventBusWithNetWorkIssue.dispatch(EVENT, ImmutableSet.of(KEY_1)).block();
- assertThatListenerReceiveOneEvent(listener);
- }
- }
-
- @Test
- void startShouldCreateEventExchange() {
- eventBus.start();
- assertThat(rabbitManagementAPI.listExchanges())
- .filteredOn(exchange -> exchange.getName().equals(MAILBOX_EVENT_EXCHANGE_NAME))
- .hasOnlyOneElementSatisfying(exchange -> {
- assertThat(exchange.isDurable()).isTrue();
- assertThat(exchange.getType()).isEqualTo(DIRECT_EXCHANGE);
- });
- }
-
- @Test
- void dispatchShouldWorkAfterRestartForOldRegistration() throws Exception {
- eventBus.start();
- EventListener listener = newListener();
- eventBus.register(listener, GROUP_A);
-
- rabbitMQExtension.getRabbitMQ().restart();
-
- eventBus.dispatch(EVENT, NO_KEYS).block();
- assertThatListenerReceiveOneEvent(listener);
- }
-
- @Test
- void dispatchShouldWorkAfterRestartForNewRegistration() throws Exception {
- eventBus.start();
- EventListener listener = newListener();
-
- rabbitMQExtension.getRabbitMQ().restart();
-
- eventBus.register(listener, GROUP_A);
-
- eventBus.dispatch(EVENT, NO_KEYS).block();
-
- assertThatListenerReceiveOneEvent(listener);
-
- }
-
- @Test
- void redeliverShouldWorkAfterRestartForOldRegistration() throws Exception {
- eventBus.start();
- EventListener listener = newListener();
- eventBus.register(listener, GROUP_A);
-
- rabbitMQExtension.getRabbitMQ().restart();
-
- eventBus.reDeliver(GROUP_A, EVENT).block();
- assertThatListenerReceiveOneEvent(listener);
- }
-
- @Test
- void redeliverShouldWorkAfterRestartForNewRegistration() throws Exception {
- eventBus.start();
- EventListener listener = newListener();
-
- rabbitMQExtension.getRabbitMQ().restart();
-
- eventBus.register(listener, GROUP_A);
-
- eventBus.reDeliver(GROUP_A, EVENT).block();
- assertThatListenerReceiveOneEvent(listener);
- }
-
- @Test
- void dispatchShouldWorkAfterRestartForOldKeyRegistration() throws Exception {
- eventBus.start();
- EventListener listener = newListener();
- Mono.from(eventBus.register(listener, KEY_1)).block();
-
- rabbitMQExtension.getRabbitMQ().restart();
-
- eventBus.dispatch(EVENT, KEY_1).block();
- assertThatListenerReceiveOneEvent(listener);
- }
-
- @Test
- void dispatchedMessagesShouldSurviveARabbitMQRestart() throws Exception {
- eventBusWithKeyHandlerNotStarted.startWithoutStartingKeyRegistrationHandler();
- EventListener listener = newAsyncListener();
- Mono.from(eventBusWithKeyHandlerNotStarted.register(listener, KEY_1)).block();
- Mono<Void> dispatch = eventBusWithKeyHandlerNotStarted.dispatch(EVENT, KEY_1);
- dispatch.block();
-
- rabbitMQExtension.getRabbitMQ().restart();
-
- eventBusWithKeyHandlerNotStarted.startKeyRegistrationHandler();
-
- assertThatListenerReceiveOneEvent(listener);
- }
-
- @Disabled("JAMES-3083 Disable this unstable test")
- @Test
- void dispatchShouldWorkAfterRestartForNewKeyRegistration() throws Exception {
- eventBus.start();
- EventListener listener = newListener();
-
- rabbitMQExtension.getRabbitMQ().restart();
-
- Mono.from(eventBus.register(listener, KEY_1)).block();
-
- eventBus.dispatch(EVENT, KEY_1).block();
- assertThatListenerReceiveOneEvent(listener);
- }
-
- @Test
- void dispatchShouldWorkAfterNetworkIssuesForNewRegistration() {
- eventBus.start();
- EventListener listener = newListener();
-
- rabbitMQExtension.getRabbitMQ().pause();
-
- assertThatThrownBy(() -> eventBus.dispatch(EVENT, NO_KEYS).block())
- .isInstanceOf(IllegalStateException.class)
- .hasMessageContaining("Retries exhausted");
-
- rabbitMQExtension.getRabbitMQ().unpause();
-
- eventBus.register(listener, GROUP_A);
- eventBus.dispatch(EVENT, NO_KEYS).block();
- assertThatListenerReceiveOneEvent(listener);
- }
-
- @Test
- void redeliverShouldWorkAfterNetworkIssuesForNewRegistration() {
- eventBus.start();
- EventListener listener = newListener();
-
- rabbitMQExtension.getRabbitMQ().pause();
-
- assertThatThrownBy(() -> eventBus.reDeliver(GROUP_A, EVENT).block())
- .isInstanceOf(GroupRegistrationNotFound.class);
-
- rabbitMQExtension.getRabbitMQ().unpause();
-
- eventBus.register(listener, GROUP_A);
- eventBus.reDeliver(GROUP_A, EVENT).block();
- assertThatListenerReceiveOneEvent(listener);
- }
-
- @Test
- void dispatchShouldWorkAfterNetworkIssuesForOldKeyRegistration() {
- eventBus.start();
- EventListener listener = newListener();
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
- Mono.from(eventBus.register(listener, KEY_1)).block();
-
- rabbitMQExtension.getRabbitMQ().pause();
-
- assertThatThrownBy(() -> eventBus.dispatch(EVENT, NO_KEYS).block())
- .isInstanceOf(IllegalStateException.class)
- .hasMessageContaining("Retries exhausted");
-
- rabbitMQExtension.getRabbitMQ().unpause();
-
- eventBus.dispatch(EVENT, KEY_1).block();
- assertThatListenerReceiveOneEvent(listener);
- }
-
- @Test
- void dispatchShouldWorkAfterNetworkIssuesForNewKeyRegistration() {
- eventBus.start();
- EventListener listener = newListener();
- when(listener.getExecutionMode()).thenReturn(EventListener.ExecutionMode.ASYNCHRONOUS);
-
- rabbitMQExtension.getRabbitMQ().pause();
-
- assertThatThrownBy(() -> eventBus.dispatch(EVENT, NO_KEYS).block())
- .isInstanceOf(IllegalStateException.class)
- .hasMessageContaining("Retries exhausted");
-
- rabbitMQExtension.getRabbitMQ().unpause();
-
- Mono.from(eventBus.register(listener, KEY_1)).block();
- eventBus.dispatch(EVENT, KEY_1).block();
- assertThatListenerReceiveOneEvent(listener);
- }
-
- @Test
- void stopShouldNotDeleteEventBusExchange() {
- eventBus.start();
- eventBus.stop();
-
- assertThat(rabbitManagementAPI.listExchanges())
- .anySatisfy(exchange -> assertThat(exchange.getName()).isEqualTo(MAILBOX_EVENT_EXCHANGE_NAME));
- }
-
- @Test
- void stopShouldNotDeleteGroupRegistrationWorkQueue() {
- eventBus.start();
- eventBus.register(mock(EventListener.class), GROUP_A);
- eventBus.stop();
-
- assertThat(rabbitManagementAPI.listQueues())
- .anySatisfy(queue -> assertThat(queue.getName()).contains(GroupA.class.getName()));
- }
-
- @Test
- void eventBusShouldNotThrowWhenContinuouslyStartAndStop() {
- assertThatCode(() -> {
- eventBus.start();
- eventBus.stop();
- eventBus.stop();
- eventBus.start();
- eventBus.start();
- eventBus.start();
- eventBus.stop();
- eventBus.stop();
- }).doesNotThrowAnyException();
- }
-
- @Test
- void dispatchShouldStopDeliveringEventsShortlyAfterStopIsCalled() throws Exception {
- eventBus.start();
-
- EventListenerCountingSuccessfulExecution listener = new EventListenerCountingSuccessfulExecution();
- eventBus.register(listener, GROUP_A);
-
- try (Closeable closeable = ConcurrentTestRunner.builder()
- .operation((threadNumber, step) -> eventBus.dispatch(EVENT, KEY_1).block())
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .noErrorLogs()
- .run()) {
-
- TimeUnit.SECONDS.sleep(2);
-
- eventBus.stop();
- eventBus2.stop();
- int callsAfterStop = listener.numberOfEventCalls();
-
- TimeUnit.SECONDS.sleep(1);
- assertThat(listener.numberOfEventCalls())
- .isCloseTo(callsAfterStop, Percentage.withPercentage(2));
- }
- }
- }
-
- @Nested
- class MultiEventBus {
-
- @Test
- void multipleEventBusStartShouldCreateOnlyOneEventExchange() {
- assertThat(rabbitManagementAPI.listExchanges())
- .filteredOn(exchange -> exchange.getName().equals(MAILBOX_EVENT_EXCHANGE_NAME))
- .hasSize(1);
- }
-
- @Test
- void multipleEventBusShouldNotThrowWhenStartAndStopContinuously() {
- assertThatCode(() -> {
- eventBus.start();
- eventBus.start();
- eventBus2.start();
- eventBus2.start();
- eventBus.stop();
- eventBus.stop();
- eventBus.stop();
- eventBus3.start();
- eventBus3.start();
- eventBus3.start();
- eventBus3.stop();
- eventBus.start();
- eventBus2.start();
- eventBus.stop();
- eventBus2.stop();
- }).doesNotThrowAnyException();
- }
-
- @Test
- void multipleEventBusStopShouldNotDeleteEventBusExchange() {
- eventBus.stop();
- eventBus2.stop();
- eventBus3.stop();
- eventBusWithKeyHandlerNotStarted.stop();
-
- assertThat(rabbitManagementAPI.listExchanges())
- .anySatisfy(exchange -> assertThat(exchange.getName()).isEqualTo(MAILBOX_EVENT_EXCHANGE_NAME));
- }
-
- @Test
- void multipleEventBusStopShouldNotDeleteGroupRegistrationWorkQueue() {
- eventBus.register(mock(EventListener.class), GROUP_A);
-
- eventBus.stop();
- eventBus2.stop();
- eventBus3.stop();
- eventBusWithKeyHandlerNotStarted.stop();
-
- assertThat(rabbitManagementAPI.listQueues())
- .anySatisfy(queue -> assertThat(queue.getName()).contains(GroupA.class.getName()));
- }
-
- @Test
- void multipleEventBusStopShouldDeleteAllKeyRegistrationsWorkQueue() {
- eventBus.stop();
- eventBus2.stop();
- eventBus3.stop();
- eventBusWithKeyHandlerNotStarted.stop();
-
- assertThat(rabbitManagementAPI.listQueues())
- .filteredOn(queue -> !queue.getName().startsWith(MAILBOX_EVENT_WORK_QUEUE_PREFIX)
- && !queue.getName().startsWith(MAILBOX_EVENT_DEAD_LETTER_QUEUE))
- .isEmpty();
- }
-
- @Test
- void dispatchShouldStopDeliveringEventsShortlyAfterStopIsCalled() throws Exception {
- eventBus.start();
- eventBus2.start();
-
- EventListenerCountingSuccessfulExecution listener = new EventListenerCountingSuccessfulExecution();
- eventBus.register(listener, GROUP_A);
- eventBus2.register(listener, GROUP_A);
-
- try (Closeable closeable = ConcurrentTestRunner.builder()
- .operation((threadNumber, step) -> eventBus.dispatch(EVENT, KEY_1).block())
- .threadCount(THREAD_COUNT)
- .operationCount(OPERATION_COUNT)
- .noErrorLogs()
- .run()) {
-
- TimeUnit.SECONDS.sleep(2);
-
- eventBus.stop();
- eventBus2.stop();
- int callsAfterStop = listener.numberOfEventCalls();
-
- TimeUnit.SECONDS.sleep(1);
- assertThat(listener.numberOfEventCalls())
- .isCloseTo(callsAfterStop, Percentage.withPercentage(2));
- }
- }
- }
-
- }
-
- @Nested
- class ErrorDispatchingTest {
-
- @AfterEach
- void tearDown() {
- rabbitMQExtension.getRabbitMQ().unpause();
- }
-
- @Test
- void dispatchShouldNotSendToGroupListenerWhenError() {
- EventCollector eventCollector = eventCollector();
- eventBus().register(eventCollector, GROUP_A);
-
- rabbitMQExtension.getRabbitMQ().pause();
-
- doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
- assertThat(eventCollector.getEvents()).isEmpty();
- }
-
- @Test
- void dispatchShouldPersistEventWhenDispatchingNoKeyGetError() {
- EventCollector eventCollector = eventCollector();
- eventBus().register(eventCollector, GROUP_A);
-
- rabbitMQExtension.getRabbitMQ().pause();
-
- doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
- assertThat(dispatchingFailureEvents()).containsOnly(EVENT);
- }
-
- @Test
- void dispatchShouldPersistEventWhenDispatchingWithKeysGetError() {
- EventCollector eventCollector = eventCollector();
- eventBus().register(eventCollector, GROUP_A);
- Mono.from(eventBus().register(eventCollector, KEY_1)).block();
-
- rabbitMQExtension.getRabbitMQ().pause();
-
- doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
- assertThat(dispatchingFailureEvents()).containsOnly(EVENT);
- }
-
- @Test
- void dispatchShouldPersistOnlyOneEventWhenDispatchingMultiGroupsGetError() {
- EventCollector eventCollector = eventCollector();
- eventBus().register(eventCollector, GROUP_A);
- eventBus().register(eventCollector, GROUP_B);
-
- rabbitMQExtension.getRabbitMQ().pause();
-
- doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
- assertThat(dispatchingFailureEvents()).containsOnly(EVENT);
- }
-
- @Test
- void dispatchShouldPersistEventsWhenDispatchingGroupsGetErrorMultipleTimes() {
- EventCollector eventCollector = eventCollector();
- eventBus().register(eventCollector, GROUP_A);
-
- rabbitMQExtension.getRabbitMQ().pause();
- doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
- doQuietly(() -> eventBus().dispatch(EVENT_2, NO_KEYS).block());
-
- assertThat(dispatchingFailureEvents()).containsExactly(EVENT, EVENT_2);
- }
-
- @Test
- void dispatchShouldPersistEventsWhenDispatchingTheSameEventGetErrorMultipleTimes() {
- EventCollector eventCollector = eventCollector();
- eventBus().register(eventCollector, GROUP_A);
-
- rabbitMQExtension.getRabbitMQ().pause();
- doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
- doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
-
- assertThat(dispatchingFailureEvents()).containsExactly(EVENT, EVENT);
- }
-
- @Test
- void reDeliverShouldDeliverToAllGroupsWhenDispatchingFailure() {
- EventCollector eventCollector = eventCollector();
- eventBus().register(eventCollector, GROUP_A);
-
- EventCollector eventCollector2 = eventCollector();
- eventBus().register(eventCollector2, GROUP_B);
-
- rabbitMQExtension.getRabbitMQ().pause();
- doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
- rabbitMQExtension.getRabbitMQ().unpause();
- dispatchingFailureEvents()
- .forEach(event -> eventBus().reDeliver(DispatchingFailureGroup.INSTANCE, event).block());
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(eventCollector.getEvents())
- .hasSameElementsAs(eventCollector2.getEvents())
- .containsExactly(EVENT));
- }
-
- @Test
- void reDeliverShouldAddEventInDeadLetterWhenGettingError() {
- EventCollector eventCollector = eventCollector();
- eventBus().register(eventCollector, GROUP_A);
-
- rabbitMQExtension.getRabbitMQ().pause();
- doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
- getSpeedProfile().longWaitCondition()
- .until(() -> deadLetter().containEvents().block());
-
- doQuietly(() -> eventBus().reDeliver(DispatchingFailureGroup.INSTANCE, EVENT).block());
- rabbitMQExtension.getRabbitMQ().unpause();
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(dispatchingFailureEvents())
- .containsExactly(EVENT, EVENT));
- }
-
- @Test
- void reDeliverShouldNotStoreEventInAnotherGroupWhenGettingError() {
- EventCollector eventCollector = eventCollector();
- eventBus().register(eventCollector, GROUP_A);
-
- rabbitMQExtension.getRabbitMQ().pause();
- doQuietly(() -> eventBus().dispatch(EVENT, NO_KEYS).block());
- getSpeedProfile().longWaitCondition()
- .until(() -> deadLetter().containEvents().block());
-
- doQuietly(() -> eventBus().reDeliver(DispatchingFailureGroup.INSTANCE, EVENT).block());
- rabbitMQExtension.getRabbitMQ().unpause();
-
- getSpeedProfile().shortWaitCondition()
- .untilAsserted(() -> assertThat(deadLetter().groupsWithFailedEvents().toStream())
- .hasOnlyElementsOfType(DispatchingFailureGroup.class));
- }
-
- private Stream<Event> dispatchingFailureEvents() {
- return deadLetter().failedIds(DispatchingFailureGroup.INSTANCE)
- .flatMap(insertionId -> deadLetter().failedEvent(DispatchingFailureGroup.INSTANCE, insertionId))
- .toStream();
- }
-
- private void doQuietly(Runnable runnable) {
- try {
- runnable.run();
- } catch (Exception e) {
- // ignore
- }
- }
- }
-
- private void assertThatListenerReceiveOneEvent(EventListener listener) {
- RabbitMQFixture.awaitAtMostThirtySeconds
- .untilAsserted(() -> verify(listener).event(EVENT));
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RoutingKeyConverterTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RoutingKeyConverterTest.java
deleted file mode 100644
index 9fb93dc..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/RoutingKeyConverterTest.java
+++ /dev/null
@@ -1,144 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.util.Objects;
-
-import org.apache.james.events.RegistrationKey;
-import org.apache.james.mailbox.model.TestId;
-import org.junit.jupiter.api.Test;
-
-class RoutingKeyConverterTest {
- static class TestRegistrationKey implements RegistrationKey {
- static class Factory implements RegistrationKey.Factory {
- @Override
- public Class<? extends RegistrationKey> forClass() {
- return TestRegistrationKey.class;
- }
-
- @Override
- public RegistrationKey fromString(String asString) {
- return new TestRegistrationKey(asString);
- }
- }
-
- private final String value;
-
- TestRegistrationKey(String value) {
- this.value = value;
- }
-
- @Override
- public String asString() {
- return value;
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o instanceof TestRegistrationKey) {
- TestRegistrationKey that = (TestRegistrationKey) o;
-
- return Objects.equals(this.value, that.value);
- }
- return false;
- }
-
- @Override
- public final int hashCode() {
- return Objects.hash(value);
- }
- }
-
- private static final RegistrationKey REGISTRATION_KEY_1 = new MailboxIdRegistrationKey(TestId.of(42));
- private static final String ROUTING_KEY_1 = "org.apache.james.mailbox.events.MailboxIdRegistrationKey:42";
-
- private RoutingKeyConverter testee = RoutingKeyConverter.forFactories(
- new TestRegistrationKey.Factory(),
- new MailboxIdRegistrationKey.Factory(new TestId.Factory()));
-
- @Test
- void toRoutingKeyShouldTransformAKeyIntoAString() {
- assertThat(RoutingKeyConverter.RoutingKey.of(REGISTRATION_KEY_1).asString())
- .isEqualTo(ROUTING_KEY_1);
- }
-
- @Test
- void toRegistrationKeyShouldReturnCorrespondingRoutingKey() {
- assertThat(testee.toRegistrationKey(ROUTING_KEY_1))
- .isEqualTo(REGISTRATION_KEY_1);
- }
-
- @Test
- void toRoutingKeyShouldAcceptSeparator() {
- assertThat(RoutingKeyConverter.RoutingKey.of(new TestRegistrationKey("a:b")).asString())
- .isEqualTo("org.apache.james.mailbox.events.RoutingKeyConverterTest$TestRegistrationKey:a:b");
- }
-
- @Test
- void toRegistrationKeyShouldAcceptSeparator() {
- assertThat(testee.toRegistrationKey("org.apache.james.mailbox.events.RoutingKeyConverterTest$TestRegistrationKey:a:b"))
- .isEqualTo(new TestRegistrationKey("a:b"));
- }
-
- @Test
- void toRoutingKeyShouldAcceptEmptyValue() {
- assertThat(RoutingKeyConverter.RoutingKey.of(new TestRegistrationKey("")).asString())
- .isEqualTo("org.apache.james.mailbox.events.RoutingKeyConverterTest$TestRegistrationKey:");
- }
-
- @Test
- void toRegistrationKeyShouldAcceptEmptyValue() {
- assertThat(testee.toRegistrationKey("org.apache.james.mailbox.events.RoutingKeyConverterTest$TestRegistrationKey:"))
- .isEqualTo(new TestRegistrationKey(""));
- }
-
- @Test
- void toRegistrationKeyShouldRejectNull() {
- assertThatThrownBy(() -> testee.toRegistrationKey(null))
- .isInstanceOf(NullPointerException.class);
- }
-
- @Test
- void toRegistrationKeyShouldRejectEmptyString() {
- assertThatThrownBy(() -> testee.toRegistrationKey(""))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- void toRegistrationKeyShouldRejectNoSeparator() {
- assertThatThrownBy(() -> testee.toRegistrationKey("noSeparator"))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- void toRegistrationKeyShouldRejectUnknownRegistrationKeyClass() {
- assertThatThrownBy(() -> testee.toRegistrationKey("unknown:"))
- .isInstanceOf(IllegalArgumentException.class);
- }
-
- @Test
- void toRegistrationKeyShouldRejectInvalidValue() {
- assertThatThrownBy(() -> testee.toRegistrationKey("org.apache.james.mailbox.events.MailboxIdRegistrationKey:invalid"))
- .isInstanceOf(IllegalArgumentException.class);
- }
-}
diff --git a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/WaitDelayGeneratorTest.java b/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/WaitDelayGeneratorTest.java
deleted file mode 100644
index e7f1fb6..0000000
--- a/mailbox/event/event-rabbitmq/src/test/java/org/apache/james/mailbox/events/WaitDelayGeneratorTest.java
+++ /dev/null
@@ -1,103 +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.mailbox.events;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.time.Duration;
-
-import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.Test;
-
-class WaitDelayGeneratorTest {
-
- @Test
- void generateDelayShouldReturnZeroWhenZeroRetryCount() {
- WaitDelayGenerator generator = WaitDelayGenerator.of(RetryBackoffConfiguration.DEFAULT);
-
- assertThat(generator.generateDelay(0))
- .isEqualTo(Duration.ofMillis(0));
- }
-
- @Test
- void generateDelayShouldReturnByRandomInRangeOfExponentialGrowthOfRetryCount() {
- WaitDelayGenerator generator = WaitDelayGenerator.of(RetryBackoffConfiguration.builder()
- .maxRetries(4)
- .firstBackoff(Duration.ofMillis(100))
- .jitterFactor(0.5)
- .build());
-
- SoftAssertions.assertSoftly(softly -> {
- softly.assertThat(generator.generateDelay(1).toMillis())
- .isBetween(50L, 150L);
- softly.assertThat(generator.generateDelay(2).toMillis())
- .isBetween(100L, 300L);
- softly.assertThat(generator.generateDelay(3).toMillis())
- .isBetween(200L, 600L);
- softly.assertThat(generator.generateDelay(4).toMillis())
- .isBetween(300L, 1200L);
- });
- }
-
- @Test
- void generateDelayShouldReturnZeroWhenZeroMaxRetries() {
- WaitDelayGenerator generator = WaitDelayGenerator.of(RetryBackoffConfiguration.builder()
- .maxRetries(0)
- .firstBackoff(Duration.ofMillis(1000))
- .jitterFactor(0.5)
- .build());
-
- SoftAssertions.assertSoftly(softly -> {
- softly.assertThat(generator.generateDelay(1)).isEqualTo(Duration.ZERO);
- softly.assertThat(generator.generateDelay(2)).isEqualTo(Duration.ZERO);
- softly.assertThat(generator.generateDelay(3)).isEqualTo(Duration.ZERO);
- });
- }
-
- @Test
- void generateDelayShouldReturnZeroWhenZeroFirstBackOff() {
- WaitDelayGenerator generator = WaitDelayGenerator.of(RetryBackoffConfiguration.builder()
- .maxRetries(3)
- .firstBackoff(Duration.ZERO)
- .jitterFactor(0.5)
- .build());
-
- SoftAssertions.assertSoftly(softly -> {
- softly.assertThat(generator.generateDelay(1)).isEqualTo(Duration.ZERO);
- softly.assertThat(generator.generateDelay(2)).isEqualTo(Duration.ZERO);
- softly.assertThat(generator.generateDelay(3)).isEqualTo(Duration.ZERO);
- });
- }
-
- @Test
- void generateDelayShouldReturnFloorOfExponentialGrowthStepsWhenZeroJitterFactor() {
- WaitDelayGenerator generator = WaitDelayGenerator.of(RetryBackoffConfiguration.builder()
- .maxRetries(3)
- .firstBackoff(Duration.ofMillis(100))
- .jitterFactor(0.0)
- .build());
-
- SoftAssertions.assertSoftly(softly -> {
- softly.assertThat(generator.generateDelay(1)).isEqualTo(Duration.ofMillis(100));
- softly.assertThat(generator.generateDelay(2)).isEqualTo(Duration.ofMillis(200));
- softly.assertThat(generator.generateDelay(3)).isEqualTo(Duration.ofMillis(400));
- });
- }
-}
\ No newline at end of file
diff --git a/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala b/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
index fa7c110..6708055 100644
--- a/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
+++ b/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
@@ -30,9 +30,9 @@ import org.apache.james.event.json.DTOs.SystemFlag.SystemFlag
import org.apache.james.event.json.DTOs._
import org.apache.james.events
import org.apache.james.events.Event.EventId
+import org.apache.james.events.MailboxEvents.{Added => JavaAdded, Expunged => JavaExpunged, FlagsUpdated => JavaFlagsUpdated, MailboxACLUpdated => JavaMailboxACLUpdated, MailboxAdded => JavaMailboxAdded, MailboxDeletion => JavaMailboxDeletion, MailboxRenamed => JavaMailboxRenamed, QuotaUsageUpdatedEvent => JavaQuotaUsageUpdatedEvent}
+import org.apache.james.events.MessageMoveEvent
import org.apache.james.mailbox.MailboxSession.SessionId
-import org.apache.james.mailbox.events.MailboxEvents.{Added => JavaAdded, Expunged => JavaExpunged, FlagsUpdated => JavaFlagsUpdated, MailboxACLUpdated => JavaMailboxACLUpdated, MailboxAdded => JavaMailboxAdded, MailboxDeletion => JavaMailboxDeletion, MailboxRenamed => JavaMailboxRenamed, QuotaUsageUpdatedEvent => JavaQuotaUsageUpdatedEvent}
-import org.apache.james.mailbox.events.{MessageMoveEvent => JavaMessageMoveEvent}
import org.apache.james.mailbox.model.{MailboxId, MessageId, MessageMoves, QuotaRoot, MailboxACL => JavaMailboxACL, MessageMetaData => JavaMessageMetaData, Quota => JavaQuota}
import org.apache.james.mailbox.quota.QuotaRootDeserializer
import org.apache.james.mailbox.{MessageUid, ModSeq}
@@ -174,7 +174,7 @@ private object ScalaConverter {
mailboxId = event.getMailboxId,
expunged = event.getExpunged.asScala.view.mapValues(DTOs.MessageMetaData.fromJava).toMap)
- private def toScala(event: JavaMessageMoveEvent): DTO.MessageMoveEvent = DTO.MessageMoveEvent(
+ private def toScala(event: MessageMoveEvent): DTO.MessageMoveEvent = DTO.MessageMoveEvent(
eventId = event.getEventId,
user = event.getUsername,
previousMailboxIds = event.getMessageMoves.getPreviousMailboxIds.asScala.toSet,
@@ -197,7 +197,7 @@ private object ScalaConverter {
case e: JavaMailboxAdded => toScala(e)
case e: JavaMailboxDeletion => toScala(e)
case e: JavaMailboxRenamed => toScala(e)
- case e: JavaMessageMoveEvent => toScala(e)
+ case e: MessageMoveEvent => toScala(e)
case e: JavaQuotaUsageUpdatedEvent => toScala(e)
case _ => throw new RuntimeException("no Scala conversion known")
}
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java
index 7477cad..2f9c48a 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/AddedSerializationTest.java
@@ -33,11 +33,11 @@ import java.util.SortedMap;
import javax.mail.Flags;
import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.Added;
import org.apache.james.mailbox.FlagsBuilder;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
-import org.apache.james.mailbox.events.MailboxEvents.Added;
import org.apache.james.mailbox.model.MailboxConstants;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java
index 866f241..ab5bd33 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/ExpungedSerializationTest.java
@@ -33,11 +33,11 @@ import java.util.NoSuchElementException;
import javax.mail.Flags;
import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.Expunged;
import org.apache.james.mailbox.FlagsBuilder;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
-import org.apache.james.mailbox.events.MailboxEvents.Expunged;
import org.apache.james.mailbox.model.MailboxConstants;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java
index d90e7df..2e5fbf1 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/FlagsUpdatedSerializationTest.java
@@ -31,11 +31,11 @@ import java.util.NoSuchElementException;
import javax.mail.Flags;
import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.FlagsUpdated;
import org.apache.james.mailbox.FlagsBuilder;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
-import org.apache.james.mailbox.events.MailboxEvents.FlagsUpdated;
import org.apache.james.mailbox.model.MailboxConstants;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java
index e957e53..20e1888 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxACLUpdatedEventSerializationTest.java
@@ -28,9 +28,9 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.NoSuchElementException;
import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.MailboxACLUpdated;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.acl.ACLDiff;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxACLUpdated;
import org.apache.james.mailbox.model.MailboxACL;
import org.apache.james.mailbox.model.MailboxConstants;
import org.apache.james.mailbox.model.MailboxPath;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java
index 1063d2f..6ebc085 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxAddedSerializationTest.java
@@ -28,8 +28,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.NoSuchElementException;
import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.MailboxAdded;
import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxAdded;
import org.apache.james.mailbox.model.MailboxConstants;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.TestId;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java
index 99f7072..4ee6d75 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxDeletionSerializationTest.java
@@ -34,8 +34,8 @@ import org.apache.james.core.Domain;
import org.apache.james.core.Username;
import org.apache.james.core.quota.QuotaCountUsage;
import org.apache.james.core.quota.QuotaSizeUsage;
+import org.apache.james.events.MailboxEvents.MailboxDeletion;
import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxDeletion;
import org.apache.james.mailbox.model.MailboxACL;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java
index 18e55d4..9f48940 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MailboxRenamedSerializationTest.java
@@ -29,8 +29,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.NoSuchElementException;
import org.apache.james.core.Username;
+import org.apache.james.events.MailboxEvents.MailboxRenamed;
import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.MailboxEvents.MailboxRenamed;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.TestId;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java
index b24bc93..9a74194 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/MessageMoveEventSerializationTest.java
@@ -29,7 +29,7 @@ import java.util.NoSuchElementException;
import org.apache.james.core.Username;
import org.apache.james.events.Event;
-import org.apache.james.mailbox.events.MessageMoveEvent;
+import org.apache.james.events.MessageMoveEvent;
import org.apache.james.mailbox.model.MessageMoves;
import org.apache.james.mailbox.model.TestId;
import org.apache.james.mailbox.model.TestMessageId;
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java
index 7991349..0295738 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java
@@ -34,7 +34,7 @@ import org.apache.james.core.quota.QuotaCountLimit;
import org.apache.james.core.quota.QuotaCountUsage;
import org.apache.james.core.quota.QuotaSizeLimit;
import org.apache.james.core.quota.QuotaSizeUsage;
-import org.apache.james.mailbox.events.MailboxEvents.QuotaUsageUpdatedEvent;
+import org.apache.james.events.MailboxEvents.QuotaUsageUpdatedEvent;
import org.apache.james.mailbox.model.Quota;
import org.apache.james.mailbox.model.QuotaRoot;
import org.junit.jupiter.api.Test;
diff --git a/mailbox/jpa/pom.xml b/mailbox/jpa/pom.xml
index 6183cc6..a063405 100644
--- a/mailbox/jpa/pom.xml
+++ b/mailbox/jpa/pom.xml
@@ -54,11 +54,6 @@
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
- <artifactId>apache-james-mailbox-event-memory</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>${james.groupId}</groupId>
<artifactId>apache-james-mailbox-store</artifactId>
</dependency>
<dependency>
@@ -80,6 +75,11 @@
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
+ <artifactId>event-bus-in-vm</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
<artifactId>james-server-data-jpa</artifactId>
<scope>test</scope>
</dependency>
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java
index 79a6cb1..c7f5738 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JpaMailboxManagerProvider.java
@@ -22,16 +22,16 @@ package org.apache.james.mailbox.jpa;
import javax.persistence.EntityManagerFactory;
import org.apache.james.backends.jpa.JpaTestCluster;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.Authenticator;
import org.apache.james.mailbox.Authorizator;
import org.apache.james.mailbox.acl.GroupMembershipResolver;
import org.apache.james.mailbox.acl.MailboxACLResolver;
import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.jpa.mail.JPAModSeqProvider;
import org.apache.james.mailbox.jpa.mail.JPAUidProvider;
import org.apache.james.mailbox.jpa.openjpa.OpenJPAMailboxManager;
diff --git a/mailbox/lucene/pom.xml b/mailbox/lucene/pom.xml
index caeceb3..bc59f6a 100644
--- a/mailbox/lucene/pom.xml
+++ b/mailbox/lucene/pom.xml
@@ -44,11 +44,6 @@
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
- <artifactId>apache-james-mailbox-event-memory</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>${james.groupId}</groupId>
<artifactId>apache-james-mailbox-memory</artifactId>
<scope>test</scope>
</dependency>
@@ -70,6 +65,11 @@
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
+ <artifactId>event-bus-in-vm</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${james.groupId}</groupId>
<artifactId>metrics-tests</artifactId>
<scope>test</scope>
</dependency>
diff --git a/mailbox/maildir/pom.xml b/mailbox/maildir/pom.xml
index 29cd01c..562dcca 100644
--- a/mailbox/maildir/pom.xml
+++ b/mailbox/maildir/pom.xml
@@ -44,12 +44,12 @@
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
- <artifactId>apache-james-mailbox-event-memory</artifactId>
- <scope>test</scope>
+ <artifactId>apache-james-mailbox-store</artifactId>
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
- <artifactId>apache-james-mailbox-store</artifactId>
+ <artifactId>event-bus-in-vm</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>${james.groupId}</groupId>
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java
index c68f597..6a90c97 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/MaildirMailboxManagerProvider.java
@@ -21,16 +21,16 @@ package org.apache.james.mailbox.maildir;
import java.io.File;
+import org.apache.james.events.EventBusTestFixture;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.Authenticator;
import org.apache.james.mailbox.Authorizator;
import org.apache.james.mailbox.acl.GroupMembershipResolver;
import org.apache.james.mailbox.acl.MailboxACLResolver;
import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
-import org.apache.james.mailbox.events.EventBusTestFixture;
-import org.apache.james.mailbox.events.InVMEventBus;
-import org.apache.james.mailbox.events.MemoryEventDeadLetters;
-import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.store.JVMMailboxPathLocker;
import org.apache.james.mailbox.store.MailboxManagerConfiguration;
import org.apache.james.mailbox.store.PreDeletionHooks;
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 bc172a8..10cf638 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
@@ -24,7 +24,11 @@ import java.util.Optional;
import java.util.function.Function;
import org.apache.james.events.EventBus;
+import org.apache.james.events.EventBusTestFixture;
import org.apache.james.events.EventListener;
+import org.apache.james.events.InVMEventBus;
+import org.apache.james.events.MemoryEventDeadLetters;
+import org.apache.james.events.delivery.InVmEventDelivery;
import org.apache.james.mailbox.AttachmentContentLoader;
... 1361 lines suppressed ...
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org