JAMES-2608 Store attributes as Json
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/3b223d53 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/3b223d53 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/3b223d53 Branch: refs/heads/master Commit: 3b223d537508d9a79aa50640cc23d87726508c29 Parents: 1ebe3fd Author: Antoine Duprat <[email protected]> Authored: Mon Dec 17 11:34:23 2018 +0100 Committer: Raphael Ouazana <[email protected]> Committed: Wed Dec 19 09:24:12 2018 +0100 ---------------------------------------------------------------------- .../CassandraMailRepositoryMailDaoV2.java | 47 ++---- .../CassandraMailRepositoryModule.java | 5 +- .../CassandraMailRepositoryMailDAOTest.java | 163 +++++++++++++------ 3 files changed, 126 insertions(+), 89 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/3b223d53/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java ---------------------------------------------------------------------- diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java index 156fa85..36e8e28 100644 --- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java +++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDaoV2.java @@ -44,13 +44,6 @@ import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.RE import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.SENDER; import static org.apache.james.mailrepository.cassandra.MailRepositoryTableV2.STATE; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.nio.ByteBuffer; import java.util.Collection; import java.util.Date; import java.util.List; @@ -69,7 +62,9 @@ import org.apache.james.core.MailAddress; import org.apache.james.mailrepository.api.MailKey; import org.apache.james.mailrepository.api.MailRepositoryUrl; import org.apache.james.server.core.MailImpl; -import org.apache.james.util.streams.Iterators; +import org.apache.mailet.Attribute; +import org.apache.mailet.AttributeName; +import org.apache.mailet.AttributeValue; import org.apache.mailet.Mail; import org.apache.mailet.PerRecipientHeaders; import org.apache.mailet.PerRecipientHeaders.Header; @@ -183,7 +178,7 @@ public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepository String errorMessage = row.getString(ERROR_MESSAGE); String name = row.getString(MAIL_KEY); Date lastUpdated = row.getTimestamp(LAST_UPDATED); - Map<String, ByteBuffer> rawAttributes = row.getMap(ATTRIBUTES, String.class, ByteBuffer.class); + Map<String, String> rawAttributes = row.getMap(ATTRIBUTES, String.class, String.class); PerRecipientHeaders perRecipientHeaders = fromList(row.getList(PER_RECIPIENT_SPECIFIC_HEADERS, TupleValue.class)); MailImpl.Builder mailBuilder = MailImpl.builder() @@ -203,21 +198,20 @@ public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepository blobIdFactory.from(row.getString(BODY_BLOB_ID))); } - private Map<String, Serializable> toAttributes(Map<String, ByteBuffer> rowAttributes) { + private List<Attribute> toAttributes(Map<String, String> rowAttributes) { return rowAttributes.entrySet() .stream() - .map(entry -> Pair.of(entry.getKey(), fromByteBuffer(entry.getValue()))) - .collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight)); + .map(Throwing.function(entry -> new Attribute(AttributeName.of(entry.getKey()), AttributeValue.fromJsonString(entry.getValue())))) + .collect(Guavate.toImmutableList()); } private ImmutableList<String> asStringList(Collection<MailAddress> mailAddresses) { return mailAddresses.stream().map(MailAddress::asString).collect(Guavate.toImmutableList()); } - private ImmutableMap<String, ByteBuffer> toRawAttributeMap(Mail mail) { - return Iterators.toStream(mail.getAttributeNames()) - .map(name -> Pair.of(name, mail.getAttribute(name))) - .map(pair -> Pair.of(pair.getLeft(), toByteBuffer(pair.getRight()))) + private ImmutableMap<String, String> toRawAttributeMap(Mail mail) { + return mail.attributes() + .map(attribute -> Pair.of(attribute.getName().asString(), toJson(attribute.getValue()))) .collect(Guavate.toImmutableMap(Pair::getLeft, Pair::getRight)); } @@ -242,25 +236,8 @@ public class CassandraMailRepositoryMailDaoV2 implements CassandraMailRepository return result; } - private ByteBuffer toByteBuffer(Serializable serializable) { - try { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - new ObjectOutputStream(outputStream).writeObject(serializable); - return ByteBuffer.wrap(outputStream.toByteArray()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private Serializable fromByteBuffer(ByteBuffer byteBuffer) { - try { - byte[] data = new byte[byteBuffer.remaining()]; - byteBuffer.get(data); - ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(data)); - return (Serializable) objectInputStream.readObject(); - } catch (IOException | ClassNotFoundException e) { - throw new RuntimeException(e); - } + private String toJson(AttributeValue<?> attributeValue) { + return attributeValue.toJson().toString(); } private MailAddress toMailAddress(String rawValue) { http://git-wip-us.apache.org/repos/asf/james-project/blob/3b223d53/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java ---------------------------------------------------------------------- diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java index f2c44f4..6e6c3cd 100644 --- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java +++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryModule.java @@ -71,7 +71,8 @@ public interface CassandraMailRepositoryModule { .table(MailRepositoryTableV2.CONTENT_TABLE_NAME) .comment("Stores the mails for a given repository. " + "Content is stored with other blobs. " + - "This v2 version was introduced to support multiple headers for each user") + "This v2 version was introduced to support multiple headers for each user. " + + "The attributes are store as Json introduced in Mailet API v3.2.") .statement(statement -> statement .addPartitionKey(MailRepositoryTable.REPOSITORY_NAME, text()) .addPartitionKey(MailRepositoryTable.MAIL_KEY, text()) @@ -79,7 +80,7 @@ public interface CassandraMailRepositoryModule { .addColumn(MailRepositoryTable.STATE, text()) .addColumn(MailRepositoryTable.HEADER_BLOB_ID, text()) .addColumn(MailRepositoryTable.BODY_BLOB_ID, text()) - .addColumn(MailRepositoryTable.ATTRIBUTES, map(text(), blob())) + .addColumn(MailRepositoryTable.ATTRIBUTES, map(text(), text())) .addColumn(MailRepositoryTable.ERROR_MESSAGE, text()) .addColumn(MailRepositoryTable.SENDER, text()) .addColumn(MailRepositoryTable.RECIPIENTS, list(text())) http://git-wip-us.apache.org/repos/asf/james-project/blob/3b223d53/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java ---------------------------------------------------------------------- diff --git a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java index a50c69e..a04b8ed 100644 --- a/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java +++ b/server/mailrepository/mailrepository-cassandra/src/test/java/org/apache/james/mailrepository/cassandra/CassandraMailRepositoryMailDAOTest.java @@ -22,6 +22,8 @@ package org.apache.james.mailrepository.cassandra; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.SoftAssertions.assertSoftly; +import java.util.Collection; +import java.util.List; import java.util.Optional; import javax.mail.MessagingException; @@ -32,6 +34,9 @@ import org.apache.james.blob.api.BlobId; import org.apache.james.blob.api.TestBlobId; import org.apache.james.mailrepository.api.MailKey; import org.apache.james.mailrepository.api.MailRepositoryUrl; +import org.apache.mailet.Attribute; +import org.apache.mailet.AttributeName; +import org.apache.mailet.AttributeValue; import org.apache.mailet.Mail; import org.apache.mailet.PerRecipientHeaders; import org.apache.mailet.base.MailAddressFixture; @@ -57,58 +62,6 @@ class CassandraMailRepositoryMailDAOTest { abstract CassandraMailRepositoryMailDaoAPI testee(); @Test - void readShouldReturnAllMailMetadata() throws Exception { - CassandraMailRepositoryMailDaoAPI testee = testee(); - - BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader"); - BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody"); - String errorMessage = "error message"; - String state = "state"; - String remoteAddr = "remoteAddr"; - String remoteHost = "remoteHost"; - PerRecipientHeaders.Header header = PerRecipientHeaders.Header.builder().name("headerName").value("headerValue").build(); - String attributeName = "att1"; - ImmutableList<String> attributeValue = ImmutableList.of("value1", "value2"); - - testee.store(URL, - FakeMail.builder() - .name(KEY_1.asString()) - .sender(MailAddressFixture.SENDER) - .recipients(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2) - .errorMessage(errorMessage) - .state(state) - .remoteAddr(remoteAddr) - .remoteHost(remoteHost) - .addHeaderForRecipient(header, MailAddressFixture.RECIPIENT1) - .attribute(attributeName, attributeValue) - .build(), - blobIdHeader, - blobIdBody) - .join(); - - CassandraMailRepositoryMailDAO.MailDTO mailDTO = testee.read(URL, KEY_1).join().get(); - - Mail partialMail = mailDTO.getMailBuilder().build(); - assertSoftly(softly -> { - softly.assertThat(mailDTO.getBodyBlobId()).isEqualTo(blobIdBody); - softly.assertThat(mailDTO.getHeaderBlobId()).isEqualTo(blobIdHeader); - softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString()); - softly.assertThat(partialMail.getErrorMessage()).isEqualTo(errorMessage); - softly.assertThat(partialMail.getState()).isEqualTo(state); - softly.assertThat(partialMail.getRemoteAddr()).isEqualTo(remoteAddr); - softly.assertThat(partialMail.getRemoteHost()).isEqualTo(remoteHost); - softly.assertThat(partialMail.getAttributeNames()).containsOnly(attributeName); - softly.assertThat(partialMail.getAttribute(attributeName)).isEqualTo(attributeValue); - softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getRecipientsWithSpecificHeaders()) - .containsOnly(MailAddressFixture.RECIPIENT1); - softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getHeadersForRecipient(MailAddressFixture.RECIPIENT1)) - .containsOnly(header); - softly.assertThat(partialMail.getMaybeSender().asOptional()).contains(MailAddressFixture.SENDER); - softly.assertThat(partialMail.getRecipients()).containsOnly(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2); - }); - } - - @Test void storeShouldAcceptMailWithOnlyName() throws Exception { CassandraMailRepositoryMailDaoAPI testee = testee(); BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader"); @@ -174,6 +127,58 @@ class CassandraMailRepositoryMailDAOTest { CassandraMailRepositoryMailDaoAPI testee() { return testee; } + + @Test + void readShouldReturnAllMailMetadata() throws Exception { + CassandraMailRepositoryMailDaoAPI testee = testee(); + + BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader"); + BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody"); + String errorMessage = "error message"; + String state = "state"; + String remoteAddr = "remoteAddr"; + String remoteHost = "remoteHost"; + PerRecipientHeaders.Header header = PerRecipientHeaders.Header.builder().name("headerName").value("headerValue").build(); + String attributeName = "att1"; + ImmutableList<String> attributeValue = ImmutableList.of("value1", "value2"); + + testee.store(URL, + FakeMail.builder() + .name(KEY_1.asString()) + .sender(MailAddressFixture.SENDER) + .recipients(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2) + .errorMessage(errorMessage) + .state(state) + .remoteAddr(remoteAddr) + .remoteHost(remoteHost) + .addHeaderForRecipient(header, MailAddressFixture.RECIPIENT1) + .attribute(attributeName, attributeValue) + .build(), + blobIdHeader, + blobIdBody) + .join(); + + CassandraMailRepositoryMailDAO.MailDTO mailDTO = testee.read(URL, KEY_1).join().get(); + + Mail partialMail = mailDTO.getMailBuilder().build(); + assertSoftly(softly -> { + softly.assertThat(mailDTO.getBodyBlobId()).isEqualTo(blobIdBody); + softly.assertThat(mailDTO.getHeaderBlobId()).isEqualTo(blobIdHeader); + softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString()); + softly.assertThat(partialMail.getErrorMessage()).isEqualTo(errorMessage); + softly.assertThat(partialMail.getState()).isEqualTo(state); + softly.assertThat(partialMail.getRemoteAddr()).isEqualTo(remoteAddr); + softly.assertThat(partialMail.getRemoteHost()).isEqualTo(remoteHost); + softly.assertThat(partialMail.getAttributeNames()).containsOnly(attributeName); + softly.assertThat(partialMail.getAttribute(attributeName)).isEqualTo(attributeValue); + softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getRecipientsWithSpecificHeaders()) + .containsOnly(MailAddressFixture.RECIPIENT1); + softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getHeadersForRecipient(MailAddressFixture.RECIPIENT1)) + .containsOnly(header); + softly.assertThat(partialMail.getMaybeSender().asOptional()).contains(MailAddressFixture.SENDER); + softly.assertThat(partialMail.getRecipients()).containsOnly(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2); + }); + } } @Nested @@ -190,6 +195,60 @@ class CassandraMailRepositoryMailDAOTest { CassandraMailRepositoryMailDaoAPI testee() { return testee; } + + @Test + void readShouldReturnAllMailMetadata() throws Exception { + CassandraMailRepositoryMailDaoAPI testee = testee(); + + BlobId blobIdBody = BLOB_ID_FACTORY.from("blobHeader"); + BlobId blobIdHeader = BLOB_ID_FACTORY.from("blobBody"); + String errorMessage = "error message"; + String state = "state"; + String remoteAddr = "remoteAddr"; + String remoteHost = "remoteHost"; + PerRecipientHeaders.Header header = PerRecipientHeaders.Header.builder().name("headerName").value("headerValue").build(); + String attributeName = "att1"; + List<AttributeValue<?>> attributeValue = ImmutableList.of(AttributeValue.of("value1"), AttributeValue.of("value2")); + Attribute attribute = new Attribute(AttributeName.of(attributeName), AttributeValue.of(attributeValue)); + List<Attribute> attributes = ImmutableList.of(attribute); + + testee.store(URL, + FakeMail.builder() + .name(KEY_1.asString()) + .sender(MailAddressFixture.SENDER) + .recipients(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2) + .errorMessage(errorMessage) + .state(state) + .remoteAddr(remoteAddr) + .remoteHost(remoteHost) + .addHeaderForRecipient(header, MailAddressFixture.RECIPIENT1) + .attributes(attributes) + .build(), + blobIdHeader, + blobIdBody) + .join(); + + CassandraMailRepositoryMailDAO.MailDTO mailDTO = testee.read(URL, KEY_1).join().get(); + + Mail partialMail = mailDTO.getMailBuilder().build(); + assertSoftly(softly -> { + softly.assertThat(mailDTO.getBodyBlobId()).isEqualTo(blobIdBody); + softly.assertThat(mailDTO.getHeaderBlobId()).isEqualTo(blobIdHeader); + softly.assertThat(partialMail.getName()).isEqualTo(KEY_1.asString()); + softly.assertThat(partialMail.getErrorMessage()).isEqualTo(errorMessage); + softly.assertThat(partialMail.getState()).isEqualTo(state); + softly.assertThat(partialMail.getRemoteAddr()).isEqualTo(remoteAddr); + softly.assertThat(partialMail.getRemoteHost()).isEqualTo(remoteHost); + softly.assertThat(partialMail.getAttributeNames()).containsOnly(attributeName); + softly.assertThat(partialMail.getAttribute(AttributeName.of(attributeName))).contains(attribute); + softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getRecipientsWithSpecificHeaders()) + .containsOnly(MailAddressFixture.RECIPIENT1); + softly.assertThat(partialMail.getPerRecipientSpecificHeaders().getHeadersForRecipient(MailAddressFixture.RECIPIENT1)) + .containsOnly(header); + softly.assertThat(partialMail.getMaybeSender().asOptional()).contains(MailAddressFixture.SENDER); + softly.assertThat(partialMail.getRecipients()).containsOnly(MailAddressFixture.RECIPIENT1, MailAddressFixture.RECIPIENT2); + }); + } } @Nested --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
