You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2021/01/19 07:34:28 UTC

[james-project] 02/02: JAMES-3471 Refactor and generify the Factory for handling events with MailboxChange and EmailChange

This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit e9bb797d0ae6ba36ad3a2784744ac0b3dc168c2f
Author: Rene Cordier <rc...@linagora.com>
AuthorDate: Fri Jan 15 18:05:02 2021 +0700

    JAMES-3471 Refactor and generify the Factory for handling events with MailboxChange and EmailChange
---
 .../apache/james/jmap/api/change/EmailChange.java  | 149 +++++-------
 .../apache/james/jmap/api/change/JmapChange.java   |  24 ++
 .../james/jmap/api/change/MailboxChange.java       | 266 +++++++++------------
 .../james/jmap/change/MailboxChangeListener.scala  |  86 ++++++-
 .../jmap/change/MailboxChangeListenerTest.scala    |   6 +-
 5 files changed, 277 insertions(+), 254 deletions(-)

diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChange.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChange.java
index 99f6a4e..97ab0a6 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChange.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChange.java
@@ -19,7 +19,6 @@
 
 package org.apache.james.jmap.api.change;
 
-import java.time.Clock;
 import java.time.ZonedDateTime;
 import java.util.Collection;
 import java.util.List;
@@ -28,15 +27,9 @@ import java.util.stream.Stream;
 
 import javax.inject.Inject;
 
-import org.apache.james.core.Username;
 import org.apache.james.jmap.api.model.AccountId;
-import org.apache.james.mailbox.MailboxManager;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.Event;
 import org.apache.james.mailbox.events.MailboxListener;
-import org.apache.james.mailbox.exception.MailboxException;
-import org.apache.james.mailbox.model.MailboxACL;
-import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.events.MailboxListener.Added;
 import org.apache.james.mailbox.model.MessageId;
 
 import com.github.steveash.guavate.Guavate;
