MAILBOX-268 Add mandatory attributes to Attachment
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/dd4f7caa Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/dd4f7caa Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/dd4f7caa Branch: refs/heads/master Commit: dd4f7caaf13cf3e14a24357783414a8a75e2a954 Parents: 7b259d9 Author: Antoine Duprat <adup...@linagora.com> Authored: Wed May 25 10:09:18 2016 +0200 Committer: Antoine Duprat <antdup...@gmail.com> Committed: Fri May 27 10:02:02 2016 +0200 ---------------------------------------------------------------------- .../mailbox/store/mail/model/Attachment.java | 109 ++++++++++++++++++- .../mailbox/store/mail/model/AttachmentId.java | 53 ++++++++- .../store/mail/model/impl/MessageParser.java | 22 +++- .../store/mail/model/AttachmentIdTest.java | 56 ++++++++++ .../store/mail/model/AttachmentTest.java | 74 ++++++++++++- .../mail/model/impl/MessageParserTest.java | 28 ++++- .../eml/oneAttachmentWithSimpleContentType.eml | 38 +++++++ 7 files changed, 370 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/dd4f7caa/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/Attachment.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/Attachment.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/Attachment.java index f422f12..5af2b28 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/Attachment.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/Attachment.java @@ -22,16 +22,123 @@ package org.apache.james.mailbox.store.mail.model; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; public class Attachment { + public static Builder builder() { + return new Builder(); + } + + public static Attachment from(byte[] bytes, String type) { + return builder() + .attachmentId(AttachmentId.forPayload(bytes)) + .bytes(bytes) + .type(type) + .size(bytes.length) + .build(); + } + + public static class Builder { + + private AttachmentId attachmentId; + private byte[] bytes; + private String type; + private Long size; + + private Builder() { + } + + public Builder attachmentId(AttachmentId attachmentId) { + Preconditions.checkArgument(attachmentId != null); + this.attachmentId = attachmentId; + return this; + } + + public Builder bytes(byte[] bytes) { + Preconditions.checkArgument(bytes != null); + this.bytes = bytes; + return this; + } + + public Builder type(String type) { + Preconditions.checkArgument(!Strings.isNullOrEmpty(type)); + this.type = type; + return this; + } + + public Builder size(long size) { + this.size = size; + return this; + } + + public Attachment build() { + Preconditions.checkState(attachmentId != null, "'attachmentId' is mandatory"); + Preconditions.checkState(bytes != null, "'bytes' is mandatory"); + Preconditions.checkState(type != null, "'type' is mandatory"); + Preconditions.checkState(size != null, "'size' is mandatory"); + return new Attachment(bytes, attachmentId, type, size); + } + } + private final byte[] bytes; + private final AttachmentId attachmentId; + private final String type; + private final long size; - public Attachment(byte[] bytes) { + private Attachment(byte[] bytes, AttachmentId attachmentId, String type, long size) { this.bytes = bytes; + this.attachmentId = attachmentId; + this.type = type; + this.size = size; + } + + public AttachmentId getAttachmentId() { + return attachmentId; + } + + public String getType() { + return type; + } + + public long getSize() { + return size; } public InputStream getStream() throws IOException { return new ByteArrayInputStream(bytes); } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Attachment) { + Attachment other = (Attachment) obj; + return Objects.equal(attachmentId, other.attachmentId) + && Arrays.equals(bytes, other.bytes) + && Objects.equal(type, other.type) + && Objects.equal(size, other.size); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(attachmentId, bytes, type, size); + } + + @Override + public String toString() { + return MoreObjects + .toStringHelper(this) + .add("attachmentId", attachmentId) + .add("bytes", bytes) + .add("type", type) + .add("size", size) + .toString(); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/dd4f7caa/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/AttachmentId.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/AttachmentId.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/AttachmentId.java index dc87bf1..344c84e 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/AttachmentId.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/AttachmentId.java @@ -18,6 +18,55 @@ ****************************************************************/ package org.apache.james.mailbox.store.mail.model; -public interface AttachmentId { - String serialize(); + +import org.apache.commons.codec.digest.DigestUtils; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; + +public class AttachmentId { + + public static AttachmentId forPayload(byte[] payload) { + Preconditions.checkArgument(payload != null); + return new AttachmentId(DigestUtils.sha1Hex(payload)); + } + + public static AttachmentId from(String id) { + Preconditions.checkArgument(!Strings.isNullOrEmpty(id)); + return new AttachmentId(id); + } + + private final String id; + + private AttachmentId(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof AttachmentId) { + AttachmentId other = (AttachmentId) obj; + return Objects.equal(id, other.id); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(id); + } + + @Override + public String toString() { + return MoreObjects + .toStringHelper(this) + .add("id", id) + .toString(); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/dd4f7caa/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 83987b3..bba6a13 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 @@ -33,11 +33,17 @@ import org.apache.james.mime4j.dom.Multipart; import org.apache.james.mime4j.dom.field.ContentDispositionField; import org.apache.james.mime4j.message.DefaultMessageBuilder; import org.apache.james.mime4j.message.DefaultMessageWriter; +import org.apache.james.mime4j.stream.Field; +import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; public class MessageParser { + private static final String CONTENT_TYPE = "Content-Type"; + private static final String HEADER_SEPARATOR = ";"; + public List<Attachment> retrieveAttachments(InputStream fullContent) throws MimeException, IOException { Body body = new DefaultMessageBuilder() .parseMessage(fullContent) @@ -58,19 +64,29 @@ public class MessageParser { MessageWriter messageWriter = new DefaultMessageWriter(); for (Entity entity : multipart.getBodyParts()) { if (isAttachment(entity)) { - attachments.add(createAttachment(messageWriter, entity.getBody())); + attachments.add(createAttachment(messageWriter, entity.getBody(), + contentType(entity.getHeader().getField(CONTENT_TYPE)))); } } return attachments.build(); } + private String contentType(Field contentType) { + String body = contentType.getBody(); + if (body.contains(HEADER_SEPARATOR)) { + return Iterables.get(Splitter.on(HEADER_SEPARATOR).split(body), 0); + } + return body; + } + private boolean isAttachment(Entity part) { return ContentDispositionField.DISPOSITION_TYPE_ATTACHMENT.equalsIgnoreCase(part.getDispositionType()); } - private Attachment createAttachment(MessageWriter messageWriter, Body body) throws IOException { + private Attachment createAttachment(MessageWriter messageWriter, Body body, String contentType) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); messageWriter.writeBody(body, out); - return new Attachment(out.toByteArray()); + byte[] bytes = out.toByteArray(); + return Attachment.from(bytes, contentType); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/dd4f7caa/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentIdTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentIdTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentIdTest.java new file mode 100644 index 0000000..b95dc84 --- /dev/null +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentIdTest.java @@ -0,0 +1,56 @@ +/**************************************************************** + * 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 static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class AttachmentIdTest { + + @Test + public void forPayloadShouldCalculateTheUnderlyingSha1() { + AttachmentId attachmentId = AttachmentId.forPayload("payload".getBytes()); + String expectedId = "f07e5a815613c5abeddc4b682247a4c42d8a95df"; + assertThat(attachmentId.getId()).isEqualTo(expectedId); + } + + @Test(expected = IllegalArgumentException.class) + public void forPayloadShouldThrowWhenPayloadIsNull() { + AttachmentId.forPayload(null); + } + + @Test(expected = IllegalArgumentException.class) + public void fromShouldThrowWhenIdIsNull() { + AttachmentId.from(null); + } + + @Test(expected = IllegalArgumentException.class) + public void fromShouldThrowWhenIdIsEmpty() { + AttachmentId.from(""); + } + + @Test + public void fromShouldWork() { + String expectedId = "f07e5a815613c5abeddc4b682247a4c42d8a95df"; + AttachmentId attachmentId = AttachmentId.from(expectedId); + assertThat(attachmentId.getId()).isEqualTo(expectedId); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/dd4f7caa/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentTest.java index 9c91c93..5e96c7d 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentTest.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/AttachmentTest.java @@ -32,7 +32,7 @@ public class AttachmentTest { @Test public void streamShouldBeConsumedOneTime() throws Exception { String input = "mystream"; - Attachment attachment = new Attachment(input.getBytes()); + Attachment attachment = Attachment.from(input.getBytes(), "content"); InputStream stream = attachment.getStream(); assertThat(stream).isNotNull(); @@ -42,11 +42,81 @@ public class AttachmentTest { @Test public void streamShouldBeConsumedMoreThanOneTime() throws Exception { String input = "mystream"; - Attachment attachment = new Attachment(input.getBytes()); + Attachment attachment = Attachment.from(input.getBytes(), "content"); attachment.getStream(); InputStream stream = attachment.getStream(); assertThat(stream).isNotNull(); assertThat(IOUtils.toString(stream)).isEqualTo(input); } + + @Test (expected = IllegalArgumentException.class) + public void builderShouldThrowWhenAttachmentIdIsNull() { + Attachment.builder() + .attachmentId(null); + } + + @Test (expected = IllegalArgumentException.class) + public void builderShouldThrowWhenBytesIsNull() { + Attachment.builder() + .bytes(null); + } + + @Test (expected = IllegalArgumentException.class) + public void builderShouldThrowWhenTypeIsNull() { + Attachment.builder() + .type(null); + } + + @Test (expected = IllegalArgumentException.class) + public void builderShouldThrowWhenTypeIsEmpty() { + Attachment.builder() + .type(""); + } + + @Test (expected = IllegalStateException.class) + public void buildShouldThrowWhenAttachmentIdIsNotProvided() { + Attachment.builder().build(); + } + + @Test (expected = IllegalStateException.class) + public void buildShouldThrowWhenBytesIsNotProvided() { + Attachment.builder() + .attachmentId(AttachmentId.forPayload("mystream".getBytes())) + .build(); + } + + @Test (expected = IllegalStateException.class) + public void buildShouldThrowWhenTypeIsNotProvided() { + Attachment.builder() + .attachmentId(AttachmentId.forPayload("mystream".getBytes())) + .bytes("mystream".getBytes()) + .build(); + } + + @Test (expected = IllegalStateException.class) + public void buildShouldThrowWhenSizeIsNotProvided() { + Attachment.builder() + .attachmentId(AttachmentId.forPayload("mystream".getBytes())) + .bytes("mystream".getBytes()) + .type("content") + .build(); + } + + @Test + public void fromShouldSetTheAttachmentId() throws Exception { + byte[] bytes = "mystream".getBytes(); + Attachment attachment = Attachment.from(bytes, "content"); + AttachmentId expected = AttachmentId.forPayload(bytes); + + assertThat(attachment.getAttachmentId()).isEqualTo(expected); + } + + @Test + public void fromShouldSetTheSize() throws Exception { + String input = "mystream"; + Attachment attachment = Attachment.from(input.getBytes(), "content"); + + assertThat(attachment.getSize()).isEqualTo(input.getBytes().length); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/dd4f7caa/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/MessageParserTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/MessageParserTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/MessageParserTest.java index 719ca77..de1137c 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/MessageParserTest.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/MessageParserTest.java @@ -37,20 +37,44 @@ public class MessageParserTest { } @Test - public void getAttachmentsShouldBeEmptyWhenNone() throws Exception { + public void getAttachmentsShouldBeEmptyWhenNoAttachment() throws Exception { List<Attachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/noAttachment.eml")); assertThat(attachments).isEmpty(); } @Test - public void getAttachmentsShouldRetrieveAttachmentsWhenOne() throws Exception { + public void getAttachmentsShouldRetrieveAttachmentsWhenOneAttachment() throws Exception { List<Attachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeInlined.eml")); assertThat(attachments).hasSize(1); } @Test + public void getAttachmentsShouldRetrieveTheAttachmentContentTypeWhenOneAttachment() throws Exception { + List<Attachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeInlined.eml")); + + assertThat(attachments).hasSize(1); + assertThat(attachments.get(0).getType()).isEqualTo("application/octet-stream"); + } + + @Test + public void getAttachmentsShouldRetrieveTheAttachmentContentTypeWhenOneAttachmentWithSimpleContentType() throws Exception { + List<Attachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentWithSimpleContentType.eml")); + + assertThat(attachments).hasSize(1); + assertThat(attachments.get(0).getType()).isEqualTo("application/octet-stream"); + } + + @Test + public void getAttachmentsShouldRetrieveTheAttachmentSizeWhenOneAttachment() throws Exception { + List<Attachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeInlined.eml")); + + assertThat(attachments).hasSize(1); + assertThat(attachments.get(0).getSize()).isEqualTo(3071); + } + + @Test public void getAttachmentsShouldReturnTheExpectedAttachment() throws Exception { List<Attachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentAndSomeInlined.eml")); http://git-wip-us.apache.org/repos/asf/james-project/blob/dd4f7caa/mailbox/store/src/test/resources/eml/oneAttachmentWithSimpleContentType.eml ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/resources/eml/oneAttachmentWithSimpleContentType.eml b/mailbox/store/src/test/resources/eml/oneAttachmentWithSimpleContentType.eml new file mode 100644 index 0000000..ca0abe7 --- /dev/null +++ b/mailbox/store/src/test/resources/eml/oneAttachmentWithSimpleContentType.eml @@ -0,0 +1,38 @@ +Mail content: +To: "=?utf-8?B?UmFuaSBBc3NhZg==?=" <rani.as...@jri.obm.lng.org> +Subject: =?utf-8?B?VHIuIDogUGhvdG9zICE=?= +Importance: Normal +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_Part_0_1330682067197" + +------=_Part_0_1330682067197 +Content-Type: multipart/alternative; + boundary="----=_Part_2_1330682067197" + +------=_Part_2_1330682067197 +Content-Type: text/plain; + charset= utf-8 +Content-Transfer-Encoding: 8bit +Content-Disposition: inline + +Content of part 1-1 +------=_Part_2_1330682067197 +Content-Type: text/html; + charset= utf-8 +Content-Transfer-Encoding: 8bit +Content-Disposition: inline + +<b>Content of part 1-2</b> +------=_Part_2_1330682067197-- + +------=_Part_0_1330682067197 +Content-Type: application/octet-stream +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="gimp.png" + +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 + +------=_Part_0_1330682067197-- + --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org