This is an automated email from the ASF dual-hosted git repository. chibenwa pushed a commit to branch 3.9.x in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 8dc93571acba7a6abd4223bdf6d31fb9ea1186b0 Author: Benoit TELLIER <[email protected]> AuthorDate: Tue Jun 16 17:36:28 2026 +0200 [FIX] Cassandra folder rename: base decision on truth table Carry over truth table from MailboxManager --- .../cassandra/mail/CassandraMailboxMapper.java | 28 +++++++++++----------- .../james/mailbox/store/StoreMailboxManager.java | 4 ++-- .../james/mailbox/store/mail/MailboxMapper.java | 6 ++++- .../java/org/apache/james/util/ReactorUtils.java | 11 +++++++++ 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java index cb7e2b0eed..eceec29a4b 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java @@ -44,7 +44,7 @@ import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.mailbox.model.UidValidity; import org.apache.james.mailbox.model.search.MailboxQuery; import org.apache.james.mailbox.store.mail.MailboxMapper; -import org.apache.james.util.FunctionalUtils; +import org.apache.james.util.ReactorUtils; import com.google.common.base.Preconditions; @@ -221,23 +221,23 @@ public class CassandraMailboxMapper implements MailboxMapper { Preconditions.checkNotNull(mailbox.getMailboxId(), "A mailbox we want to rename should have a defined mailboxId"); CassandraId cassandraId = (CassandraId) mailbox.getMailboxId(); - return tryRename(mailbox, cassandraId) - .filter(FunctionalUtils.identityPredicate()) - .switchIfEmpty(Mono.error(() -> new MailboxExistsException(mailbox.generateAssociatedPath().asString()))) - .thenReturn(cassandraId); - } - - private Mono<Boolean> tryRename(Mailbox cassandraMailbox, CassandraId cassandraId) { return mailboxDAO.retrieveMailbox(cassandraId) - .flatMap(mailbox -> mailboxPathV3DAO.save(cassandraMailbox) - .filter(isCreated -> isCreated) - .flatMap(mailboxHasCreated -> deletePreviousMailboxPathReference(mailbox.generateAssociatedPath()) - .then(persistMailboxEntity(cassandraMailbox)) - .thenReturn(true)) - .defaultIfEmpty(false)) + .flatMap(storedMailbox -> rename(mailbox, storedMailbox.generateAssociatedPath())) .switchIfEmpty(Mono.error(() -> new MailboxNotFoundException(cassandraId))); } + @Override + public Mono<MailboxId> rename(Mailbox cassandraMailbox, MailboxPath previousPath) { + Preconditions.checkNotNull(cassandraMailbox.getMailboxId(), "A mailbox we want to rename should have a defined mailboxId"); + CassandraId cassandraId = (CassandraId) cassandraMailbox.getMailboxId(); + + return mailboxPathV3DAO.save(cassandraMailbox) + .handle(ReactorUtils.raiseErrorIfFalse(() -> new MailboxExistsException(cassandraMailbox.generateAssociatedPath().asString()))) + .flatMap(applied -> deletePreviousMailboxPathReference(previousPath) + .then(persistMailboxEntity(cassandraMailbox))) + .thenReturn(cassandraId); + } + private Mono<Void> persistMailboxEntity(Mailbox cassandraMailbox) { return mailboxDAO.save(cassandraMailbox) .retryWhen(Retry.backoff(MAX_RETRY, MIN_RETRY_BACKOFF).maxBackoff(MAX_RETRY_BACKOFF)); 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 352f97b59c..312a3ee1fb 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 @@ -686,7 +686,7 @@ public class StoreMailboxManager implements MailboxManager { .build() .asUserBound(); - return mapper.rename(mailbox) + return mapper.rename(mailbox, from) .map(mailboxId -> { resultBuilder.add(new MailboxRenamedResult(mailboxId, from, newMailboxPath)); return mailboxId; @@ -717,7 +717,7 @@ public class StoreMailboxManager implements MailboxManager { MailboxPath fromPath = new MailboxPath(from, subOriginalName); sub.setName(subNewName); sub.setUser(newMailboxPath.getUser()); - return mapper.rename(sub) + return mapper.rename(sub, fromPath) .map(mailboxId -> { resultBuilder.add(new MailboxRenamedResult(sub.getMailboxId(), fromPath, sub.generateAssociatedPath())); return mailboxId; diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MailboxMapper.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MailboxMapper.java index a88d6a1012..3412efe295 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MailboxMapper.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MailboxMapper.java @@ -50,8 +50,12 @@ public interface MailboxMapper extends Mapper { /** * Rename the given {@link Mailbox} to the underlying storage */ + default Mono<MailboxId> rename(Mailbox mailbox, MailboxPath previousPath) { + return rename(mailbox); + } + Mono<MailboxId> rename(Mailbox mailbox); - + /** * Delete the given {@link Mailbox} from the underlying storage */ diff --git a/server/container/util/src/main/java/org/apache/james/util/ReactorUtils.java b/server/container/util/src/main/java/org/apache/james/util/ReactorUtils.java index 8c26be6382..c111028b89 100644 --- a/server/container/util/src/main/java/org/apache/james/util/ReactorUtils.java +++ b/server/container/util/src/main/java/org/apache/james/util/ReactorUtils.java @@ -28,6 +28,7 @@ import java.util.Optional; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Stream; import org.reactivestreams.Publisher; @@ -107,6 +108,16 @@ public class ReactorUtils { return (element, sink) -> element.ifPresent(sink::next); } + public static BiConsumer<Boolean, SynchronousSink<Boolean>> raiseErrorIfFalse(Supplier<Exception> exceptionSupplier) { + return (element, sink) -> { + if (!element) { + sink.error(exceptionSupplier.get()); + } else { + sink.next(element); + } + }; + } + public static InputStream toInputStream(Flux<ByteBuffer> byteArrays) { return new StreamInputStream(byteArrays.toStream(DEFAULT_INPUT_STREAM_PREFETCH)); } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