@@ -44,7 +37,7 @@ import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
-public class EmailChange {
+public class EmailChange implements JmapChange {
     public static class Builder {
         @FunctionalInterface
         public interface RequireAccountId {
@@ -128,105 +121,77 @@ public class EmailChange {
     }
 
     public static class Factory {
-        private final Clock clock;
-        private final MailboxManager mailboxManager;
         private final State.Factory stateFactory;
 
         @Inject
-        public Factory(Clock clock, MailboxManager mailboxManager, State.Factory stateFactory) {
-            this.clock = clock;
-            this.mailboxManager = mailboxManager;
+        public Factory(State.Factory stateFactory) {
             this.stateFactory = stateFactory;
         }
 
-        public List<EmailChange> fromEvent(Event event) {
-            ZonedDateTime now = ZonedDateTime.now(clock);
-
-            if (event instanceof MailboxListener.Added) {
-                MailboxListener.Added messageAdded = (MailboxListener.Added) event;
-
-                EmailChange ownerChange = EmailChange.builder()
-                    .accountId(AccountId.fromUsername(messageAdded.getUsername()))
+        public List<JmapChange> fromAdded(Added messageAdded, ZonedDateTime now, List<AccountId> sharees) {
+            EmailChange ownerChange = EmailChange.builder()
+                .accountId(AccountId.fromUsername(messageAdded.getUsername()))
+                .state(stateFactory.generate())
+                .date(now)
+                .isDelegated(false)
+                .created(messageAdded.getMessageIds())
+                .build();
+
+            Stream<EmailChange> shareeChanges = sharees.stream()
+                .map(shareeId -> EmailChange.builder()
+                    .accountId(shareeId)
                     .state(stateFactory.generate())
                     .date(now)
-                    .isDelegated(false)
+                    .isDelegated(true)
                     .created(messageAdded.getMessageIds())
-                    .build();
-
-                Stream<EmailChange> shareeChanges = getSharees(messageAdded.getMailboxPath(), messageAdded.getUsername(), mailboxManager)
-                    .map(name -> EmailChange.builder()
-                        .accountId(AccountId.fromString(name))
-                        .state(stateFactory.generate())
-                        .date(now)
-                        .isDelegated(true)
-                        .created(messageAdded.getMessageIds())
-                        .build());
-
-                return Stream.concat(Stream.of(ownerChange), shareeChanges)
-                    .collect(Guavate.toImmutableList());
-            }
-            if (event instanceof MailboxListener.FlagsUpdated) {
-                MailboxListener.FlagsUpdated messageFlagUpdated = (MailboxListener.FlagsUpdated) event;
-
-                EmailChange ownerChange = EmailChange.builder()
-                    .accountId(AccountId.fromUsername(messageFlagUpdated.getUsername()))
+                    .build());
+
+            return Stream.concat(Stream.of(ownerChange), shareeChanges)
+                .collect(Guavate.toImmutableList());
+        }
+
+        public List<JmapChange> fromFlagsUpdated(MailboxListener.FlagsUpdated messageFlagUpdated, ZonedDateTime now, List<AccountId> sharees) {
+            EmailChange ownerChange = EmailChange.builder()
+                .accountId(AccountId.fromUsername(messageFlagUpdated.getUsername()))
+                .state(stateFactory.generate())
+                .date(now)
+                .isDelegated(false)
+                .updated(messageFlagUpdated.getMessageIds())
+                .build();
+
+            Stream<EmailChange> shareeChanges = sharees.stream()
+                .map(shareeId -> EmailChange.builder()
+                    .accountId(shareeId)
                     .state(stateFactory.generate())
                     .date(now)
-                    .isDelegated(false)
+                    .isDelegated(true)
                     .updated(messageFlagUpdated.getMessageIds())
-                    .build();
-
-                Stream<EmailChange> shareeChanges = getSharees(messageFlagUpdated.getMailboxPath(), messageFlagUpdated.getUsername(), mailboxManager)
-                    .map(name -> EmailChange.builder()
-                        .accountId(AccountId.fromString(name))
-                        .state(stateFactory.generate())
-                        .date(now)
-                        .isDelegated(true)
-                        .updated(messageFlagUpdated.getMessageIds())
-                        .build());
-
-                return Stream.concat(Stream.of(ownerChange), shareeChanges)
-                    .collect(Guavate.toImmutableList());
-            }
-            if (event instanceof MailboxListener.Expunged) {
-                MailboxListener.Expunged expunged = (MailboxListener.Expunged) event;
-
-                EmailChange ownerChange = EmailChange.builder()
-                    .accountId(AccountId.fromUsername(expunged.getUsername()))
+                    .build());
+
+            return Stream.concat(Stream.of(ownerChange), shareeChanges)
+                .collect(Guavate.toImmutableList());
+        }
+
+        public List<JmapChange> fromExpunged(MailboxListener.Expunged expunged, ZonedDateTime now, List<AccountId> sharees) {
+            EmailChange ownerChange = EmailChange.builder()
+                .accountId(AccountId.fromUsername(expunged.getUsername()))
+                .state(stateFactory.generate())
+                .date(now)
+                .isDelegated(false)
+                .destroyed(expunged.getMessageIds())
+                .build();
+
+            Stream<EmailChange> shareeChanges = sharees.stream()
+                .map(shareeId -> EmailChange.builder()
+                    .accountId(shareeId)
                     .state(stateFactory.generate())
                     .date(now)
-                    .isDelegated(false)
+                    .isDelegated(true)
                     .destroyed(expunged.getMessageIds())
-                    .build();
-
-                Stream<EmailChange> shareeChanges = getSharees(expunged.getMailboxPath(), expunged.getUsername(), mailboxManager)
-                    .map(name -> EmailChange.builder()
-                        .accountId(AccountId.fromString(name))
-                        .state(stateFactory.generate())
-                        .date(now)
-                        .isDelegated(true)
-                        .destroyed(expunged.getMessageIds())
-                        .build());
-
-                return Stream.concat(Stream.of(ownerChange), shareeChanges)
-                    .collect(Guavate.toImmutableList());
-            }
-
-            return ImmutableList.of();
-        }
-    }
+                    .build());
 
-    private static Stream<String> getSharees(MailboxPath path, Username username, MailboxManager mailboxManager) {
-        MailboxSession mailboxSession = mailboxManager.createSystemSession(username);
-        try {
-            MailboxACL mailboxACL = mailboxManager.listRights(path, mailboxSession);
-            return mailboxACL.getEntries().keySet()
-                .stream()
-                .filter(rfc4314Rights -> !rfc4314Rights.isNegative())
-                .filter(rfc4314Rights -> rfc4314Rights.getNameType().equals(MailboxACL.NameType.user))
-                .map(MailboxACL.EntryKey::getName);
-        } catch (MailboxException e) {
-            return Stream.of();
+            return Stream.concat(Stream.of(ownerChange), shareeChanges)
+                .collect(Guavate.toImmutableList());
         }
     }
 
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/JmapChange.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/JmapChange.java
new file mode 100644
index 0000000..b7a1a2e
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/JmapChange.java
@@ -0,0 +1,24 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.api.change;
+
+public interface JmapChange {
+
+}
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChange.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChange.java
index 3d8533d..86a2fd5 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChange.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChange.java
@@ -19,7 +19,6 @@
 
 package org.apache.james.jmap.api.change;
 
-import java.time.Clock;
 import java.time.ZonedDateTime;
 import java.util.List;
 import java.util.Objects;
@@ -29,11 +28,7 @@ import java.util.stream.Stream;
 import javax.inject.Inject;
 import javax.mail.Flags;
 
-import org.apache.james.core.Username;
 import org.apache.james.jmap.api.model.AccountId;
-import org.apache.james.mailbox.MailboxManager;
-import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.events.Event;
 import org.apache.james.mailbox.events.MailboxListener.Added;
 import org.apache.james.mailbox.events.MailboxListener.Expunged;
 import org.apache.james.mailbox.events.MailboxListener.FlagsUpdated;
@@ -41,7 +36,6 @@ import org.apache.james.mailbox.events.MailboxListener.MailboxACLUpdated;
 import org.apache.james.mailbox.events.MailboxListener.MailboxAdded;
 import org.apache.james.mailbox.events.MailboxListener.MailboxDeletion;
 import org.apache.james.mailbox.events.MailboxListener.MailboxRenamed;
-import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxId;
 
@@ -50,7 +44,7 @@ import com.google.common.base.MoreObjects;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
-public class MailboxChange {
+public class MailboxChange implements JmapChange {
     public static class Builder {
         @FunctionalInterface
         public interface RequiredAccountId {
@@ -129,198 +123,170 @@ public class MailboxChange {
     }
 
     public static class Factory {
-        private final Clock clock;
-        private final MailboxManager mailboxManager;
         private final State.Factory stateFactory;
 
         @Inject
-        public Factory(Clock clock, MailboxManager mailboxManager, State.Factory stateFactory) {
-            this.clock = clock;
-            this.mailboxManager = mailboxManager;
+        public Factory(State.Factory stateFactory) {
             this.stateFactory = stateFactory;
         }
 
-        public List<MailboxChange> fromEvent(Event event) {
-            ZonedDateTime now = ZonedDateTime.now(clock);
-            if (event instanceof MailboxAdded) {
-                MailboxAdded mailboxAdded = (MailboxAdded) event;
-
-                return ImmutableList.of(MailboxChange.builder()
-                    .accountId(AccountId.fromUsername(mailboxAdded.getUsername()))
-                    .state(stateFactory.generate())
-                    .date(now)
-                    .isCountChange(false)
-                    .created(ImmutableList.of(mailboxAdded.getMailboxId()))
-                    .build());
-            }
-            if (event instanceof MailboxRenamed) {
-                MailboxRenamed mailboxRenamed = (MailboxRenamed) event;
+        public List<JmapChange> fromMailboxAdded(MailboxAdded mailboxAdded, ZonedDateTime now) {
+            return ImmutableList.of(MailboxChange.builder()
+                .accountId(AccountId.fromUsername(mailboxAdded.getUsername()))
+                .state(stateFactory.generate())
+                .date(now)
+                .isCountChange(false)
+                .created(ImmutableList.of(mailboxAdded.getMailboxId()))
+                .build());
+        }
 
-                MailboxChange ownerChange = MailboxChange.builder()
-                    .accountId(AccountId.fromUsername(mailboxRenamed.getUsername()))
+        public List<JmapChange> fromMailboxRenamed(MailboxRenamed mailboxRenamed, ZonedDateTime now, List<AccountId> sharees) {
+            MailboxChange ownerChange = MailboxChange.builder()
+                .accountId(AccountId.fromUsername(mailboxRenamed.getUsername()))
+                .state(stateFactory.generate())
+                .date(now)
+                .isCountChange(false)
+                .updated(ImmutableList.of(mailboxRenamed.getMailboxId()))
+                .build();
+
+            Stream<MailboxChange> shareeChanges = sharees.stream()
+                .map(shareeId -> MailboxChange.builder()
+                    .accountId(shareeId)
                     .state(stateFactory.generate())
                     .date(now)
                     .isCountChange(false)
                     .updated(ImmutableList.of(mailboxRenamed.getMailboxId()))
-                    .build();
-
-                Stream<MailboxChange> shareeChanges = getSharees(mailboxRenamed.getMailboxId(), mailboxRenamed.getUsername(), mailboxManager)
-                    .map(name -> MailboxChange.builder()
-                        .accountId(AccountId.fromString(name))
-                        .state(stateFactory.generate())
-                        .date(now)
-                        .isCountChange(false)
-                        .updated(ImmutableList.of(mailboxRenamed.getMailboxId()))
-                        .delegated()
-                        .build());
+                    .delegated()
+                    .build());
 
-                return Stream.concat(Stream.of(ownerChange), shareeChanges)
-                    .collect(Guavate.toImmutableList());
-            }
-            if (event instanceof MailboxACLUpdated) {
-                MailboxACLUpdated mailboxACLUpdated = (MailboxACLUpdated) event;
+            return Stream.concat(Stream.of(ownerChange), shareeChanges)
+                .collect(Guavate.toImmutableList());
+        }
 
-                MailboxChange ownerChange = MailboxChange.builder()
-                    .accountId(AccountId.fromUsername(mailboxACLUpdated.getUsername()))
+        public List<JmapChange> fromMailboxACLUpdated(MailboxACLUpdated mailboxACLUpdated, ZonedDateTime now, List<AccountId> sharees) {
+            MailboxChange ownerChange = MailboxChange.builder()
+                .accountId(AccountId.fromUsername(mailboxACLUpdated.getUsername()))
+                .state(stateFactory.generate())
+                .date(now)
+                .isCountChange(false)
+                .updated(ImmutableList.of(mailboxACLUpdated.getMailboxId()))
+                .build();
+
+            Stream<MailboxChange> shareeChanges = sharees.stream()
+                .map(shareeId -> MailboxChange.builder()
+                    .accountId(shareeId)
                     .state(stateFactory.generate())
                     .date(now)
                     .isCountChange(false)
                     .updated(ImmutableList.of(mailboxACLUpdated.getMailboxId()))
-                    .build();
-
-                Stream<MailboxChange> shareeChanges = getSharees(mailboxACLUpdated.getMailboxId(), mailboxACLUpdated.getUsername(), mailboxManager)
-                    .map(name -> MailboxChange.builder()
-                        .accountId(AccountId.fromString(name))
-                        .state(stateFactory.generate())
-                        .date(now)
-                        .isCountChange(false)
-                        .updated(ImmutableList.of(mailboxACLUpdated.getMailboxId()))
-                        .delegated()
-                        .build());
+                    .delegated()
+                    .build());
 
-                return Stream.concat(Stream.of(ownerChange), shareeChanges)
-                    .collect(Guavate.toImmutableList());
-            }
-            if (event instanceof MailboxDeletion) {
-                MailboxDeletion mailboxDeletion = (MailboxDeletion) event;
+            return Stream.concat(Stream.of(ownerChange), shareeChanges)
+                .collect(Guavate.toImmutableList());
+        }
 
-                MailboxChange ownerChange = MailboxChange.builder()
-                    .accountId(AccountId.fromUsername(mailboxDeletion.getUsername()))
+        public List<JmapChange> fromMailboxDeletion(MailboxDeletion mailboxDeletion, ZonedDateTime now) {
+            MailboxChange ownerChange = MailboxChange.builder()
+                .accountId(AccountId.fromUsername(mailboxDeletion.getUsername()))
+                .state(stateFactory.generate())
+                .date(now)
+                .isCountChange(false)
+                .destroyed(ImmutableList.of(mailboxDeletion.getMailboxId()))
+                .build();
+
+            Stream<MailboxChange> shareeChanges = mailboxDeletion.getMailboxACL()
+                .getEntries().keySet()
+                .stream()
+                .filter(rfc4314Rights -> !rfc4314Rights.isNegative())
+                .filter(rfc4314Rights -> rfc4314Rights.getNameType().equals(MailboxACL.NameType.user))
+                .map(MailboxACL.EntryKey::getName)
+                .map(name -> MailboxChange.builder()
+                    .accountId(AccountId.fromString(name))
                     .state(stateFactory.generate())
                     .date(now)
                     .isCountChange(false)
                     .destroyed(ImmutableList.of(mailboxDeletion.getMailboxId()))
-                    .build();
-
-                Stream<MailboxChange> shareeChanges = mailboxDeletion.getMailboxACL()
-                    .getEntries().keySet()
-                    .stream()
-                    .filter(rfc4314Rights -> !rfc4314Rights.isNegative())
-                    .filter(rfc4314Rights -> rfc4314Rights.getNameType().equals(MailboxACL.NameType.user))
-                    .map(MailboxACL.EntryKey::getName)
-                    .map(name -> MailboxChange.builder()
-                        .accountId(AccountId.fromString(name))
-                        .state(stateFactory.generate())
-                        .date(now)
-                        .isCountChange(false)
-                        .destroyed(ImmutableList.of(mailboxDeletion.getMailboxId()))
-                        .delegated()
-                        .build());
+                    .delegated()
+                    .build());
 
-                return Stream.concat(Stream.of(ownerChange), shareeChanges)
-                    .collect(Guavate.toImmutableList());
-            }
-            if (event instanceof Added) {
-                Added messageAdded = (Added) event;
+            return Stream.concat(Stream.of(ownerChange), shareeChanges)
+                .collect(Guavate.toImmutableList());
+        }
 
-                MailboxChange ownerChange = MailboxChange.builder()
-                    .accountId(AccountId.fromUsername(messageAdded.getUsername()))
+        public List<JmapChange> fromAdded(Added messageAdded, ZonedDateTime now, List<AccountId> sharees) {
+            MailboxChange ownerChange = MailboxChange.builder()
+                .accountId(AccountId.fromUsername(messageAdded.getUsername()))
+                .state(stateFactory.generate())
+                .date(now)
+                .isCountChange(true)
+                .updated(ImmutableList.of(messageAdded.getMailboxId()))
+                .build();
+
+            Stream<MailboxChange> shareeChanges = sharees.stream()
+                .map(shareeId -> MailboxChange.builder()
+                    .accountId(shareeId)
                     .state(stateFactory.generate())
                     .date(now)
                     .isCountChange(true)
                     .updated(ImmutableList.of(messageAdded.getMailboxId()))
-                    .build();
+                    .delegated()
+                    .build());
 
-                Stream<MailboxChange> shareeChanges = getSharees(messageAdded.getMailboxId(), messageAdded.getUsername(), mailboxManager)
-                    .map(name -> MailboxChange.builder()
-                        .accountId(AccountId.fromString(name))
-                        .state(stateFactory.generate())
-                        .date(now)
-                        .isCountChange(true)
-                        .updated(ImmutableList.of(messageAdded.getMailboxId()))
-                        .delegated()
-                        .build());
+            return Stream.concat(Stream.of(ownerChange), shareeChanges)
+                .collect(Guavate.toImmutableList());
+        }
 
-                return Stream.concat(Stream.of(ownerChange), shareeChanges)
-                    .collect(Guavate.toImmutableList());
-            }
-            if (event instanceof FlagsUpdated) {
-                FlagsUpdated messageFlagUpdated = (FlagsUpdated) event;
-                boolean isSeenChanged = messageFlagUpdated.getUpdatedFlags()
-                    .stream()
-                    .anyMatch(flags -> flags.isChanged(Flags.Flag.SEEN));
-                if (isSeenChanged) {
-                    MailboxChange ownerChange = MailboxChange.builder()
-                        .accountId(AccountId.fromUsername(messageFlagUpdated.getUsername()))
-                        .state(stateFactory.generate())
-                        .date(now)
-                        .isCountChange(true)
-                        .updated(ImmutableList.of(messageFlagUpdated.getMailboxId()))
-                        .build();
-
-                    Stream<MailboxChange> shareeChanges = getSharees(messageFlagUpdated.getMailboxId(), messageFlagUpdated.getUsername(), mailboxManager)
-                        .map(name -> MailboxChange.builder()
-                            .accountId(AccountId.fromString(name))
-                            .state(stateFactory.generate())
-                            .date(now)
-                            .isCountChange(true)
-                            .updated(ImmutableList.of(messageFlagUpdated.getMailboxId()))
-                            .delegated()
-                            .build());
-
-                    return Stream.concat(Stream.of(ownerChange), shareeChanges)
-                        .collect(Guavate.toImmutableList());
-                }
-            }
-            if (event instanceof Expunged) {
-                Expunged expunged = (Expunged) event;
+        public List<JmapChange> fromFlagsUpdated(FlagsUpdated messageFlagUpdated, ZonedDateTime now, List<AccountId> sharees) {
+            boolean isSeenChanged = messageFlagUpdated.getUpdatedFlags()
+                .stream()
+                .anyMatch(flags -> flags.isChanged(Flags.Flag.SEEN));
+            if (isSeenChanged) {
                 MailboxChange ownerChange = MailboxChange.builder()
-                    .accountId(AccountId.fromUsername(expunged.getUsername()))
+                    .accountId(AccountId.fromUsername(messageFlagUpdated.getUsername()))
                     .state(stateFactory.generate())
                     .date(now)
                     .isCountChange(true)
-                    .updated(ImmutableList.of(expunged.getMailboxId()))
+                    .updated(ImmutableList.of(messageFlagUpdated.getMailboxId()))
                     .build();
 
-                Stream<MailboxChange> shareeChanges = getSharees(expunged.getMailboxId(), expunged.getUsername(), mailboxManager)
-                    .map(name -> MailboxChange.builder()
-                        .accountId(AccountId.fromString(name))
+                Stream<MailboxChange> shareeChanges = sharees.stream()
+                    .map(shareeId -> MailboxChange.builder()
+                        .accountId(shareeId)
                         .state(stateFactory.generate())
                         .date(now)
                         .isCountChange(true)
-                        .updated(ImmutableList.of(expunged.getMailboxId()))
+                        .updated(ImmutableList.of(messageFlagUpdated.getMailboxId()))
                         .delegated()
                         .build());
 
                 return Stream.concat(Stream.of(ownerChange), shareeChanges)
                     .collect(Guavate.toImmutableList());
             }
-
             return ImmutableList.of();
         }
-    }
 
-    private static Stream<String> getSharees(MailboxId mailboxId, Username username, MailboxManager mailboxManager) {
-        MailboxSession mailboxSession = mailboxManager.createSystemSession(username);
-        try {
-            MailboxACL mailboxACL = mailboxManager.listRights(mailboxId, mailboxSession);
-            return mailboxACL.getEntries().keySet()
-                .stream()
-                .filter(rfc4314Rights -> !rfc4314Rights.isNegative())
-                .filter(rfc4314Rights -> rfc4314Rights.getNameType().equals(MailboxACL.NameType.user))
-                .map(MailboxACL.EntryKey::getName);
-        } catch (MailboxException e) {
-            return Stream.of();
+        public List<JmapChange> fromExpunged(Expunged expunged, ZonedDateTime now, List<AccountId> sharees) {
+            MailboxChange ownerChange = MailboxChange.builder()
+                .accountId(AccountId.fromUsername(expunged.getUsername()))
+                .state(stateFactory.generate())
+                .date(now)
+                .isCountChange(true)
+                .updated(ImmutableList.of(expunged.getMailboxId()))
+                .build();
+
+            Stream<MailboxChange> shareeChanges = sharees.stream()
+                .map(shareeId -> MailboxChange.builder()
+                    .accountId(shareeId)
+                    .state(stateFactory.generate())
+                    .date(now)
+                    .isCountChange(true)
+                    .updated(ImmutableList.of(expunged.getMailboxId()))
+                    .delegated()
+                    .build());
+
+            return Stream.concat(Stream.of(ownerChange), shareeChanges)
+                .collect(Guavate.toImmutableList());
         }
     }
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/MailboxChangeListener.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/MailboxChangeListener.scala
index 486767b..9c01d0f 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/MailboxChangeListener.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/MailboxChangeListener.scala
@@ -19,32 +19,100 @@
 
 package org.apache.james.jmap.change
 
+import org.apache.james.core.Username
+
 import javax.inject.Inject
-import org.apache.james.jmap.api.change.{EmailChange, EmailChangeRepository, MailboxChange, MailboxChangeRepository}
-import org.apache.james.mailbox.events.MailboxListener.{MailboxEvent, ReactiveGroupMailboxListener}
+import org.apache.james.jmap.api.change.{EmailChange, EmailChangeRepository, JmapChange, MailboxChange, MailboxChangeRepository}
+import org.apache.james.jmap.api.model.AccountId
+import org.apache.james.jmap.change.MailboxChangeListener.LOGGER
+import org.apache.james.mailbox.{MailboxManager, MailboxSession}
+import org.apache.james.mailbox.events.MailboxListener.{Added, Expunged, FlagsUpdated, MailboxACLUpdated, MailboxAdded, MailboxDeletion, MailboxEvent, MailboxRenamed, ReactiveGroupMailboxListener}
 import org.apache.james.mailbox.events.{Event, Group}
+import org.apache.james.mailbox.exception.MailboxException
+import org.apache.james.mailbox.model.{MailboxACL, MailboxId}
 import org.apache.james.util.ReactorUtils.DEFAULT_CONCURRENCY
 import org.reactivestreams.Publisher
+import org.slf4j.{Logger, LoggerFactory}
 import reactor.core.scala.publisher.{SFlux, SMono}
 
+import java.time.{Clock, ZonedDateTime}
 import scala.jdk.CollectionConverters._
 
 case class MailboxChangeListenerGroup() extends Group {}
 
+object MailboxChangeListener {
+  val LOGGER: Logger = LoggerFactory.getLogger(classOf[MailboxChangeListener])
+}
+
 case class MailboxChangeListener @Inject() (mailboxChangeRepository: MailboxChangeRepository,
                                             mailboxChangeFactory: MailboxChange.Factory,
                                             emailChangeRepository: EmailChangeRepository,
-                                            emailChangeFactory: EmailChange.Factory) extends ReactiveGroupMailboxListener {
+                                            emailChangeFactory: EmailChange.Factory,
+                                            mailboxManager: MailboxManager,
+                                            clock: Clock) extends ReactiveGroupMailboxListener {
 
   override def reactiveEvent(event: Event): Publisher[Void] =
-    SFlux.fromIterable(mailboxChangeFactory.fromEvent(event).asScala)
-      .flatMap(change => mailboxChangeRepository.save(change), DEFAULT_CONCURRENCY)
-      .thenMany(SFlux.fromIterable(emailChangeFactory.fromEvent(event).asScala))
-      .flatMap(change => emailChangeRepository.save(change), DEFAULT_CONCURRENCY)
-      .`then`
-      .`then`(SMono.empty[Void]).asJava
+    handleEvent(event.asInstanceOf[MailboxEvent])
+      .`then`(SMono.empty[Void])
+      .asJava
 
   override def getDefaultGroup: Group = MailboxChangeListenerGroup()
 
   override def isHandling(event: Event): Boolean = event.isInstanceOf[MailboxEvent]
+
+  private def handleEvent(mailboxEvent: MailboxEvent): SMono[Unit] = {
+    val now: ZonedDateTime = ZonedDateTime.now(clock)
+    val mailboxId: MailboxId = mailboxEvent.getMailboxId
+    val username: Username = mailboxEvent.getUsername
+
+    SFlux.fromIterable(
+      mailboxEvent match {
+        case mailboxAdded: MailboxAdded =>
+          mailboxChangeFactory.fromMailboxAdded(mailboxAdded, now).asScala
+        case mailboxRenamed: MailboxRenamed =>
+          mailboxChangeFactory.fromMailboxRenamed(mailboxRenamed, now, getSharees(mailboxId, username).asJava).asScala
+        case mailboxACLUpdated: MailboxACLUpdated =>
+          mailboxChangeFactory.fromMailboxACLUpdated(mailboxACLUpdated, now, getSharees(mailboxId, username).asJava).asScala
+        case mailboxDeletion: MailboxDeletion =>
+          mailboxChangeFactory.fromMailboxDeletion(mailboxDeletion, now).asScala
+        case added: Added =>
+          val sharees = getSharees(mailboxId, username).asJava
+          mailboxChangeFactory.fromAdded(added, now, sharees).asScala
+            .concat(emailChangeFactory.fromAdded(added, now, sharees).asScala)
+        case flagsUpdated: FlagsUpdated =>
+          val sharees = getSharees(mailboxId, username).asJava
+          mailboxChangeFactory.fromFlagsUpdated(flagsUpdated, now, sharees).asScala
+            .concat(emailChangeFactory.fromFlagsUpdated(flagsUpdated, now, sharees).asScala)
+        case expunged: Expunged =>
+          val sharees = getSharees(mailboxId, username).asJava
+          mailboxChangeFactory.fromExpunged(expunged, now, sharees).asScala
+            .concat(emailChangeFactory.fromExpunged(expunged, now, sharees).asScala)
+      })
+      .flatMap(saveChangeEvent, DEFAULT_CONCURRENCY)
+      .`then`()
+  }
+
+  private def saveChangeEvent(jmapChange: JmapChange): Publisher[Void] =
+    jmapChange match {
+      case mailboxChange: MailboxChange => mailboxChangeRepository.save(mailboxChange)
+      case emailChange: EmailChange => emailChangeRepository.save(emailChange)
+    }
+
+  private def getSharees(mailboxId: MailboxId, username: Username): List[AccountId] = {
+    val mailboxSession: MailboxSession = mailboxManager.createSystemSession(username)
+    try {
+      val mailboxACL = mailboxManager.listRights(mailboxId, mailboxSession)
+      mailboxACL.getEntries.keySet
+        .asScala
+        .filter(!_.isNegative)
+        .filter(_.getNameType == MailboxACL.NameType.user)
+        .map(_.getName)
+        .map(AccountId.fromString)
+        .toList
+    } catch {
+      case e: MailboxException =>
+        LOGGER.warn("Could not get sharees for mailbox [%s] when listening to change events", mailboxId)
+        List.empty
+    }
+  }
 }
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala
index a2bfcfa..3e58532 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala
@@ -66,11 +66,11 @@ class MailboxChangeListenerTest {
     clock = Clock.systemUTC()
     mailboxManager = resources.getMailboxManager
     stateFactory = new State.DefaultFactory
-    mailboxChangeFactory = new MailboxChange.Factory(clock, mailboxManager, stateFactory)
+    mailboxChangeFactory = new MailboxChange.Factory(stateFactory)
     mailboxChangeRepository = new MemoryMailboxChangeRepository()
-    emailChangeFactory = new EmailChange.Factory(clock, mailboxManager, stateFactory)
+    emailChangeFactory = new EmailChange.Factory(stateFactory)
     emailChangeRepository = new MemoryEmailChangeRepository()
-    listener = MailboxChangeListener(mailboxChangeRepository, mailboxChangeFactory, emailChangeRepository, emailChangeFactory)
+    listener = MailboxChangeListener(mailboxChangeRepository, mailboxChangeFactory, emailChangeRepository, emailChangeFactory, mailboxManager, clock)
     resources.getEventBus.register(listener)
   }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org