JAMES-1791 Support inline attachments
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/896bc961 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/896bc961 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/896bc961 Branch: refs/heads/master Commit: 896bc961ab22b4ec0b979a7c6fab9f37561d581c Parents: 85aeb1e Author: Antoine Duprat <adup...@linagora.com> Authored: Tue Jul 5 15:52:20 2016 +0200 Committer: Antoine Duprat <adup...@linagora.com> Committed: Fri Jul 8 11:28:30 2016 +0200 ---------------------------------------------------------------------- .../CassandraMailboxSessionMapperFactory.java | 2 +- .../mail/CassandraAttachmentMapper.java | 26 +++ .../cassandra/mail/CassandraMessageMapper.java | 55 ++++- .../modules/CassandraMessageModule.java | 36 ++-- .../cassandra/table/CassandraMessageTable.java | 12 +- .../cassandra/mail/CassandraMappersTest.java | 59 ++++++ .../cassandra/mail/CassandraMappersTests.java | 59 ------ .../mailbox/hbase/mail/HBaseMailboxMessage.java | 6 +- .../james/mailbox/jcr/JCRMessageManager.java | 4 +- .../jcr/mail/model/JCRMailboxMessage.java | 6 +- .../james/mailbox/jpa/JPAMessageManager.java | 4 +- .../openjpa/AbstractJPAMailboxMessage.java | 6 +- .../jpa/openjpa/OpenJPAMessageManager.java | 4 +- .../maildir/mail/model/MaildirMessage.java | 25 +-- .../inmemory/mail/InMemoryAttachmentMapper.java | 15 ++ .../mailbox/store/StoreMessageManager.java | 22 +- .../mailbox/store/mail/AttachmentMapper.java | 3 + .../store/mail/NoopAttachmentMapper.java | 6 + .../mail/model/DelegatingMailboxMessage.java | 4 +- .../james/mailbox/store/mail/model/Message.java | 6 +- .../store/mail/model/MessageAttachment.java | 123 ++++++++++++ .../store/mail/model/impl/MessageParser.java | 105 ++++++++-- .../mail/model/impl/SimpleMailboxMessage.java | 10 +- .../store/mail/model/impl/SimpleMessage.java | 14 +- .../AbstractMailboxManagerAttachmentTest.java | 50 ++--- .../mailbox/store/SimpleMailboxMembership.java | 4 +- .../store/mail/model/AttachmentMapperTest.java | 38 ++++ .../mailbox/store/mail/model/MessageAssert.java | 4 +- .../store/mail/model/MessageAttachmentTest.java | 100 +++++++++ .../store/mail/model/MessageMapperTest.java | 66 ++++-- .../mail/model/impl/MessageParserTest.java | 59 ++++-- .../eml/oneAttachmentAndSomeInlined.eml | 39 ---- .../eml/oneAttachmentAndSomeTextInlined.eml | 39 ++++ .../test/resources/eml/oneInlinedAttachment.eml | 201 +++++++++++++++++++ .../cucumber/GetMessagesMethodStepdefs.java | 5 +- .../cucumber/util/BooleanFromString.java | 34 ++++ .../cucumber/util/IntegerFromString.java | 35 ++++ .../cucumber/util/ObjectFromString.java | 27 +++ .../util/ObjectFromStringExtractor.java | 42 ++++ .../cucumber/util/StringFromString.java | 35 ++++ .../integration/cucumber/util/TableRow.java | 50 +++++ .../test/resources/cucumber/GetMessages.feature | 18 +- .../src/test/resources/eml/twoAttachments.eml | 3 +- .../protocols/jmap/doc/specs/spec/message.mdwn | 3 - .../james/jmap/methods/GetMessagesMethod.java | 45 +---- .../org/apache/james/jmap/model/Attachment.java | 2 +- .../apache/james/jmap/model/MessageFactory.java | 15 +- .../jmap/methods/GetMessagesMethodTest.java | 24 +-- .../james/jmap/model/MailboxMessageTest.java | 15 +- 49 files changed, 1229 insertions(+), 336 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/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 77cf9d7..639db36 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 @@ -68,7 +68,7 @@ public class CassandraMailboxSessionMapperFactory extends MailboxSessionMapperFa @Override public CassandraMessageMapper createMessageMapper(MailboxSession mailboxSession) { - return new CassandraMessageMapper(session, uidProvider, modSeqProvider, null, maxRetry, typesProvider); + return new CassandraMessageMapper(session, uidProvider, modSeqProvider, null, maxRetry, typesProvider, createAttachmentMapper(mailboxSession)); } @Override http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/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 fcbfec8..0cceb19 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 @@ -20,6 +20,7 @@ package org.apache.james.mailbox.cassandra.mail; import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; +import static com.datastax.driver.core.querybuilder.QueryBuilder.in; 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.CassandraAttachmentTable.FIELDS; @@ -33,6 +34,7 @@ import static org.apache.james.mailbox.cassandra.table.CassandraAttachmentTable. import java.io.IOException; import java.nio.ByteBuffer; import java.util.Collection; +import java.util.List; import java.util.concurrent.CompletableFuture; import org.apache.commons.io.IOUtils; @@ -42,13 +44,17 @@ import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.store.mail.AttachmentMapper; import org.apache.james.mailbox.store.mail.model.Attachment; import org.apache.james.mailbox.store.mail.model.AttachmentId; +import org.apache.james.util.streams.ImmutableCollectors; +import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.Row; import com.datastax.driver.core.Session; import com.github.fge.lambdas.Throwing; import com.github.fge.lambdas.ThrownByLambdaException; import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; public class CassandraAttachmentMapper implements AttachmentMapper { @@ -89,6 +95,26 @@ public class CassandraAttachmentMapper implements AttachmentMapper { } @Override + public List<Attachment> getAttachments(List<AttachmentId> attachmentIds) { + Preconditions.checkArgument(attachmentIds != null); + List<String> ids = attachmentIds.stream() + .map(AttachmentId::getId) + .collect(ImmutableCollectors.toImmutableList()); + return cassandraAsyncExecutor.execute( + select(FIELDS) + .from(TABLE_NAME) + .where(in(ID, ids))) + .thenApply(this::attachments) + .join(); + } + + private List<Attachment> attachments(ResultSet resultSet) { + Builder<Attachment> builder = ImmutableList.<Attachment> builder(); + resultSet.forEach(row -> builder.add(attachment(row))); + return builder.build(); + } + + @Override public void storeAttachment(Attachment attachment) throws MailboxException { try { asyncStoreAttachment(attachment).join(); http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java index 22fe268..0232cfb 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java @@ -28,7 +28,7 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.lte; import static com.datastax.driver.core.querybuilder.QueryBuilder.select; import static com.datastax.driver.core.querybuilder.QueryBuilder.set; import static com.datastax.driver.core.querybuilder.QueryBuilder.update; -import static org.apache.james.mailbox.cassandra.table.CassandraMessageTable.ATTACHMENTS_IDS; +import static org.apache.james.mailbox.cassandra.table.CassandraMessageTable.ATTACHMENTS; import static org.apache.james.mailbox.cassandra.table.CassandraMessageTable.BODY; import static org.apache.james.mailbox.cassandra.table.CassandraMessageTable.BODY_CONTENT; import static org.apache.james.mailbox.cassandra.table.CassandraMessageTable.BODY_OCTECTS; @@ -64,6 +64,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import javax.mail.Flags; @@ -80,6 +81,7 @@ import org.apache.james.mailbox.cassandra.CassandraId; import org.apache.james.mailbox.cassandra.mail.utils.MessageDeletedDuringFlagsUpdateException; import org.apache.james.mailbox.cassandra.table.CassandraMailboxCountersTable; import org.apache.james.mailbox.cassandra.table.CassandraMessageTable; +import org.apache.james.mailbox.cassandra.table.CassandraMessageTable.Attachments; import org.apache.james.mailbox.cassandra.table.CassandraMessageTable.Properties; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.MessageMetaData; @@ -87,12 +89,15 @@ import org.apache.james.mailbox.model.MessageRange; import org.apache.james.mailbox.model.UpdatedFlags; import org.apache.james.mailbox.store.FlagsUpdateCalculator; import org.apache.james.mailbox.store.SimpleMessageMetaData; +import org.apache.james.mailbox.store.mail.AttachmentMapper; import org.apache.james.mailbox.store.mail.MessageMapper; import org.apache.james.mailbox.store.mail.ModSeqProvider; import org.apache.james.mailbox.store.mail.UidProvider; +import org.apache.james.mailbox.store.mail.model.Attachment; import org.apache.james.mailbox.store.mail.model.AttachmentId; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage; import org.apache.james.mailbox.store.mail.model.impl.SimpleProperty; @@ -107,6 +112,7 @@ import com.datastax.driver.core.querybuilder.Assignment; import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.Select; import com.datastax.driver.core.querybuilder.Select.Where; +import com.github.fge.lambdas.Throwing; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.io.ByteStreams; @@ -120,14 +126,16 @@ public class CassandraMessageMapper implements MessageMapper { private final UidProvider uidProvider; private final CassandraTypesProvider typesProvider; private final int maxRetries; + private final AttachmentMapper attachmentMapper; - public CassandraMessageMapper(Session session, UidProvider uidProvider, ModSeqProvider modSeqProvider, MailboxSession mailboxSession, int maxRetries, CassandraTypesProvider typesProvider) { + public CassandraMessageMapper(Session session, UidProvider uidProvider, ModSeqProvider modSeqProvider, MailboxSession mailboxSession, int maxRetries, CassandraTypesProvider typesProvider, AttachmentMapper attachmentMapper) { this.session = session; this.uidProvider = uidProvider; this.modSeqProvider = modSeqProvider; this.mailboxSession = mailboxSession; this.maxRetries = maxRetries; this.typesProvider = typesProvider; + this.attachmentMapper = attachmentMapper; } @Override @@ -305,7 +313,7 @@ public class CassandraMessageMapper implements MessageMapper { getFlags(row), getPropertyBuilder(row), CassandraId.of(row.getUUID(MAILBOX_ID)), - getAttachmentsIds(row, fetchType)); + getAttachments(row, fetchType)); message.setUid(row.getLong(IMAP_UID)); message.setModSeq(row.getLong(MOD_SEQ)); return message; @@ -333,19 +341,42 @@ public class CassandraMessageMapper implements MessageMapper { return property; } - private List<AttachmentId> getAttachmentsIds(Row row, FetchType fetchType) { + private List<MessageAttachment> getAttachments(Row row, FetchType fetchType) { switch (fetchType) { case Full: case Body: - return row.getList(ATTACHMENTS_IDS, String.class) + List<UDTValue> udtValues = row.getList(ATTACHMENTS, UDTValue.class); + Map<AttachmentId,Attachment> attachmentsById = attachmentsById(row, udtValues); + + return udtValues .stream() - .map(AttachmentId::from) + .map(Throwing.function(x -> + MessageAttachment.builder() + .attachment(attachmentsById.get(attachmentIdFrom(x))) + .cid(x.getString(Attachments.CID)) + .isInline(x.getBool(Attachments.IS_INLINE)) + .build())) .collect(ImmutableCollectors.toImmutableList()); default: return ImmutableList.of(); } } + private Map<AttachmentId,Attachment> attachmentsById(Row row, List<UDTValue> udtValues) { + return attachmentMapper.getAttachments(attachmentIds(udtValues)).stream() + .collect(ImmutableCollectors.toImmutableMap(Attachment::getAttachmentId, Function.identity())); + } + + private List<AttachmentId> attachmentIds(List<UDTValue> udtValues) { + return udtValues.stream() + .map(this::attachmentIdFrom) + .collect(ImmutableCollectors.toImmutableList()); + } + + private AttachmentId attachmentIdFrom(UDTValue udtValue) { + return AttachmentId.from(udtValue.getString(Attachments.ID)); + } + private MessageMetaData save(Mailbox mailbox, MailboxMessage message) throws MailboxException { try { CassandraId mailboxId = (CassandraId) mailbox.getMailboxId(); @@ -375,8 +406,8 @@ public class CassandraMessageMapper implements MessageMapper { .setString(Properties.VALUE, x.getValue())) .collect(Collectors.toList())) .value(TEXTUAL_LINE_COUNT, message.getTextualLineCount()) - .value(ATTACHMENTS_IDS, message.getAttachmentsIds().stream() - .map(AttachmentId::getId) + .value(ATTACHMENTS, message.getAttachments().stream() + .map(this::toUDT) .collect(Collectors.toList()))); return new SimpleMessageMetaData(message); @@ -385,6 +416,14 @@ public class CassandraMessageMapper implements MessageMapper { } } + private UDTValue toUDT(MessageAttachment messageAttachment) { + return typesProvider.getDefinedUserType(ATTACHMENTS) + .newValue() + .setString(Attachments.ID, messageAttachment.getAttachmentId().getId()) + .setString(Attachments.CID, messageAttachment.getCid().orNull()) + .setBool(Attachments.IS_INLINE, messageAttachment.isInline()); + } + private Set<String> userFlagsSet(MailboxMessage message) { return Arrays.stream(message.createFlags().getUserFlags()).collect(Collectors.toSet()); } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java index 3565213..03494e9 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/modules/CassandraMessageModule.java @@ -19,27 +19,27 @@ package org.apache.james.mailbox.cassandra.modules; -import com.datastax.driver.core.schemabuilder.SchemaBuilder; -import org.apache.james.backends.cassandra.components.CassandraIndex; -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.mailbox.cassandra.table.CassandraMessageTable; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - import static com.datastax.driver.core.DataType.bigint; import static com.datastax.driver.core.DataType.blob; import static com.datastax.driver.core.DataType.cboolean; import static com.datastax.driver.core.DataType.cint; -import static com.datastax.driver.core.DataType.frozenList; import static com.datastax.driver.core.DataType.set; import static com.datastax.driver.core.DataType.text; import static com.datastax.driver.core.DataType.timestamp; import static com.datastax.driver.core.DataType.timeuuid; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apache.james.backends.cassandra.components.CassandraIndex; +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.mailbox.cassandra.table.CassandraMessageTable; + +import com.datastax.driver.core.schemabuilder.SchemaBuilder; + public class CassandraMessageModule implements CassandraModule { private final List<CassandraTable> tables; @@ -69,7 +69,7 @@ public class CassandraMessageModule implements CassandraModule { .addColumn(CassandraMessageTable.Flag.SEEN, cboolean()) .addColumn(CassandraMessageTable.Flag.USER, cboolean()) .addColumn(CassandraMessageTable.Flag.USER_FLAGS, set(text())) - .addColumn(CassandraMessageTable.ATTACHMENTS_IDS, frozenList(text())) + .addUDTListColumn(CassandraMessageTable.ATTACHMENTS, SchemaBuilder.frozen(CassandraMessageTable.ATTACHMENTS)) .addUDTListColumn(CassandraMessageTable.PROPERTIES, SchemaBuilder.frozen(CassandraMessageTable.PROPERTIES)))); index = Arrays.asList( new CassandraIndex( @@ -87,13 +87,19 @@ public class CassandraMessageModule implements CassandraModule { .ifNotExists() .onTable(CassandraMessageTable.TABLE_NAME) .andColumn(CassandraMessageTable.Flag.DELETED))); - types = Collections.singletonList( + types = Arrays.asList( new CassandraType(CassandraMessageTable.PROPERTIES, SchemaBuilder.createType(CassandraMessageTable.PROPERTIES) .ifNotExists() .addColumn(CassandraMessageTable.Properties.NAMESPACE, text()) .addColumn(CassandraMessageTable.Properties.NAME, text()) - .addColumn(CassandraMessageTable.Properties.VALUE, text()))); + .addColumn(CassandraMessageTable.Properties.VALUE, text())), + new CassandraType(CassandraMessageTable.ATTACHMENTS, + SchemaBuilder.createType(CassandraMessageTable.ATTACHMENTS) + .ifNotExists() + .addColumn(CassandraMessageTable.Attachments.ID, text()) + .addColumn(CassandraMessageTable.Attachments.CID, text()) + .addColumn(CassandraMessageTable.Attachments.IS_INLINE, cboolean()))); } @Override http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageTable.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageTable.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageTable.java index e2e19af..cbd89bf 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageTable.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMessageTable.java @@ -37,12 +37,12 @@ public interface CassandraMessageTable { String BODY_CONTENT = "bodyContent"; String HEADER_CONTENT = "headerContent"; String PROPERTIES = "properties"; - String ATTACHMENTS_IDS = "attachmentsIds"; + String ATTACHMENTS = "attachments"; - String[] FIELDS = { MAILBOX_ID, IMAP_UID, INTERNAL_DATE, MOD_SEQ, BODY_START_OCTET, FULL_CONTENT_OCTETS, BODY_OCTECTS, Flag.ANSWERED, Flag.DELETED, Flag.DRAFT, Flag.FLAGGED, Flag.RECENT, Flag.SEEN, Flag.USER, Flag.USER_FLAGS, BODY_CONTENT, HEADER_CONTENT, TEXTUAL_LINE_COUNT, PROPERTIES, ATTACHMENTS_IDS }; + String[] FIELDS = { MAILBOX_ID, IMAP_UID, INTERNAL_DATE, MOD_SEQ, BODY_START_OCTET, FULL_CONTENT_OCTETS, BODY_OCTECTS, Flag.ANSWERED, Flag.DELETED, Flag.DRAFT, Flag.FLAGGED, Flag.RECENT, Flag.SEEN, Flag.USER, Flag.USER_FLAGS, BODY_CONTENT, HEADER_CONTENT, TEXTUAL_LINE_COUNT, PROPERTIES, ATTACHMENTS }; String[] METADATA = { MAILBOX_ID, IMAP_UID, INTERNAL_DATE, MOD_SEQ, BODY_START_OCTET, FULL_CONTENT_OCTETS, BODY_OCTECTS, Flag.ANSWERED, Flag.DELETED, Flag.DRAFT, Flag.FLAGGED, Flag.RECENT, Flag.SEEN, Flag.USER, Flag.USER_FLAGS, TEXTUAL_LINE_COUNT, PROPERTIES }; String[] HEADERS = { MAILBOX_ID, IMAP_UID, INTERNAL_DATE, MOD_SEQ, BODY_START_OCTET, FULL_CONTENT_OCTETS, BODY_OCTECTS, Flag.ANSWERED, Flag.DELETED, Flag.DRAFT, Flag.FLAGGED, Flag.RECENT, Flag.SEEN, Flag.USER, Flag.USER_FLAGS, HEADER_CONTENT, TEXTUAL_LINE_COUNT, PROPERTIES }; - String[] BODY = { MAILBOX_ID, IMAP_UID, INTERNAL_DATE, MOD_SEQ, BODY_START_OCTET, FULL_CONTENT_OCTETS, BODY_OCTECTS, Flag.ANSWERED, Flag.DELETED, Flag.DRAFT, Flag.FLAGGED, Flag.RECENT, Flag.SEEN, Flag.USER, Flag.USER_FLAGS, BODY_CONTENT, TEXTUAL_LINE_COUNT, PROPERTIES, ATTACHMENTS_IDS }; + String[] BODY = { MAILBOX_ID, IMAP_UID, INTERNAL_DATE, MOD_SEQ, BODY_START_OCTET, FULL_CONTENT_OCTETS, BODY_OCTECTS, Flag.ANSWERED, Flag.DELETED, Flag.DRAFT, Flag.FLAGGED, Flag.RECENT, Flag.SEEN, Flag.USER, Flag.USER_FLAGS, BODY_CONTENT, TEXTUAL_LINE_COUNT, PROPERTIES, ATTACHMENTS }; interface Flag { String ANSWERED = "flagAnswered"; @@ -71,4 +71,10 @@ public interface CassandraMessageTable { String NAME = "name"; String VALUE = "value"; } + + interface Attachments { + String ID = "id"; + String CID = "cid"; + String IS_INLINE = "isInline"; + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMappersTest.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMappersTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMappersTest.java new file mode 100644 index 0000000..bf2eb64 --- /dev/null +++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMappersTest.java @@ -0,0 +1,59 @@ +/**************************************************************** + * 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 org.apache.james.mailbox.exception.MailboxException; +import org.junit.runner.RunWith; +import org.xenei.junit.contract.Contract; +import org.xenei.junit.contract.ContractImpl; +import org.xenei.junit.contract.ContractSuite; +import org.xenei.junit.contract.IProducer; + +import com.google.common.base.Throwables; + +@RunWith(ContractSuite.class) +@ContractImpl(CassandraMapperProvider.class) +public class CassandraMappersTest { + + private IProducer<CassandraMapperProvider> producer = new IProducer<CassandraMapperProvider>() { + + private final CassandraMapperProvider cassandraMapperProvider = new CassandraMapperProvider(); + + @Override + public CassandraMapperProvider newInstance() { + return cassandraMapperProvider; + } + + @Override + public void cleanUp() { + try { + cassandraMapperProvider.clearMapper(); + } catch (MailboxException e) { + throw Throwables.propagate(e); + } + } + }; + + @Contract.Inject + public IProducer<CassandraMapperProvider> getProducer() { + return producer; + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMappersTests.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMappersTests.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMappersTests.java deleted file mode 100644 index 9f37d64..0000000 --- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMappersTests.java +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************** - * 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 org.apache.james.mailbox.exception.MailboxException; -import org.junit.runner.RunWith; -import org.xenei.junit.contract.Contract; -import org.xenei.junit.contract.ContractImpl; -import org.xenei.junit.contract.ContractSuite; -import org.xenei.junit.contract.IProducer; - -import com.google.common.base.Throwables; - -@RunWith(ContractSuite.class) -@ContractImpl(CassandraMapperProvider.class) -public class CassandraMappersTests { - - private IProducer<CassandraMapperProvider> producer = new IProducer<CassandraMapperProvider>() { - - private final CassandraMapperProvider cassandraMapperProvider = new CassandraMapperProvider(); - - @Override - public CassandraMapperProvider newInstance() { - return cassandraMapperProvider; - } - - @Override - public void cleanUp() { - try { - cassandraMapperProvider.clearMapper(); - } catch (MailboxException e) { - throw Throwables.propagate(e); - } - } - }; - - @Contract.Inject - public IProducer<CassandraMapperProvider> getProducer() { - return producer; - } - -} http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/hbase/src/main/java/org/apache/james/mailbox/hbase/mail/HBaseMailboxMessage.java ---------------------------------------------------------------------- diff --git a/mailbox/hbase/src/main/java/org/apache/james/mailbox/hbase/mail/HBaseMailboxMessage.java b/mailbox/hbase/src/main/java/org/apache/james/mailbox/hbase/mail/HBaseMailboxMessage.java index ae8c54b..8e8266c 100644 --- a/mailbox/hbase/src/main/java/org/apache/james/mailbox/hbase/mail/HBaseMailboxMessage.java +++ b/mailbox/hbase/src/main/java/org/apache/james/mailbox/hbase/mail/HBaseMailboxMessage.java @@ -38,10 +38,10 @@ import org.apache.hadoop.conf.Configuration; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.hbase.HBaseId; import org.apache.james.mailbox.hbase.io.ChunkInputStream; -import org.apache.james.mailbox.store.mail.model.AttachmentId; import org.apache.james.mailbox.store.mail.model.DefaultMessageId; import org.apache.james.mailbox.store.mail.model.FlagsBuilder; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.MessageId; import org.apache.james.mailbox.store.mail.model.Property; import org.apache.james.mailbox.store.mail.model.impl.MessageUidComparator; @@ -355,7 +355,7 @@ public class HBaseMailboxMessage implements MailboxMessage { } @Override - public List<AttachmentId> getAttachmentsIds() { - throw new NotImplementedException("Attachments Ids not implemented"); + public List<MessageAttachment> getAttachments() { + throw new NotImplementedException("Attachments are not implemented"); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/jcr/src/main/java/org/apache/james/mailbox/jcr/JCRMessageManager.java ---------------------------------------------------------------------- diff --git a/mailbox/jcr/src/main/java/org/apache/james/mailbox/jcr/JCRMessageManager.java b/mailbox/jcr/src/main/java/org/apache/james/mailbox/jcr/JCRMessageManager.java index dcfaed4..59448ca 100644 --- a/mailbox/jcr/src/main/java/org/apache/james/mailbox/jcr/JCRMessageManager.java +++ b/mailbox/jcr/src/main/java/org/apache/james/mailbox/jcr/JCRMessageManager.java @@ -36,8 +36,8 @@ import org.apache.james.mailbox.quota.QuotaRootResolver; import org.apache.james.mailbox.store.MailboxSessionMapperFactory; import org.apache.james.mailbox.store.StoreMessageManager; import org.apache.james.mailbox.store.event.MailboxEventDispatcher; -import org.apache.james.mailbox.store.mail.model.Attachment; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.impl.MessageParser; import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; import org.apache.james.mailbox.store.search.MessageSearchIndex; @@ -59,7 +59,7 @@ public class JCRMessageManager extends StoreMessageManager { @Override - protected MailboxMessage createMessage(Date internalDate, int size, int bodyStartOctet, SharedInputStream content, Flags flags, PropertyBuilder propertyBuilder, List<Attachment> attachments) throws MailboxException{ + protected MailboxMessage createMessage(Date internalDate, int size, int bodyStartOctet, SharedInputStream content, Flags flags, PropertyBuilder propertyBuilder, List<MessageAttachment> attachments) throws MailboxException{ JCRId mailboxId = (JCRId) getMailboxEntity().getMailboxId(); return new JCRMailboxMessage(mailboxId, internalDate, size, flags, content, bodyStartOctet, propertyBuilder, log); http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/model/JCRMailboxMessage.java ---------------------------------------------------------------------- diff --git a/mailbox/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/model/JCRMailboxMessage.java b/mailbox/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/model/JCRMailboxMessage.java index 62d17dd..eecb9e0 100644 --- a/mailbox/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/model/JCRMailboxMessage.java +++ b/mailbox/jcr/src/main/java/org/apache/james/mailbox/jcr/mail/model/JCRMailboxMessage.java @@ -42,10 +42,10 @@ import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.jcr.JCRId; import org.apache.james.mailbox.jcr.JCRImapConstants; import org.apache.james.mailbox.jcr.Persistent; -import org.apache.james.mailbox.store.mail.model.AttachmentId; import org.apache.james.mailbox.store.mail.model.DefaultMessageId; import org.apache.james.mailbox.store.mail.model.FlagsBuilder; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.MessageId; import org.apache.james.mailbox.store.mail.model.Property; import org.apache.james.mailbox.store.mail.model.impl.MessageUidComparator; @@ -680,7 +680,7 @@ public class JCRMailboxMessage implements MailboxMessage, JCRImapConstants, Pers } @Override - public List<AttachmentId> getAttachmentsIds() { - throw new NotImplementedException("Attachments Ids not implemented"); + public List<MessageAttachment> getAttachments() { + throw new NotImplementedException("Attachments are not implemented"); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMessageManager.java ---------------------------------------------------------------------- diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMessageManager.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMessageManager.java index ce36f27..6dcb8c1 100644 --- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMessageManager.java +++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/JPAMessageManager.java @@ -36,9 +36,9 @@ import org.apache.james.mailbox.quota.QuotaRootResolver; import org.apache.james.mailbox.store.MailboxSessionMapperFactory; import org.apache.james.mailbox.store.StoreMessageManager; import org.apache.james.mailbox.store.event.MailboxEventDispatcher; -import org.apache.james.mailbox.store.mail.model.Attachment; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.impl.MessageParser; import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; import org.apache.james.mailbox.store.search.MessageSearchIndex; @@ -60,7 +60,7 @@ public class JPAMessageManager extends StoreMessageManager { @Override protected MailboxMessage createMessage(Date internalDate, int size, int bodyStartOctet, SharedInputStream content, - final Flags flags, PropertyBuilder propertyBuilder, List<Attachment> attachments) throws MailboxException{ + final Flags flags, PropertyBuilder propertyBuilder, List<MessageAttachment> attachments) throws MailboxException{ return new JPAMailboxMessage((JPAMailbox) getMailboxEntity(), internalDate, size, flags, content, bodyStartOctet, propertyBuilder); } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java ---------------------------------------------------------------------- diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java index 3488127..c1aa3fa 100644 --- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java +++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/model/openjpa/AbstractJPAMailboxMessage.java @@ -46,11 +46,11 @@ import org.apache.james.mailbox.jpa.JPAId; import org.apache.james.mailbox.jpa.mail.model.JPAMailbox; import org.apache.james.mailbox.jpa.mail.model.JPAProperty; import org.apache.james.mailbox.jpa.mail.model.JPAUserFlag; -import org.apache.james.mailbox.store.mail.model.AttachmentId; import org.apache.james.mailbox.store.mail.model.DefaultMessageId; import org.apache.james.mailbox.store.mail.model.DelegatingMailboxMessage; import org.apache.james.mailbox.store.mail.model.FlagsBuilder; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.MessageId; import org.apache.james.mailbox.store.mail.model.Property; import org.apache.james.mailbox.store.mail.model.impl.MessageUidComparator; @@ -577,8 +577,8 @@ public abstract class AbstractJPAMailboxMessage implements MailboxMessage { @Override - public List<AttachmentId> getAttachmentsIds() { - throw new NotImplementedException("Attachments Ids not implemented"); + public List<MessageAttachment> getAttachments() { + throw new NotImplementedException("Attachments are not implemented"); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/openjpa/OpenJPAMessageManager.java ---------------------------------------------------------------------- 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 332ded6..3ae70a3 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 @@ -37,9 +37,9 @@ import org.apache.james.mailbox.quota.QuotaManager; import org.apache.james.mailbox.quota.QuotaRootResolver; import org.apache.james.mailbox.store.MailboxSessionMapperFactory; import org.apache.james.mailbox.store.event.MailboxEventDispatcher; -import org.apache.james.mailbox.store.mail.model.Attachment; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.impl.MessageParser; import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; import org.apache.james.mailbox.store.search.MessageSearchIndex; @@ -76,7 +76,7 @@ public class OpenJPAMessageManager extends JPAMessageManager { } @Override - protected MailboxMessage createMessage(Date internalDate, int size, int bodyStartOctet, SharedInputStream content, Flags flags, PropertyBuilder propertyBuilder, List<Attachment> attachments) throws MailboxException { + protected MailboxMessage createMessage(Date internalDate, int size, int bodyStartOctet, SharedInputStream content, Flags flags, PropertyBuilder propertyBuilder, List<MessageAttachment> attachments) throws MailboxException { int headerEnd = bodyStartOctet -2; if (headerEnd < 0) { headerEnd = 0; http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMessage.java ---------------------------------------------------------------------- diff --git a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMessage.java b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMessage.java index be2ecaa..c537f96 100644 --- a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMessage.java +++ b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/model/MaildirMessage.java @@ -18,11 +18,21 @@ ****************************************************************/ package org.apache.james.mailbox.maildir.mail.model; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; +import java.util.Date; +import java.util.List; + +import javax.mail.util.SharedFileInputStream; + import org.apache.commons.io.IOUtils; import org.apache.commons.lang.NotImplementedException; import org.apache.james.mailbox.maildir.MaildirMessageName; -import org.apache.james.mailbox.store.mail.model.AttachmentId; import org.apache.james.mailbox.store.mail.model.Message; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.MessageId; import org.apache.james.mailbox.store.mail.model.Property; import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; @@ -36,15 +46,6 @@ import org.apache.james.mime4j.stream.MimeConfig; import org.apache.james.mime4j.stream.MimeTokenStream; import org.apache.james.mime4j.stream.RecursionMode; -import javax.mail.util.SharedFileInputStream; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; -import java.util.Date; -import java.util.List; - public class MaildirMessage implements Message { private final MaildirMessageName messageName; @@ -277,8 +278,8 @@ public class MaildirMessage implements Message { } @Override - public List<AttachmentId> getAttachmentsIds() { - throw new NotImplementedException("Attachments Ids not implemented"); + public List<MessageAttachment> getAttachments() { + throw new NotImplementedException("Attachments are not implemented"); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/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 a790456..188318e 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 @@ -19,6 +19,7 @@ package org.apache.james.mailbox.inmemory.mail; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -29,6 +30,8 @@ import org.apache.james.mailbox.store.mail.model.Attachment; import org.apache.james.mailbox.store.mail.model.AttachmentId; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; public class InMemoryAttachmentMapper implements AttachmentMapper { @@ -49,6 +52,18 @@ public class InMemoryAttachmentMapper implements AttachmentMapper { } @Override + public List<Attachment> getAttachments(List<AttachmentId> attachmentIds) { + Preconditions.checkArgument(attachmentIds != null); + Builder<Attachment> builder = ImmutableList.<Attachment> builder(); + for (AttachmentId attachmentId : attachmentIds) { + if (attachmentsById.containsKey(attachmentId)) { + builder.add(attachmentsById.get(attachmentId)); + } + } + return builder.build(); + } + + @Override public void storeAttachment(Attachment attachment) throws MailboxException { attachmentsById.put(attachment.getAttachmentId(), attachment); } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java ---------------------------------------------------------------------- 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 e5295f7..7e57f85 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 @@ -65,9 +65,9 @@ import org.apache.james.mailbox.store.mail.AttachmentMapper; import org.apache.james.mailbox.store.mail.MessageMapper; import org.apache.james.mailbox.store.mail.MessageMapper.FetchType; import org.apache.james.mailbox.store.mail.model.Attachment; -import org.apache.james.mailbox.store.mail.model.AttachmentId; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.impl.MessageParser; import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage; @@ -383,7 +383,7 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana contentIn = new SharedFileInputStream(file); final int size = (int) file.length(); - final List<Attachment> attachments = extractAttachments(contentIn); + final List<MessageAttachment> attachments = extractAttachments(contentIn); final MailboxMessage message = createMessage(internalDate, size, bodyStartOctet, contentIn, flags, propertyBuilder, attachments); new QuotaChecker(quotaManager, quotaRootResolver, mailbox).tryAddition(1, size); @@ -423,7 +423,7 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana } - private List<Attachment> extractAttachments(SharedFileInputStream contentIn) { + private List<MessageAttachment> extractAttachments(SharedFileInputStream contentIn) { try { return messageParser.retrieveAttachments(contentIn); } catch (Exception e) { @@ -444,12 +444,8 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana * @return membership * @throws MailboxException */ - protected MailboxMessage createMessage(Date internalDate, int size, int bodyStartOctet, SharedInputStream content, Flags flags, PropertyBuilder propertyBuilder, List<Attachment> attachments) throws MailboxException { - ImmutableList.Builder<AttachmentId> attachmentsIds = ImmutableList.builder(); - for (Attachment attachment: attachments) { - attachmentsIds.add(attachment.getAttachmentId()); - } - return new SimpleMailboxMessage(internalDate, size, bodyStartOctet, content, flags, propertyBuilder, getMailboxEntity().getMailboxId(), attachmentsIds.build()); + protected MailboxMessage createMessage(Date internalDate, int size, int bodyStartOctet, SharedInputStream content, Flags flags, PropertyBuilder propertyBuilder, List<MessageAttachment> attachments) throws MailboxException { + return new SimpleMailboxMessage(internalDate, size, bodyStartOctet, content, flags, propertyBuilder, getMailboxEntity().getMailboxId(), attachments); } /** @@ -635,13 +631,17 @@ public class StoreMessageManager implements org.apache.james.mailbox.MessageMana }, true); } - protected MessageMetaData appendMessageToStore(final MailboxMessage message, final List<Attachment> attachments, MailboxSession session) throws MailboxException { + protected MessageMetaData appendMessageToStore(final MailboxMessage message, final List<MessageAttachment> messageAttachments, MailboxSession session) throws MailboxException { final MessageMapper messageMapper = mapperFactory.getMessageMapper(session); final AttachmentMapper attachmentMapper = mapperFactory.getAttachmentMapper(session); return mapperFactory.getMessageMapper(session).execute(new Mapper.Transaction<MessageMetaData>() { public MessageMetaData run() throws MailboxException { - attachmentMapper.storeAttachments(attachments); + ImmutableList.Builder<Attachment> attachments = ImmutableList.builder(); + for (MessageAttachment attachment : messageAttachments) { + attachments.add(attachment.getAttachment()); + } + attachmentMapper.storeAttachments(attachments.build()); return messageMapper.add(getMailboxEntity(), message); } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/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 e7386da..946a460 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 @@ -19,6 +19,7 @@ package org.apache.james.mailbox.store.mail; import java.util.Collection; +import java.util.List; import org.apache.james.mailbox.exception.AttachmentNotFoundException; import org.apache.james.mailbox.exception.MailboxException; @@ -30,6 +31,8 @@ public interface AttachmentMapper extends Mapper { Attachment getAttachment(AttachmentId attachmentId) throws AttachmentNotFoundException; + List<Attachment> getAttachments(List<AttachmentId> attachmentIds); + void storeAttachment(Attachment attachment) throws MailboxException; void storeAttachments(Collection<Attachment> attachments) throws MailboxException; http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/NoopAttachmentMapper.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/NoopAttachmentMapper.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/NoopAttachmentMapper.java index e783174..36000e8 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/NoopAttachmentMapper.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/NoopAttachmentMapper.java @@ -20,6 +20,7 @@ package org.apache.james.mailbox.store.mail; import java.util.Collection; +import java.util.List; import org.apache.james.mailbox.exception.AttachmentNotFoundException; import org.apache.james.mailbox.exception.MailboxException; @@ -44,6 +45,11 @@ public class NoopAttachmentMapper implements AttachmentMapper { } @Override + public List<Attachment> getAttachments(List<AttachmentId> attachmentIds) { + return null; + } + + @Override public void storeAttachment(Attachment attachment) throws MailboxException { } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java index c8bc67e..828ba56 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/DelegatingMailboxMessage.java @@ -117,7 +117,7 @@ public abstract class DelegatingMailboxMessage implements MailboxMessage { } @Override - public List<AttachmentId> getAttachmentsIds() { - return message.getAttachmentsIds(); + public List<MessageAttachment> getAttachments() { + return message.getAttachments(); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/Message.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/Message.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/Message.java index 4d3999b..dbe2a04 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/Message.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/Message.java @@ -105,10 +105,10 @@ public interface Message { List<Property> getProperties(); /** - * Return the list of ids of parsed attachments + * Return the list of attachments * - * @return a read only list of attachments ids + * @return a read only list of attachments */ - List<AttachmentId> getAttachmentsIds(); + List<MessageAttachment> getAttachments(); } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/MessageAttachment.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/MessageAttachment.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/MessageAttachment.java new file mode 100644 index 0000000..6004e92 --- /dev/null +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/MessageAttachment.java @@ -0,0 +1,123 @@ +/**************************************************************** + * 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.store.mail.model; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; + +public class MessageAttachment { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private Attachment attachment; + private Optional<String> cid; + private Boolean isInline; + + private Builder() { + cid = Optional.absent(); + } + + public Builder attachment(Attachment attachment) { + Preconditions.checkArgument(attachment != null); + this.attachment = attachment; + return this; + } + + public Builder cid(String cid) { + this.cid = Optional.fromNullable(cid); + return this; + } + + public Builder isInline(boolean isInline) { + this.isInline = isInline; + return this; + } + + public MessageAttachment build() { + Preconditions.checkState(attachment != null, "'attachment' is mandatory"); + if (isInline == null) { + isInline = false; + } + if (isInline && !cid.isPresent()) { + throw new IllegalStateException("'cid' is mandatory for inline attachments"); + } + return new MessageAttachment(attachment, cid, isInline); + } + } + + private final Attachment attachment; + private final Optional<String> cid; + private final boolean isInline; + + @VisibleForTesting MessageAttachment(Attachment attachment, Optional<String> cid, boolean isInline) { + this.attachment = attachment; + this.cid = cid; + this.isInline = isInline; + } + + public Attachment getAttachment() { + return attachment; + } + + public AttachmentId getAttachmentId() { + return attachment.getAttachmentId(); + } + + public Optional<String> getCid() { + return cid; + } + + public boolean isInline() { + return isInline; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MessageAttachment) { + MessageAttachment other = (MessageAttachment) obj; + return Objects.equal(attachment, other.attachment) + && Objects.equal(cid, other.cid) + && Objects.equal(isInline, other.isInline); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(attachment, cid, isInline); + } + + @Override + public String toString() { + return MoreObjects + .toStringHelper(this) + .add("attachment", attachment) + .add("cid", cid) + .add("isInline", isInline) + .toString(); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/MessageParser.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/MessageParser.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/MessageParser.java index 56099ff..dd99f29 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/MessageParser.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/MessageParser.java @@ -25,13 +25,16 @@ import java.io.InputStream; import java.util.List; import org.apache.james.mailbox.store.mail.model.Attachment; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mime4j.MimeException; import org.apache.james.mime4j.dom.Body; import org.apache.james.mime4j.dom.Entity; import org.apache.james.mime4j.dom.MessageWriter; import org.apache.james.mime4j.dom.Multipart; import org.apache.james.mime4j.dom.field.ContentDispositionField; +import org.apache.james.mime4j.dom.field.ContentIdField; import org.apache.james.mime4j.dom.field.ContentTypeField; +import org.apache.james.mime4j.dom.field.ParsedField; import org.apache.james.mime4j.message.DefaultMessageBuilder; import org.apache.james.mime4j.message.DefaultMessageWriter; import org.apache.james.mime4j.stream.Field; @@ -42,10 +45,16 @@ import com.google.common.collect.ImmutableList; public class MessageParser { + private static final String TEXT_MEDIA_TYPE = "text"; private static final String CONTENT_TYPE = "Content-Type"; + private static final String CONTENT_ID = "Content-ID"; + private static final String CONTENT_DISPOSITION = "Content-Disposition"; private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream"; + private static final List<String> ATTACHMENT_CONTENT_DISPOSITIONS = ImmutableList.of( + ContentDispositionField.DISPOSITION_TYPE_ATTACHMENT.toLowerCase(), + ContentDispositionField.DISPOSITION_TYPE_INLINE.toLowerCase()); - public List<Attachment> retrieveAttachments(InputStream fullContent) throws MimeException, IOException { + public List<MessageAttachment> retrieveAttachments(InputStream fullContent) throws MimeException, IOException { Body body = new DefaultMessageBuilder() .parseMessage(fullContent) .getBody(); @@ -60,25 +69,51 @@ public class MessageParser { } } - private List<Attachment> listAttachments(Multipart multipart) throws IOException { - ImmutableList.Builder<Attachment> attachments = ImmutableList.builder(); + private List<MessageAttachment> listAttachments(Multipart multipart) throws IOException { + ImmutableList.Builder<MessageAttachment> attachments = ImmutableList.builder(); MessageWriter messageWriter = new DefaultMessageWriter(); for (Entity entity : multipart.getBodyParts()) { - if (isAttachment(entity)) { - Optional<ContentTypeField> contentTypeField = contentTypeField(entity.getHeader().getField(CONTENT_TYPE)); - Optional<String> contentType = contentType(contentTypeField); - Optional<String> name = name(contentTypeField); - - attachments.add(Attachment.builder() - .bytes(getBytes(messageWriter, entity.getBody())) - .type(contentType.or(DEFAULT_CONTENT_TYPE)) - .name(name) - .build()); + if (entity.isMultipart() && entity.getBody() instanceof Multipart) { + attachments.addAll(listAttachments((Multipart) entity.getBody())); + } else { + if (isAttachment(entity)) { + attachments.add(retrieveAttachment(messageWriter, entity)); + } } } return attachments.build(); } + private MessageAttachment retrieveAttachment(MessageWriter messageWriter, Entity entity) throws IOException { + Optional<ContentTypeField> contentTypeField = getContentTypeField(entity); + Optional<String> contentType = contentType(contentTypeField); + Optional<String> name = name(contentTypeField); + Optional<String> cid = cid(castField(entity.getHeader().getField(CONTENT_ID), ContentIdField.class)); + boolean isInline = isInline(castField(entity.getHeader().getField(CONTENT_DISPOSITION), ContentDispositionField.class)); + + return MessageAttachment.builder() + .attachment(Attachment.builder() + .bytes(getBytes(messageWriter, entity.getBody())) + .type(contentType.or(DEFAULT_CONTENT_TYPE)) + .name(name) + .build()) + .cid(cid.orNull()) + .isInline(isInline) + .build(); + } + + private Optional<ContentTypeField> getContentTypeField(Entity entity) { + return castField(entity.getHeader().getField(CONTENT_TYPE), ContentTypeField.class); + } + + @SuppressWarnings("unchecked") + private <U extends ParsedField> Optional<U> castField(Field field, Class<U> clazz) { + if (field == null || !clazz.isInstance(field)) { + return Optional.absent(); + } + return Optional.of((U) field); + } + private Optional<String> contentType(Optional<ContentTypeField> contentTypeField) { return contentTypeField.transform(new Function<ContentTypeField, Optional<String>>() { @Override @@ -97,15 +132,47 @@ public class MessageParser { }).or(Optional.<String> absent()); } - private Optional<ContentTypeField> contentTypeField(Field contentType) { - if (contentType == null || !(contentType instanceof ContentTypeField)) { - return Optional.absent(); - } - return Optional.of((ContentTypeField) contentType); + private Optional<String> cid(Optional<ContentIdField> contentIdField) { + return contentIdField.transform(new Function<ContentIdField, Optional<String>>() { + @Override + public Optional<String> apply(ContentIdField field) { + return Optional.fromNullable(field.getId()); + } + }).or(Optional.<String> absent()); + } + + private boolean isInline(Optional<ContentDispositionField> contentDispositionField) { + return contentDispositionField.transform(new Function<ContentDispositionField, Boolean>() { + @Override + public Boolean apply(ContentDispositionField field) { + return field.isInline(); + } + }).or(false); } private boolean isAttachment(Entity part) { - return ContentDispositionField.DISPOSITION_TYPE_ATTACHMENT.equalsIgnoreCase(part.getDispositionType()); + if (isTextPart(part)) { + return false; + } + return Optional.fromNullable(part.getDispositionType()) + .transform(new Function<String, Boolean>() { + + @Override + public Boolean apply(String dispositionType) { + return ATTACHMENT_CONTENT_DISPOSITIONS.contains(dispositionType.toLowerCase()); + } + }).isPresent(); + } + + private boolean isTextPart(Entity part) { + Optional<ContentTypeField> contentTypeField = getContentTypeField(part); + if (contentTypeField.isPresent()) { + String mediaType = contentTypeField.get().getMediaType(); + if (mediaType != null && mediaType.equals(TEXT_MEDIA_TYPE)) { + return true; + } + } + return false; } private byte[] getBytes(MessageWriter messageWriter, Body body) throws IOException { http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java index 0122cb1..f7c7c80 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMailboxMessage.java @@ -29,10 +29,10 @@ import javax.mail.util.SharedByteArrayInputStream; import org.apache.commons.io.IOUtils; import org.apache.james.mailbox.exception.MailboxException; -import org.apache.james.mailbox.store.mail.model.AttachmentId; import org.apache.james.mailbox.store.mail.model.DelegatingMailboxMessage; import org.apache.james.mailbox.store.mail.model.MailboxId; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; @@ -48,7 +48,7 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage { int bodyStartOctet = Ints.checkedCast(original.getFullContentOctets() - original.getBodyOctets()); PropertyBuilder pBuilder = new PropertyBuilder(original.getProperties()); pBuilder.setTextualLineCount(original.getTextualLineCount()); - return new SimpleMailboxMessage(internalDate, size, bodyStartOctet, content, flags, pBuilder, mailboxId, original.getAttachmentsIds()); + return new SimpleMailboxMessage(internalDate, size, bodyStartOctet, content, flags, pBuilder, mailboxId, original.getAttachments()); } private static SharedByteArrayInputStream copyFullContent(MailboxMessage original) throws MailboxException { @@ -72,14 +72,14 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage { public SimpleMailboxMessage(Date internalDate, long size, int bodyStartOctet, SharedInputStream content, Flags flags, - PropertyBuilder propertyBuilder, MailboxId mailboxId, List<AttachmentId> attachmentsIds) { + PropertyBuilder propertyBuilder, MailboxId mailboxId, List<MessageAttachment> attachments) { super(new SimpleMessage( content, size, internalDate, propertyBuilder.getSubType(), propertyBuilder.getMediaType(), bodyStartOctet, propertyBuilder.getTextualLineCount(), propertyBuilder.toProperties(), - attachmentsIds + attachments )); setFlags(flags); @@ -92,7 +92,7 @@ public class SimpleMailboxMessage extends DelegatingMailboxMessage { PropertyBuilder propertyBuilder, MailboxId mailboxId) { this(internalDate, size, bodyStartOctet, content, flags, - propertyBuilder, mailboxId, ImmutableList.<AttachmentId>of()); + propertyBuilder, mailboxId, ImmutableList.<MessageAttachment>of()); } @Override http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java index d77571e..19c98d2 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/SimpleMessage.java @@ -25,8 +25,8 @@ import java.util.List; import javax.mail.internet.SharedInputStream; -import org.apache.james.mailbox.store.mail.model.AttachmentId; import org.apache.james.mailbox.store.mail.model.Message; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.MessageId; import org.apache.james.mailbox.store.mail.model.Property; @@ -42,9 +42,9 @@ public class SimpleMessage implements Message { private final long size; private final Long textualLineCount; private final List<Property> properties; - private final List<AttachmentId> attachmentsIds; + private final List<MessageAttachment> attachments; - public SimpleMessage(SharedInputStream content, long size, Date internalDate, String subType, String mediaType, int bodyStartOctet, Long textualLineCount, List<Property> properties, List<AttachmentId> attachmentsIds) { + public SimpleMessage(SharedInputStream content, long size, Date internalDate, String subType, String mediaType, int bodyStartOctet, Long textualLineCount, List<Property> properties, List<MessageAttachment> attachments) { this.subType = subType; this.mediaType = mediaType; this.content = content; @@ -53,11 +53,11 @@ public class SimpleMessage implements Message { this.size = size; this.textualLineCount = textualLineCount; this.properties = properties; - this.attachmentsIds = attachmentsIds; + this.attachments = attachments; } public SimpleMessage(SharedInputStream content, long size, Date internalDate, String subType, String mediaType, int bodyStartOctet, Long textualLineCount, List<Property> properties) { - this(content, size, internalDate, subType, mediaType, bodyStartOctet, textualLineCount, properties, ImmutableList.<AttachmentId>of()); + this(content, size, internalDate, subType, mediaType, bodyStartOctet, textualLineCount, properties, ImmutableList.<MessageAttachment>of()); } @Override @@ -120,7 +120,7 @@ public class SimpleMessage implements Message { } @Override - public List<AttachmentId> getAttachmentsIds() { - return attachmentsIds; + public List<MessageAttachment> getAttachments() { + return attachments; } } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java index 5f14fda..9527afa 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java @@ -41,9 +41,9 @@ import org.apache.james.mailbox.store.mail.AttachmentMapper; import org.apache.james.mailbox.store.mail.MailboxMapper; import org.apache.james.mailbox.store.mail.MessageMapper; import org.apache.james.mailbox.store.mail.MessageMapper.FetchType; -import org.apache.james.mailbox.store.mail.model.AttachmentId; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -96,41 +96,41 @@ public abstract class AbstractMailboxManagerAttachmentTest { Iterator<MailboxMessage> messages = messageMapper.findInMailbox(inbox, MessageRange.all(), FetchType.Full, 1); assertThat(messages.hasNext()).isTrue(); - assertThat(messages.next().getAttachmentsIds()).isEmpty(); + assertThat(messages.next().getAttachments()).isEmpty(); } @Test public void appendMessageShouldStoreAttachmentWhenMailWithOneAttachment() throws Exception { - InputStream mailInputStream = ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeInlined.eml"); + InputStream mailInputStream = ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeTextInlined.eml"); inboxMessageManager.appendMessage(mailInputStream, SUN_SEP_9TH_2001, mailboxSession, true, new Flags(Flags.Flag.RECENT)); Iterator<MailboxMessage> messages = messageMapper.findInMailbox(inbox, MessageRange.all(), FetchType.Full, 1); assertThat(messages.hasNext()).isTrue(); - assertThat(messages.next().getAttachmentsIds()).hasSize(1); + assertThat(messages.next().getAttachments()).hasSize(1); } @Test public void appendMessageShouldStoreAttachmentNameWhenMailWithOneAttachment() throws Exception { - InputStream mailInputStream = ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeInlined.eml"); + InputStream mailInputStream = ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeTextInlined.eml"); inboxMessageManager.appendMessage(mailInputStream, SUN_SEP_9TH_2001, mailboxSession, true, new Flags(Flags.Flag.RECENT)); Optional<String> expectedName = Optional.of("exploits_of_a_mom.png"); Iterator<MailboxMessage> messages = messageMapper.findInMailbox(inbox, MessageRange.all(), FetchType.Full, 1); - List<AttachmentId> attachmentsIds = messages.next().getAttachmentsIds(); - assertThat(attachmentMapper.getAttachment(attachmentsIds.get(0)).getName()).isEqualTo(expectedName); + List<MessageAttachment> attachments = messages.next().getAttachments(); + assertThat(attachmentMapper.getAttachment(attachments.get(0).getAttachmentId()).getName()).isEqualTo(expectedName); } @Test public void appendMessageShouldStoreARetrievableAttachmentWhenMailWithOneAttachment() throws Exception { - InputStream mailInputStream = ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeInlined.eml"); + InputStream mailInputStream = ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeTextInlined.eml"); inboxMessageManager.appendMessage(mailInputStream, SUN_SEP_9TH_2001, mailboxSession, true, new Flags(Flags.Flag.RECENT)); Iterator<MailboxMessage> messages = messageMapper.findInMailbox(inbox, MessageRange.all(), FetchType.Full, 1); assertThat(messages.hasNext()).isTrue(); - List<AttachmentId> attachmentsIds = messages.next().getAttachmentsIds(); - assertThat(attachmentsIds).hasSize(1); - assertThat(attachmentMapper.getAttachment(attachmentsIds.get(0)).getStream()) + List<MessageAttachment> attachments = messages.next().getAttachments(); + assertThat(attachments).hasSize(1); + assertThat(attachmentMapper.getAttachment(attachments.get(0).getAttachmentId()).getStream()) .hasContentEqualTo(ClassLoader.getSystemResourceAsStream("eml/gimp.png")); } @@ -141,7 +141,7 @@ public abstract class AbstractMailboxManagerAttachmentTest { Iterator<MailboxMessage> messages = messageMapper.findInMailbox(inbox, MessageRange.all(), FetchType.Full, 1); assertThat(messages.hasNext()).isTrue(); - assertThat(messages.next().getAttachmentsIds()).hasSize(2); + assertThat(messages.next().getAttachments()).hasSize(2); } @Test @@ -151,11 +151,11 @@ public abstract class AbstractMailboxManagerAttachmentTest { Iterator<MailboxMessage> messages = messageMapper.findInMailbox(inbox, MessageRange.all(), FetchType.Full, 1); assertThat(messages.hasNext()).isTrue(); - List<AttachmentId> attachmentsIds = messages.next().getAttachmentsIds(); - assertThat(attachmentsIds).hasSize(2); - assertThat(attachmentMapper.getAttachment(attachmentsIds.get(0)).getStream()) + List<MessageAttachment> attachments = messages.next().getAttachments(); + assertThat(attachments).hasSize(2); + assertThat(attachmentMapper.getAttachment(attachments.get(0).getAttachmentId()).getStream()) .hasContentEqualTo(ClassLoader.getSystemResourceAsStream("eml/4037_014.jpg")); - assertThat(attachmentMapper.getAttachment(attachmentsIds.get(1)).getStream()) + assertThat(attachmentMapper.getAttachment(attachments.get(1).getAttachmentId()).getStream()) .hasContentEqualTo(ClassLoader.getSystemResourceAsStream("eml/4037_015.jpg")); } @@ -166,7 +166,7 @@ public abstract class AbstractMailboxManagerAttachmentTest { Iterator<MailboxMessage> messages = messageMapper.findInMailbox(inbox, MessageRange.all(), FetchType.Full, 1); assertThat(messages.hasNext()).isTrue(); - assertThat(messages.next().getAttachmentsIds()).hasSize(1); + assertThat(messages.next().getAttachments()).hasSize(1); } @Test @@ -178,14 +178,14 @@ public abstract class AbstractMailboxManagerAttachmentTest { Iterator<MailboxMessage> messages = messageMapper.findInMailbox(inbox, MessageRange.all(), FetchType.Full, 1); assertThat(messages.hasNext()).isTrue(); - List<AttachmentId> attachmentsIds = messages.next().getAttachmentsIds(); - assertThat(attachmentsIds).hasSize(0); + List<MessageAttachment> attachments = messages.next().getAttachments(); + assertThat(attachments).hasSize(0); } @Test public void appendMessageShouldStoreOnceWhenDuplicateAttachment() throws Exception { - InputStream mailInputStream = ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeInlined.eml"); - InputStream mailInputStream2 = ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeInlined.eml"); + InputStream mailInputStream = ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeTextInlined.eml"); + InputStream mailInputStream2 = ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeTextInlined.eml"); String user2 = "us...@domain.tld"; MailboxSession user2MailboxSession = new MockMailboxSession(user2); MessageMapper user2MessageMapper = getMailboxSessionMapperFactory().getMessageMapper(user2MailboxSession); @@ -201,11 +201,11 @@ public abstract class AbstractMailboxManagerAttachmentTest { Iterator<MailboxMessage> messages = messageMapper.findInMailbox(inbox, MessageRange.all(), FetchType.Full, 1); Iterator<MailboxMessage> user2Messages = user2MessageMapper.findInMailbox(user2Inbox, MessageRange.all(), FetchType.Full, 1); assertThat(messages.hasNext()).isTrue(); - List<AttachmentId> attachmentsIds = messages.next().getAttachmentsIds(); - assertThat(attachmentsIds).hasSize(1); + List<MessageAttachment> attachments = messages.next().getAttachments(); + assertThat(attachments).hasSize(1); assertThat(user2Messages.hasNext()).isTrue(); - List<AttachmentId> user2AttachmentsIds = user2Messages.next().getAttachmentsIds(); - assertThat(attachmentsIds.equals(user2AttachmentsIds)).isTrue(); + List<MessageAttachment> user2Attachments = user2Messages.next().getAttachments(); + assertThat(attachments.equals(user2Attachments)).isTrue(); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/test/java/org/apache/james/mailbox/store/SimpleMailboxMembership.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/SimpleMailboxMembership.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/SimpleMailboxMembership.java index 4d1eb4f..28fad25 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/SimpleMailboxMembership.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/SimpleMailboxMembership.java @@ -36,9 +36,9 @@ import java.util.Map.Entry; import javax.mail.Flags; import org.apache.commons.lang.NotImplementedException; -import org.apache.james.mailbox.store.mail.model.AttachmentId; import org.apache.james.mailbox.store.mail.model.DefaultMessageId; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.MessageAttachment; import org.apache.james.mailbox.store.mail.model.Property; public class SimpleMailboxMembership implements MailboxMessage { @@ -274,7 +274,7 @@ public class SimpleMailboxMembership implements MailboxMessage { } @Override - public List<AttachmentId> getAttachmentsIds() { + public List<MessageAttachment> getAttachments() { throw new NotImplementedException("Attachments Ids not implemented"); } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/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 39b26e6..830cbf5 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,6 +21,8 @@ package org.apache.james.mailbox.store.mail.model; import static org.assertj.core.api.Assertions.assertThat; +import java.util.List; + import org.apache.james.mailbox.exception.AttachmentNotFoundException; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.store.mail.AttachmentMapper; @@ -102,4 +104,40 @@ public class AttachmentMapperTest<T extends MapperProvider> { assertThat(attachment1).isEqualTo(expected1); assertThat(attachment2).isEqualTo(expected2); } + + @ContractTest + public void getAttachmentsShouldThrowWhenNullAttachmentId() throws Exception { + expected.expect(IllegalArgumentException.class); + attachmentMapper.getAttachments(null); + } + + @ContractTest + public void getAttachmentsShouldReturnEmptyListWhenNonReferencedAttachmentId() throws Exception { + List<Attachment> attachments = attachmentMapper.getAttachments(ImmutableList.of(AttachmentId.forPayload("unknown".getBytes(Charsets.UTF_8)))); + + assertThat(attachments).isEmpty(); + } + + @ContractTest + public void getAttachmentsShouldReturnTheAttachmentsWhenSome() throws Exception { + //Given + Attachment expected = Attachment.builder() + .bytes("payload".getBytes(Charsets.UTF_8)) + .type("content") + .build(); + AttachmentId attachmentId = expected.getAttachmentId(); + attachmentMapper.storeAttachment(expected); + + Attachment expected2 = Attachment.builder() + .bytes("payload2".getBytes(Charsets.UTF_8)) + .type("content") + .build(); + AttachmentId attachmentId2 = expected2.getAttachmentId(); + attachmentMapper.storeAttachment(expected2); + + //When + List<Attachment> attachments = attachmentMapper.getAttachments(ImmutableList.of(attachmentId, attachmentId2)); + //Then + assertThat(attachments).contains(expected, expected2); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/896bc961/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageAssert.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageAssert.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageAssert.java index ab7a8bb..b002da4 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageAssert.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageAssert.java @@ -75,8 +75,8 @@ public class MessageAssert extends AbstractAssert<MessageAssert, MailboxMessage> } } if (usedFetchType == MessageMapper.FetchType.Full || usedFetchType == MessageMapper.FetchType.Body) { - if (!Objects.equal(actual.getAttachmentsIds(), expected.getAttachmentsIds())) { - failWithMessage("Expected attachments ids to be <%s> but was <%s>", expected.getAttachmentsIds(), actual.getAttachmentsIds()); + if (!Objects.equal(actual.getAttachments(), expected.getAttachments())) { + failWithMessage("Expected attachments to be <%s> but was <%s>", expected.getAttachments(), actual.getAttachments()); } } return this; --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org