MAILBOX-305 Introduce the new table attachmentId -> messageIds
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/1b4d9239 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/1b4d9239 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/1b4d9239 Branch: refs/heads/master Commit: 1b4d92391c8e566c81297ae98ba4c75ae3e32408 Parents: 035f0f7 Author: Raphael Ouazana <[email protected]> Authored: Mon Sep 11 13:01:07 2017 +0200 Committer: Antoine Duprat <[email protected]> Committed: Wed Sep 13 10:21:57 2017 +0200 ---------------------------------------------------------------------- .../apache/james/mailbox/AttachmentManager.java | 5 +- .../CassandraMailboxSessionMapperFactory.java | 7 +- .../cassandra/CassandraMessageManager.java | 5 +- .../mail/CassandraAttachmentMapper.java | 29 +++- .../mail/CassandraAttachmentMessageIdDAO.java | 101 ++++++++++++++ .../modules/CassandraAttachmentModule.java | 14 +- .../CassandraAttachmentMessageIdTable.java | 30 +++++ .../CassandraSubscriptionManagerTest.java | 3 + ...estCassandraMailboxSessionMapperFactory.java | 5 +- .../mail/CassandraAttachmentFallbackTest.java | 5 +- .../mail/CassandraAttachmentMapperTest.java | 7 + .../inmemory/InMemoryMessageManager.java | 5 +- .../inmemory/mail/InMemoryAttachmentMapper.java | 14 +- .../mail/MemoryAttachmentMapperTest.java | 7 + .../mailbox/store/StoreAttachmentManager.java | 10 +- .../mailbox/store/mail/AttachmentMapper.java | 5 +- .../store/mail/model/AttachmentMapperTest.java | 134 ++++++++++++++++++- 17 files changed, 363 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/api/src/main/java/org/apache/james/mailbox/AttachmentManager.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/AttachmentManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/AttachmentManager.java index e9f2e0f..a03bb53 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/AttachmentManager.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/AttachmentManager.java @@ -26,6 +26,7 @@ import org.apache.james.mailbox.exception.AttachmentNotFoundException; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.Attachment; import org.apache.james.mailbox.model.AttachmentId; +import org.apache.james.mailbox.model.MessageId; public interface AttachmentManager { @@ -35,5 +36,7 @@ public interface AttachmentManager { void storeAttachment(Attachment attachment, MailboxSession mailboxSession) throws MailboxException; - void storeAttachments(Collection<Attachment> attachments, MailboxSession mailboxSession) throws MailboxException; + void storeAttachmentsForMessage(Collection<Attachment> attachments, MessageId ownerMessageId, MailboxSession mailboxSession) throws MailboxException; + + Collection<MessageId> getOwnerMessageIds(AttachmentId attachmentId, MailboxSession mailboxSession) throws MailboxException; } http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java index 85e3349..9d4e059 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMailboxSessionMapperFactory.java @@ -29,6 +29,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO; import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAO; import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2; import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMapper; +import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO; import org.apache.james.mailbox.cassandra.mail.CassandraBlobsDAO; import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO; import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO; @@ -82,6 +83,7 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa private final CassandraAttachmentDAOV2 attachmentDAOV2; private final CassandraDeletedMessageDAO deletedMessageDAO; private final CassandraBlobsDAO blobsDAO; + private final CassandraAttachmentMessageIdDAO attachementMessageIdDAO; private CassandraUtils cassandraUtils; private CassandraConfiguration cassandraConfiguration; @@ -92,7 +94,7 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa CassandraMailboxCounterDAO mailboxCounterDAO, CassandraMailboxRecentsDAO mailboxRecentsDAO, CassandraMailboxDAO mailboxDAO, CassandraMailboxPathDAO mailboxPathDAO, CassandraFirstUnseenDAO firstUnseenDAO, CassandraApplicableFlagDAO applicableFlagDAO, CassandraAttachmentDAO attachmentDAO, CassandraAttachmentDAOV2 attachmentDAOV2, CassandraDeletedMessageDAO deletedMessageDAO, - CassandraBlobsDAO blobsDAO, CassandraUtils cassandraUtils, CassandraConfiguration cassandraConfiguration) { + CassandraBlobsDAO blobsDAO, CassandraAttachmentMessageIdDAO attachementMessageIdDAO, CassandraUtils cassandraUtils, CassandraConfiguration cassandraConfiguration) { this.uidProvider = uidProvider; this.modSeqProvider = modSeqProvider; this.session = session; @@ -109,6 +111,7 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa this.deletedMessageDAO = deletedMessageDAO; this.applicableFlagDAO = applicableFlagDAO; this.blobsDAO = blobsDAO; + this.attachementMessageIdDAO = attachementMessageIdDAO; this.cassandraUtils = cassandraUtils; this.cassandraConfiguration = cassandraConfiguration; this.indexTableHandler = new CassandraIndexTableHandler( @@ -153,7 +156,7 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa @Override public CassandraAttachmentMapper createAttachmentMapper(MailboxSession mailboxSession) { - return new CassandraAttachmentMapper(attachmentDAO, attachmentDAOV2, blobsDAO); + return new CassandraAttachmentMapper(attachmentDAO, attachmentDAOV2, blobsDAO, attachementMessageIdDAO); } @Override http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java index 0a8890d..523cad8 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/CassandraMessageManager.java @@ -74,9 +74,10 @@ public class CassandraMessageManager extends StoreMessageManager { @Override protected void storeAttachment(final MailboxMessage message, final List<MessageAttachment> messageAttachments, final MailboxSession session) throws MailboxException { mapperFactory.getAttachmentMapper(session) - .storeAttachments( + .storeAttachmentsForMessage( messageAttachments.stream() .map(MessageAttachment::getAttachment) - .collect(Guavate.toImmutableList())); + .collect(Guavate.toImmutableList()), + message.getMessageId()); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java index 8388c20..37edb52 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapper.java @@ -33,6 +33,7 @@ import org.apache.james.mailbox.exception.AttachmentNotFoundException; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.Attachment; import org.apache.james.mailbox.model.AttachmentId; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.store.mail.AttachmentMapper; import org.apache.james.util.FluentFutureStream; import org.jetbrains.annotations.Nullable; @@ -49,12 +50,14 @@ public class CassandraAttachmentMapper implements AttachmentMapper { private final CassandraAttachmentDAO attachmentDAO; private final CassandraAttachmentDAOV2 attachmentDAOV2; private final CassandraBlobsDAO blobsDAO; + private final CassandraAttachmentMessageIdDAO attachmentMessageIdDAO; @Inject - public CassandraAttachmentMapper(CassandraAttachmentDAO attachmentDAO, CassandraAttachmentDAOV2 attachmentDAOV2, CassandraBlobsDAO blobsDAO) { + public CassandraAttachmentMapper(CassandraAttachmentDAO attachmentDAO, CassandraAttachmentDAOV2 attachmentDAOV2, CassandraBlobsDAO blobsDAO, CassandraAttachmentMessageIdDAO attachmentMessageIdDAO) { this.attachmentDAO = attachmentDAO; this.attachmentDAOV2 = attachmentDAOV2; this.blobsDAO = blobsDAO; + this.attachmentMessageIdDAO = attachmentMessageIdDAO; } @Override @@ -118,21 +121,35 @@ public class CassandraAttachmentMapper implements AttachmentMapper { @Override public void storeAttachment(Attachment attachment) throws MailboxException { - storeAttachmentAsync(attachment).join(); + blobsDAO.save(attachment.getBytes()) + .thenApply(blobId -> CassandraAttachmentDAOV2.from(attachment, blobId)) + .thenCompose(attachmentDAOV2::storeAttachment) + .join(); } @Override - public void storeAttachments(Collection<Attachment> attachments) throws MailboxException { + public void storeAttachmentsForMessage(Collection<Attachment> attachments, MessageId ownerMessageId) throws MailboxException { FluentFutureStream.of( attachments.stream() - .map(this::storeAttachmentAsync)) + .map(attachment -> storeAttachmentAsync(attachment, ownerMessageId))) + .join(); + } + + @Override + public Collection<MessageId> getOwnerMessageIds(AttachmentId attachmentId) throws MailboxException { + return attachmentMessageIdDAO.getOwnerMessageIds(attachmentId) .join(); } - public CompletableFuture<Void> storeAttachmentAsync(Attachment attachment) { + public CompletableFuture<Void> storeAttachmentAsync(Attachment attachment, MessageId ownerMessageId) { return blobsDAO.save(attachment.getBytes()) .thenApply(blobId -> CassandraAttachmentDAOV2.from(attachment, blobId)) - .thenCompose(attachmentDAOV2::storeAttachment); + .thenCompose(daoAttachment -> storeAttachmentWithIndex(daoAttachment, ownerMessageId)); + } + + private CompletableFuture<Void> storeAttachmentWithIndex(DAOAttachment daoAttachment, MessageId ownerMessageId) { + return attachmentDAOV2.storeAttachment(daoAttachment) + .thenCompose(any -> attachmentMessageIdDAO.storeAttachmentForMessageId(daoAttachment.getAttachmentId(), ownerMessageId)); } private Optional<Attachment> logNotFound(AttachmentId attachmentId, Optional<Attachment> optionalAttachment) { http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java new file mode 100644 index 0000000..88b3d4d --- /dev/null +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMessageIdDAO.java @@ -0,0 +1,101 @@ +/**************************************************************** + * 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.cassandra.mail; + +import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker; +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.cassandra.table.CassandraAttachmentMessageIdTable.ATTACHMENT_ID; +import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentMessageIdTable.ATTACHMENT_ID_AS_UUID; +import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentMessageIdTable.FIELDS; +import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentMessageIdTable.MESSAGE_ID; +import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentMessageIdTable.TABLE_NAME; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import javax.inject.Inject; + +import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor; +import org.apache.james.backends.cassandra.utils.CassandraUtils; +import org.apache.james.mailbox.model.AttachmentId; +import org.apache.james.mailbox.model.MessageId; + +import com.datastax.driver.core.PreparedStatement; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import com.github.steveash.guavate.Guavate; +import com.google.common.base.Preconditions; + +public class CassandraAttachmentMessageIdDAO { + + private final CassandraAsyncExecutor cassandraAsyncExecutor; + private final PreparedStatement insertStatement; + private final PreparedStatement selectStatement; + private final MessageId.Factory messageIdFactory; + private final CassandraUtils cassandraUtils; + + @Inject + public CassandraAttachmentMessageIdDAO(Session session, MessageId.Factory messageIdFactory, CassandraUtils cassandraUtils) { + this.messageIdFactory = messageIdFactory; + this.cassandraUtils = cassandraUtils; + this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session); + + this.selectStatement = prepareSelect(session); + this.insertStatement = prepareInsert(session); + } + + private PreparedStatement prepareInsert(Session session) { + return session.prepare( + insertInto(TABLE_NAME) + .value(ATTACHMENT_ID_AS_UUID, bindMarker(ATTACHMENT_ID_AS_UUID)) + .value(ATTACHMENT_ID, bindMarker(ATTACHMENT_ID)) + .value(MESSAGE_ID, bindMarker(MESSAGE_ID))); + } + + private PreparedStatement prepareSelect(Session session) { + return session.prepare(select(FIELDS) + .from(TABLE_NAME) + .where(eq(ATTACHMENT_ID_AS_UUID, bindMarker(ATTACHMENT_ID_AS_UUID)))); + } + + public CompletableFuture<Collection<MessageId>> getOwnerMessageIds(AttachmentId attachmentId) { + Preconditions.checkArgument(attachmentId != null); + return cassandraAsyncExecutor.execute( + selectStatement.bind() + .setUUID(ATTACHMENT_ID_AS_UUID, attachmentId.asUUID())) + .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet) + .map(this::rowToMessageId) + .collect(Guavate.toImmutableSet())); + } + + private MessageId rowToMessageId(Row row) { + return messageIdFactory.fromString(row.getString(MESSAGE_ID)); + } + + public CompletableFuture<Void> storeAttachmentForMessageId(AttachmentId attachmentId, MessageId ownerMessageId) { + return cassandraAsyncExecutor.executeVoid( + insertStatement.bind() + .setUUID(ATTACHMENT_ID_AS_UUID, attachmentId.asUUID()) + .setString(ATTACHMENT_ID, attachmentId.getId()) + .setString(MESSAGE_ID, ownerMessageId.serialize())); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraAttachmentModule.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraAttachmentModule.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraAttachmentModule.java index 50bee8b..dd2bc46 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraAttachmentModule.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraAttachmentModule.java @@ -30,6 +30,7 @@ import org.apache.james.backends.cassandra.components.CassandraModule; import org.apache.james.backends.cassandra.components.CassandraTable; import org.apache.james.backends.cassandra.components.CassandraType; import org.apache.james.backends.cassandra.utils.CassandraConstants; +import org.apache.james.mailbox.cassandra.table.CassandraAttachmentMessageIdTable; import org.apache.james.mailbox.cassandra.table.CassandraAttachmentTable; import org.apache.james.mailbox.cassandra.table.CassandraAttachmentV2Table; @@ -65,7 +66,18 @@ public class CassandraAttachmentModule implements CassandraModule { .caching(SchemaBuilder.KeyCaching.ALL, SchemaBuilder.rows(CassandraConstants.DEFAULT_CACHED_ROW_PER_PARTITION)) .comment("Holds attachment for fast attachment retrieval. Content of messages is stored" + - "in `blobs` and `blobparts` tables."))); + "in `blobs` and `blobparts` tables.")), + new CassandraTable(CassandraAttachmentMessageIdTable.TABLE_NAME, + SchemaBuilder.createTable(CassandraAttachmentMessageIdTable.TABLE_NAME) + .ifNotExists() + .addPartitionKey(CassandraAttachmentMessageIdTable.ATTACHMENT_ID_AS_UUID, uuid()) + .addColumn(CassandraAttachmentMessageIdTable.ATTACHMENT_ID, text()) + .addClusteringColumn(CassandraAttachmentMessageIdTable.MESSAGE_ID, text()) + .withOptions() + .compactionOptions(SchemaBuilder.leveledStrategy()) + .caching(SchemaBuilder.KeyCaching.ALL, + SchemaBuilder.rows(CassandraConstants.DEFAULT_CACHED_ROW_PER_PARTITION)) + .comment("Holds ids of messages owning the attachment"))); types = ImmutableList.of(); } http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraAttachmentMessageIdTable.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraAttachmentMessageIdTable.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraAttachmentMessageIdTable.java new file mode 100644 index 0000000..42655fb --- /dev/null +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraAttachmentMessageIdTable.java @@ -0,0 +1,30 @@ +/**************************************************************** + * 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.cassandra.table; + +public interface CassandraAttachmentMessageIdTable { + + String TABLE_NAME = "attachmentMessageId"; + String ATTACHMENT_ID_AS_UUID = "attachmentIdAsUUID"; + String ATTACHMENT_ID = "attachmentId"; + String MESSAGE_ID = "messageId"; + String[] FIELDS = { ATTACHMENT_ID_AS_UUID, ATTACHMENT_ID, MESSAGE_ID }; + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java index 7e94b3c..53345db 100644 --- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java +++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraSubscriptionManagerTest.java @@ -29,6 +29,7 @@ import org.apache.james.mailbox.SubscriptionManager; import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO; import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAO; import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2; +import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO; import org.apache.james.mailbox.cassandra.mail.CassandraBlobsDAO; import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO; import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO; @@ -91,6 +92,7 @@ public class CassandraSubscriptionManagerTest extends AbstractSubscriptionManage CassandraDeletedMessageDAO deletedMessageDAO = null; CassandraAttachmentDAOV2 attachmentDAOV2 = null; CassandraBlobsDAO cassandraBlobsDAO = null; + CassandraAttachmentMessageIdDAO attachmentMessageIdDAO = null; return new CassandraSubscriptionManager( new CassandraMailboxSessionMapperFactory( new CassandraUidProvider(cassandra.getConf()), @@ -109,6 +111,7 @@ public class CassandraSubscriptionManagerTest extends AbstractSubscriptionManage attachmentDAOV2, deletedMessageDAO, cassandraBlobsDAO, + attachmentMessageIdDAO, CassandraUtils.WITH_DEFAULT_CONFIGURATION, CassandraConfiguration.DEFAULT_CONFIGURATION)); } http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java index 312accd..fcd3467 100644 --- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java +++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java @@ -26,6 +26,7 @@ import org.apache.james.mailbox.cassandra.ids.CassandraMessageId; import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO; import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAO; import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2; +import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO; import org.apache.james.mailbox.cassandra.mail.CassandraBlobsDAO; import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO; import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO; @@ -61,7 +62,9 @@ public class TestCassandraMailboxSessionMapperFactory { new CassandraAttachmentDAO(session, CassandraUtils.WITH_DEFAULT_CONFIGURATION, CassandraConfiguration.DEFAULT_CONFIGURATION), new CassandraAttachmentDAOV2(session), new CassandraDeletedMessageDAO(session), - cassandraBlobsDAO, CassandraUtils.WITH_DEFAULT_CONFIGURATION, + cassandraBlobsDAO, + new CassandraAttachmentMessageIdDAO(session, factory, CassandraUtils.WITH_DEFAULT_CONFIGURATION), + CassandraUtils.WITH_DEFAULT_CONFIGURATION, CassandraConfiguration.DEFAULT_CONFIGURATION); } http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java index 7408840..d9ac703 100644 --- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java +++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentFallbackTest.java @@ -30,6 +30,7 @@ import org.apache.james.backends.cassandra.init.CassandraConfiguration; import org.apache.james.backends.cassandra.init.CassandraModuleComposite; import org.apache.james.backends.cassandra.utils.CassandraUtils; import org.apache.james.mailbox.cassandra.ids.BlobId; +import org.apache.james.mailbox.cassandra.ids.CassandraMessageId; import org.apache.james.mailbox.cassandra.modules.CassandraAttachmentModule; import org.apache.james.mailbox.cassandra.modules.CassandraBlobModule; import org.apache.james.mailbox.exception.AttachmentNotFoundException; @@ -54,6 +55,7 @@ public class CassandraAttachmentFallbackTest { private CassandraAttachmentDAO attachmentDAO; private CassandraAttachmentMapper attachmentMapper; private CassandraBlobsDAO blobsDAO; + private CassandraAttachmentMessageIdDAO attachmentMessageIdDAO; @Before public void setUp() throws Exception { @@ -71,7 +73,8 @@ public class CassandraAttachmentFallbackTest { CassandraUtils.WITH_DEFAULT_CONFIGURATION, CassandraConfiguration.DEFAULT_CONFIGURATION); blobsDAO = new CassandraBlobsDAO(cassandra.getConf()); - attachmentMapper = new CassandraAttachmentMapper(attachmentDAO, attachmentDAOV2, blobsDAO); + attachmentMessageIdDAO = new CassandraAttachmentMessageIdDAO(cassandra.getConf(), new CassandraMessageId.Factory(), CassandraUtils.WITH_DEFAULT_CONFIGURATION); + attachmentMapper = new CassandraAttachmentMapper(attachmentDAO, attachmentDAOV2, blobsDAO, attachmentMessageIdDAO); } @After http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapperTest.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapperTest.java index ed3948d..85acca5 100644 --- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapperTest.java +++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraAttachmentMapperTest.java @@ -22,6 +22,7 @@ package org.apache.james.mailbox.cassandra.mail; import org.apache.james.backends.cassandra.CassandraCluster; import org.apache.james.backends.cassandra.DockerCassandraRule; import org.apache.james.backends.cassandra.init.CassandraModuleComposite; +import org.apache.james.mailbox.cassandra.ids.CassandraMessageId; import org.apache.james.mailbox.cassandra.modules.CassandraAclModule; import org.apache.james.mailbox.cassandra.modules.CassandraAnnotationModule; import org.apache.james.mailbox.cassandra.modules.CassandraApplicableFlagsModule; @@ -36,6 +37,7 @@ import org.apache.james.mailbox.cassandra.modules.CassandraMessageModule; import org.apache.james.mailbox.cassandra.modules.CassandraModSeqModule; import org.apache.james.mailbox.cassandra.modules.CassandraUidModule; import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.store.mail.model.AttachmentMapperTest; import org.apache.james.mailbox.store.mail.model.MapperProvider; import org.junit.After; @@ -77,4 +79,9 @@ public class CassandraAttachmentMapperTest extends AttachmentMapperTest { protected MapperProvider createMapperProvider() { return new CassandraMapperProvider(cassandra); } + + @Override + protected MessageId generateMessageId() { + return new CassandraMessageId.Factory().generate(); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java ---------------------------------------------------------------------- diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java index 7620ddc..6732816 100644 --- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java +++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/InMemoryMessageManager.java @@ -46,9 +46,10 @@ public class InMemoryMessageManager extends StoreMessageManager { @Override protected void storeAttachment(final MailboxMessage message, final List<MessageAttachment> messageAttachments, final MailboxSession session) throws MailboxException { mapperFactory.getAttachmentMapper(session) - .storeAttachments( + .storeAttachmentsForMessage( messageAttachments.stream() .map(MessageAttachment::getAttachment) - .collect(Guavate.toImmutableList())); + .collect(Guavate.toImmutableList()), + message.getMessageId()); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryAttachmentMapper.java ---------------------------------------------------------------------- diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryAttachmentMapper.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryAttachmentMapper.java index 3b4f92d..314226b 100644 --- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryAttachmentMapper.java +++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryAttachmentMapper.java @@ -27,19 +27,25 @@ import org.apache.james.mailbox.exception.AttachmentNotFoundException; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.Attachment; import org.apache.james.mailbox.model.AttachmentId; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.store.mail.AttachmentMapper; import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; public class InMemoryAttachmentMapper implements AttachmentMapper { private static final int INITIAL_SIZE = 128; private final Map<AttachmentId, Attachment> attachmentsById; + private final Multimap<AttachmentId, MessageId> messageIdsByAttachmentId; public InMemoryAttachmentMapper() { attachmentsById = new ConcurrentHashMap<>(INITIAL_SIZE); + messageIdsByAttachmentId = Multimaps.synchronizedSetMultimap(HashMultimap.create()); } @Override @@ -79,9 +85,15 @@ public class InMemoryAttachmentMapper implements AttachmentMapper { } @Override - public void storeAttachments(Collection<Attachment> attachments) throws MailboxException { + public void storeAttachmentsForMessage(Collection<Attachment> attachments, MessageId ownerMessageId) throws MailboxException { for (Attachment attachment: attachments) { storeAttachment(attachment); + messageIdsByAttachmentId.put(attachment.getAttachmentId(), ownerMessageId); } } + + @Override + public Collection<MessageId> getOwnerMessageIds(AttachmentId attachmentId) throws MailboxException { + return messageIdsByAttachmentId.get(attachmentId); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/MemoryAttachmentMapperTest.java ---------------------------------------------------------------------- diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/MemoryAttachmentMapperTest.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/MemoryAttachmentMapperTest.java index 7b60d83..00e6ae1 100644 --- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/MemoryAttachmentMapperTest.java +++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/mail/MemoryAttachmentMapperTest.java @@ -20,6 +20,8 @@ package org.apache.james.mailbox.inmemory.mail; import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.inmemory.InMemoryMessageId; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.store.mail.model.AttachmentMapperTest; import org.apache.james.mailbox.store.mail.model.MapperProvider; import org.junit.Before; @@ -35,4 +37,9 @@ public class MemoryAttachmentMapperTest extends AttachmentMapperTest { protected MapperProvider createMapperProvider() { return new InMemoryMapperProvider(); } + + @Override + protected MessageId generateMessageId() { + return new InMemoryMessageId.Factory().generate(); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreAttachmentManager.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreAttachmentManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreAttachmentManager.java index 88799d9..0d2b8a6 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreAttachmentManager.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreAttachmentManager.java @@ -30,6 +30,7 @@ import org.apache.james.mailbox.exception.AttachmentNotFoundException; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.Attachment; import org.apache.james.mailbox.model.AttachmentId; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.store.mail.AttachmentMapper; import org.apache.james.mailbox.store.mail.AttachmentMapperFactory; @@ -66,7 +67,12 @@ public class StoreAttachmentManager implements AttachmentManager { } @Override - public void storeAttachments(Collection<Attachment> attachments, MailboxSession mailboxSession) throws MailboxException { - getAttachmentMapper(mailboxSession).storeAttachments(attachments); + public void storeAttachmentsForMessage(Collection<Attachment> attachments, MessageId ownerMessageId, MailboxSession mailboxSession) throws MailboxException { + getAttachmentMapper(mailboxSession).storeAttachmentsForMessage(attachments, ownerMessageId); + } + + @Override + public Collection<MessageId> getOwnerMessageIds(AttachmentId attachmentId, MailboxSession mailboxSession) throws MailboxException { + return getAttachmentMapper(mailboxSession).getOwnerMessageIds(attachmentId); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/AttachmentMapper.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/AttachmentMapper.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/AttachmentMapper.java index 06e84a7..c9c12bb 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/AttachmentMapper.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/AttachmentMapper.java @@ -25,6 +25,7 @@ import org.apache.james.mailbox.exception.AttachmentNotFoundException; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.Attachment; import org.apache.james.mailbox.model.AttachmentId; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.store.transaction.Mapper; public interface AttachmentMapper extends Mapper { @@ -35,5 +36,7 @@ public interface AttachmentMapper extends Mapper { void storeAttachment(Attachment attachment) throws MailboxException; - void storeAttachments(Collection<Attachment> attachments) throws MailboxException; + void storeAttachmentsForMessage(Collection<Attachment> attachments, MessageId ownerMessageId) throws MailboxException; + + Collection<MessageId> getOwnerMessageIds(AttachmentId attachmentId) throws MailboxException; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/1b4d9239/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentMapperTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentMapperTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentMapperTest.java index a915d36..e56ba13 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentMapperTest.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentMapperTest.java @@ -21,12 +21,14 @@ package org.apache.james.mailbox.store.mail.model; import static org.assertj.core.api.Assertions.assertThat; +import java.util.Collection; import java.util.List; import org.apache.james.mailbox.exception.AttachmentNotFoundException; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.Attachment; import org.apache.james.mailbox.model.AttachmentId; +import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.store.mail.AttachmentMapper; import org.junit.Assume; import org.junit.Rule; @@ -37,6 +39,7 @@ import com.google.common.base.Charsets; import com.google.common.collect.ImmutableList; public abstract class AttachmentMapperTest { + private static final AttachmentId UNKNOWN_ATTACHMENT_ID = AttachmentId.forPayload("unknown".getBytes(Charsets.UTF_8)); private AttachmentMapper attachmentMapper; private MapperProvider mapperProvider; @@ -46,6 +49,8 @@ public abstract class AttachmentMapperTest { protected abstract MapperProvider createMapperProvider(); + protected abstract MessageId generateMessageId(); + public void setUp() throws MailboxException { mapperProvider = createMapperProvider(); Assume.assumeTrue(mapperProvider.getSupportedCapabilities().contains(MapperProvider.Capabilities.ATTACHMENT)); @@ -61,7 +66,7 @@ public abstract class AttachmentMapperTest { @Test public void getAttachmentShouldThrowWhenNonReferencedAttachmentId() throws Exception { expected.expect(AttachmentNotFoundException.class); - attachmentMapper.getAttachment(AttachmentId.forPayload("unknown".getBytes(Charsets.UTF_8))); + attachmentMapper.getAttachment(UNKNOWN_ATTACHMENT_ID); } @Test @@ -93,7 +98,7 @@ public abstract class AttachmentMapperTest { AttachmentId attachmentId1 = expected1.getAttachmentId(); AttachmentId attachmentId2 = expected2.getAttachmentId(); //When - attachmentMapper.storeAttachments(ImmutableList.of(expected1, expected2)); + attachmentMapper.storeAttachmentsForMessage(ImmutableList.of(expected1, expected2), generateMessageId()); //Then Attachment attachment1 = attachmentMapper.getAttachment(attachmentId1); Attachment attachment2 = attachmentMapper.getAttachment(attachmentId2); @@ -109,7 +114,7 @@ public abstract class AttachmentMapperTest { @Test public void getAttachmentsShouldReturnEmptyListWhenNonReferencedAttachmentId() throws Exception { - List<Attachment> attachments = attachmentMapper.getAttachments(ImmutableList.of(AttachmentId.forPayload("unknown".getBytes(Charsets.UTF_8)))); + List<Attachment> attachments = attachmentMapper.getAttachments(ImmutableList.of(UNKNOWN_ATTACHMENT_ID)); assertThat(attachments).isEmpty(); } @@ -136,4 +141,127 @@ public abstract class AttachmentMapperTest { //Then assertThat(attachments).contains(expected, expected2); } + + @Test + public void getOwnerMessageIdsShouldReturnEmptyWhenNone() throws Exception { + Collection<MessageId> messageIds = attachmentMapper.getOwnerMessageIds(UNKNOWN_ATTACHMENT_ID); + + assertThat(messageIds).isEmpty(); + } + + @Test + public void getOwnerMessageIdsShouldReturnEmptyWhenStoredWithoutMessageId() throws Exception { + //Given + Attachment attachment = Attachment.builder() + .bytes("payload".getBytes(Charsets.UTF_8)) + .type("content") + .build(); + AttachmentId attachmentId = attachment.getAttachmentId(); + attachmentMapper.storeAttachment(attachment); + + //When + Collection<MessageId> messageIds = attachmentMapper.getOwnerMessageIds(attachmentId); + //Then + assertThat(messageIds).isEmpty(); + } + + @Test + public void getOwnerMessageIdsShouldReturnMessageIdWhenStoredWithMessageId() throws Exception { + //Given + Attachment attachment = Attachment.builder() + .bytes("payload".getBytes(Charsets.UTF_8)) + .type("content") + .build(); + AttachmentId attachmentId = attachment.getAttachmentId(); + MessageId messageId = generateMessageId(); + attachmentMapper.storeAttachmentsForMessage(ImmutableList.of(attachment), messageId); + + //When + Collection<MessageId> messageIds = attachmentMapper.getOwnerMessageIds(attachmentId); + //Then + assertThat(messageIds).containsOnly(messageId); + } + + @Test + public void getOwnerMessageIdsShouldReturnTwoMessageIdsWhenStoredTwice() throws Exception { + //Given + Attachment attachment = Attachment.builder() + .bytes("payload".getBytes(Charsets.UTF_8)) + .type("content") + .build(); + AttachmentId attachmentId = attachment.getAttachmentId(); + MessageId messageId1 = generateMessageId(); + MessageId messageId2 = generateMessageId(); + attachmentMapper.storeAttachmentsForMessage(ImmutableList.of(attachment), messageId1); + attachmentMapper.storeAttachmentsForMessage(ImmutableList.of(attachment), messageId2); + + //When + Collection<MessageId> messageIds = attachmentMapper.getOwnerMessageIds(attachmentId); + //Then + assertThat(messageIds).containsOnly(messageId1, messageId2); + } + + @Test + public void getOwnerMessageIdsShouldReturnOnlyMatchingMessageId() throws Exception { + //Given + Attachment attachment = Attachment.builder() + .bytes("payload".getBytes(Charsets.UTF_8)) + .type("content") + .build(); + Attachment otherAttachment = Attachment.builder() + .bytes("something different".getBytes(Charsets.UTF_8)) + .type("content") + .build(); + AttachmentId attachmentId = attachment.getAttachmentId(); + MessageId messageId1 = generateMessageId(); + MessageId messageId2 = generateMessageId(); + attachmentMapper.storeAttachmentsForMessage(ImmutableList.of(attachment), messageId1); + attachmentMapper.storeAttachmentsForMessage(ImmutableList.of(otherAttachment), messageId2); + + //When + Collection<MessageId> messageIds = attachmentMapper.getOwnerMessageIds(attachmentId); + //Then + assertThat(messageIds).containsOnly(messageId1); + } + + @Test + public void getOwnerMessageIdsShouldReturnOnlyOneMessageIdWhenStoredTwice() throws Exception { + //Given + Attachment attachment = Attachment.builder() + .bytes("payload".getBytes(Charsets.UTF_8)) + .type("content") + .build(); + AttachmentId attachmentId = attachment.getAttachmentId(); + MessageId messageId = generateMessageId(); + attachmentMapper.storeAttachmentsForMessage(ImmutableList.of(attachment), messageId); + attachmentMapper.storeAttachmentsForMessage(ImmutableList.of(attachment), messageId); + + //When + Collection<MessageId> messageIds = attachmentMapper.getOwnerMessageIds(attachmentId); + //Then + assertThat(messageIds).containsOnly(messageId); + } + + @Test + public void getOwnerMessageIdsShouldReturnMessageIdForTwoAttachmentsWhenBothStoredAtTheSameTime() throws Exception { + //Given + Attachment attachment = Attachment.builder() + .bytes("payload".getBytes(Charsets.UTF_8)) + .type("content") + .build(); + Attachment attachment2 = Attachment.builder() + .bytes("other payload".getBytes(Charsets.UTF_8)) + .type("content") + .build(); + AttachmentId attachmentId = attachment.getAttachmentId(); + AttachmentId attachmentId2 = attachment2.getAttachmentId(); + MessageId messageId = generateMessageId(); + attachmentMapper.storeAttachmentsForMessage(ImmutableList.of(attachment, attachment2), messageId); + + //When + Collection<MessageId> messageIds = attachmentMapper.getOwnerMessageIds(attachmentId); + Collection<MessageId> messageIds2 = attachmentMapper.getOwnerMessageIds(attachmentId2); + //Then + assertThat(messageIds).isEqualTo(messageIds2); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
