This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch 3.8.x in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 2533185267c747825ad245043fc034232dcb80b9 Author: Benoit Tellier <btell...@linagora.com> AuthorDate: Fri Jun 9 18:41:57 2023 +0700 JAMES-3911 JPA: Prevent concurrent operations on the same EntityManager --- .../mailbox/jpa/openjpa/OpenJPAMessageManager.java | 37 +++++++++++++++++++++- .../james/mailbox/store/StoreMailboxManager.java | 2 +- .../james/mailbox/store/StoreMessageManager.java | 10 +++--- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java index 567e8d5ac6..7226fb046a 100644 --- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java +++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java @@ -20,14 +20,18 @@ package org.apache.james.mailbox.jpa.openjpa; import java.time.Clock; +import java.util.EnumSet; import javax.mail.Flags; import org.apache.james.events.EventBus; import org.apache.james.mailbox.MailboxPathLocker; import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.Mailbox; +import org.apache.james.mailbox.model.MailboxACL; import org.apache.james.mailbox.model.MessageId; +import org.apache.james.mailbox.model.UidValidity; import org.apache.james.mailbox.quota.QuotaManager; import org.apache.james.mailbox.quota.QuotaRootResolver; import org.apache.james.mailbox.store.BatchSizes; @@ -37,23 +41,35 @@ import org.apache.james.mailbox.store.PreDeletionHooks; import org.apache.james.mailbox.store.StoreMailboxManager; import org.apache.james.mailbox.store.StoreMessageManager; import org.apache.james.mailbox.store.StoreRightManager; +import org.apache.james.mailbox.store.mail.MessageMapper; import org.apache.james.mailbox.store.mail.ThreadIdGuessingAlgorithm; import org.apache.james.mailbox.store.search.MessageSearchIndex; +import com.github.fge.lambdas.Throwing; + +import reactor.core.publisher.Mono; + /** * OpenJPA implementation of Mailbox */ public class OpenJPAMessageManager extends StoreMessageManager { + private final MailboxSessionMapperFactory mapperFactory; + private final StoreRightManager storeRightManager; + private final Mailbox mailbox; public OpenJPAMessageManager(MailboxSessionMapperFactory mapperFactory, MessageSearchIndex index, EventBus eventBus, MailboxPathLocker locker, Mailbox mailbox, QuotaManager quotaManager, QuotaRootResolver quotaRootResolver, MessageId.Factory messageIdFactory, BatchSizes batchSizes, - StoreRightManager storeRightManager, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm, Clock clock) { + StoreRightManager storeRightManager, ThreadIdGuessingAlgorithm threadIdGuessingAlgorithm, + Clock clock) { super(StoreMailboxManager.DEFAULT_NO_MESSAGE_CAPABILITIES, mapperFactory, index, eventBus, locker, mailbox, quotaManager, quotaRootResolver, batchSizes, storeRightManager, PreDeletionHooks.NO_PRE_DELETION_HOOK, new MessageStorer.WithoutAttachment(mapperFactory, messageIdFactory, new OpenJPAMessageFactory(OpenJPAMessageFactory.AdvancedFeature.None), threadIdGuessingAlgorithm, clock)); + this.storeRightManager = storeRightManager; + this.mapperFactory = mapperFactory; + this.mailbox = mailbox; } /** @@ -65,4 +81,23 @@ public class OpenJPAMessageManager extends StoreMessageManager { flags.add(Flags.Flag.USER); return flags; } + + public Mono<MailboxMetaData> getMetaDataReactive(MailboxMetaData.RecentMode recentMode, MailboxSession mailboxSession, EnumSet<MailboxMetaData.Item> items) throws MailboxException { + MailboxACL resolvedAcl = getResolvedAcl(mailboxSession); + if (!storeRightManager.hasRight(mailbox, MailboxACL.Right.Read, mailboxSession)) { + return Mono.just(MailboxMetaData.sensibleInformationFree(resolvedAcl, getMailboxEntity().getUidValidity(), isWriteable(mailboxSession))); + } + Flags permanentFlags = getPermanentFlags(mailboxSession); + UidValidity uidValidity = getMailboxEntity().getUidValidity(); + MessageMapper messageMapper = mapperFactory.getMessageMapper(mailboxSession); + + return messageMapper.executeReactive( + nextUid(messageMapper, items) + .flatMap(nextUid -> highestModSeq(messageMapper, items) + .flatMap(highestModSeq -> firstUnseen(messageMapper, items) + .flatMap(Throwing.function(firstUnseen -> recent(recentMode, mailboxSession) + .flatMap(recents -> mailboxCounters(messageMapper, items) + .map(counters -> new MailboxMetaData(recents, permanentFlags, uidValidity, nextUid, highestModSeq, counters.getCount(), + counters.getUnseen(), firstUnseen.orElse(null), isWriteable(mailboxSession), resolvedAcl)))))))); + } } diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java index 5c530d907f..e1d272c5f8 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java @@ -658,7 +658,7 @@ public class StoreMailboxManager implements MailboxManager { return mailboxId; }) .then(Mono.from(locker.executeReactiveWithLockReactive(from, mapper.findMailboxWithPathLike(query) - .flatMap(sub -> { + .concatMap(sub -> { String subOriginalName = sub.getName(); String subNewName = newMailboxPath.getName() + subOriginalName.substring(from.getName().length()); MailboxPath fromPath = new MailboxPath(from, subOriginalName); diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java index 8ef76f2931..a5fe322689 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java @@ -594,14 +594,14 @@ public class StoreMessageManager implements MessageManager { t5.getT4().getUnseen(), t5.getT3().orElse(null), isWriteable(mailboxSession), resolvedAcl))); } - private Mono<ModSeq> highestModSeq(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) { + protected Mono<ModSeq> highestModSeq(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) { if (items.contains(MailboxMetaData.Item.HighestModSeq)) { return messageMapper.getHighestModSeqReactive(mailbox); } return Mono.just(ModSeq.first()); } - private Mono<MessageUid> nextUid(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) { + protected Mono<MessageUid> nextUid(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) { if (items.contains(MailboxMetaData.Item.NextUid)) { return messageMapper.getLastUidReactive(mailbox) .map(optional -> optional @@ -611,14 +611,14 @@ public class StoreMessageManager implements MessageManager { return Mono.just(MessageUid.MIN_VALUE); } - private Mono<Optional<MessageUid>> firstUnseen(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) { + protected Mono<Optional<MessageUid>> firstUnseen(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) { if (items.contains(MailboxMetaData.Item.FirstUnseen)) { return messageMapper.findFirstUnseenMessageUidReactive(getMailboxEntity()); } return Mono.just(Optional.empty()); } - private Mono<MailboxCounters> mailboxCounters(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) { + protected Mono<MailboxCounters> mailboxCounters(MessageMapper messageMapper, EnumSet<MailboxMetaData.Item> items) { if (items.contains(MailboxMetaData.Item.MailboxCounters)) { return messageMapper.getMailboxCountersReactive(getMailboxEntity()); } @@ -777,7 +777,7 @@ public class StoreMessageManager implements MessageManager { * Return a List which holds all uids of recent messages and optional reset * the recent flag on the messages for the uids */ - private Mono<List<MessageUid>> recent(RecentMode recentMode, MailboxSession mailboxSession) throws MailboxException { + protected Mono<List<MessageUid>> recent(RecentMode recentMode, MailboxSession mailboxSession) throws MailboxException { MessageMapper messageMapper = mapperFactory.getMessageMapper(mailboxSession); switch (recentMode) { --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org