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