This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit f5644bd231ea1c83b2b1d2522951443803a775d3 Author: Benoit Tellier <btell...@linagora.com> AuthorDate: Thu Jul 4 15:16:45 2019 +0200 JAMES-2809 Implement a BlobStore based version of the DeletedMessageVault Not supported operations: - retention: will be implemented in JAMES-2811 - delete: will be implemented later - userWithVault: this not generic enough operation will be refactored out of the contract --- mailbox/plugin/deleted-messages-vault/pom.xml | 5 + .../vault/blob/BlobStoreDeletedMessageVault.java | 99 +++++++++++++++ .../james/vault/blob/BucketNameGenerator.java | 40 ++++++ .../blob/BlobStoreDeletedMessageVaultTest.java | 134 +++++++++++++++++++++ .../james/vault/blob/BucketNameGeneratorTest.java | 48 ++++++++ 5 files changed, 326 insertions(+) diff --git a/mailbox/plugin/deleted-messages-vault/pom.xml b/mailbox/plugin/deleted-messages-vault/pom.xml index f7bff9c..8d973c0 100644 --- a/mailbox/plugin/deleted-messages-vault/pom.xml +++ b/mailbox/plugin/deleted-messages-vault/pom.xml @@ -82,6 +82,11 @@ </dependency> <dependency> <groupId>${james.groupId}</groupId> + <artifactId>blob-memory</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${james.groupId}</groupId> <artifactId>james-server-core</artifactId> </dependency> <dependency> diff --git a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/blob/BlobStoreDeletedMessageVault.java b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/blob/BlobStoreDeletedMessageVault.java new file mode 100644 index 0000000..4f5aa16 --- /dev/null +++ b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/blob/BlobStoreDeletedMessageVault.java @@ -0,0 +1,99 @@ +/**************************************************************** + * 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.vault.blob; + +import java.io.InputStream; + +import org.apache.commons.lang3.NotImplementedException; +import org.apache.james.blob.api.BlobStore; +import org.apache.james.blob.api.BucketName; +import org.apache.james.core.User; +import org.apache.james.mailbox.model.MessageId; +import org.apache.james.task.Task; +import org.apache.james.vault.DeletedMessage; +import org.apache.james.vault.DeletedMessageVault; +import org.apache.james.vault.metadata.DeletedMessageMetadataVault; +import org.apache.james.vault.metadata.DeletedMessageWithStorageInformation; +import org.apache.james.vault.metadata.StorageInformation; +import org.apache.james.vault.search.Query; +import org.reactivestreams.Publisher; + +import com.google.common.base.Preconditions; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class BlobStoreDeletedMessageVault implements DeletedMessageVault { + private final DeletedMessageMetadataVault messageMetadataVault; + private final BlobStore blobStore; + private final BucketNameGenerator nameGenerator; + + public BlobStoreDeletedMessageVault(DeletedMessageMetadataVault messageMetadataVault, BlobStore blobStore, BucketNameGenerator nameGenerator) { + this.messageMetadataVault = messageMetadataVault; + this.blobStore = blobStore; + this.nameGenerator = nameGenerator; + } + + @Override + public Publisher<Void> append(User user, DeletedMessage deletedMessage, InputStream mimeMessage) { + Preconditions.checkNotNull(user); + Preconditions.checkNotNull(deletedMessage); + Preconditions.checkNotNull(mimeMessage); + BucketName bucketName = nameGenerator.currentBucket(); + return blobStore.save(bucketName, mimeMessage) + .map(blobId -> new StorageInformation(bucketName, blobId)) + .map(storageInformation -> new DeletedMessageWithStorageInformation(deletedMessage, storageInformation)) + .flatMap(message -> Mono.from(messageMetadataVault.store(message))) + .then(); + } + + @Override + public Publisher<InputStream> loadMimeMessage(User user, MessageId messageId) { + Preconditions.checkNotNull(user); + Preconditions.checkNotNull(messageId); + return Mono.from(messageMetadataVault.retrieveStorageInformation(user, messageId)) + .map(storageInformation -> blobStore.read(storageInformation.getBucketName(), storageInformation.getBlobId())); + } + + @Override + public Publisher<DeletedMessage> search(User user, Query query) { + Preconditions.checkNotNull(user); + Preconditions.checkNotNull(query); + return Flux.from(messageMetadataVault.listRelatedBuckets()) + .concatMap(bucketName -> Flux.from(messageMetadataVault.listMessages(bucketName, user))) + .map(DeletedMessageWithStorageInformation::getDeletedMessage) + .filter(query.toPredicate()); + } + + @Override + public Publisher<Void> delete(User user, MessageId messageId) { + throw new NotImplementedException("Will be implemented later"); + } + + @Override + public Publisher<User> usersWithVault() { + throw new NotImplementedException("Will be implemented later"); + } + + @Override + public Task deleteExpiredMessagesTask() { + throw new NotImplementedException("Will be implemented later"); + } +} diff --git a/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/blob/BucketNameGenerator.java b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/blob/BucketNameGenerator.java new file mode 100644 index 0000000..37931a2 --- /dev/null +++ b/mailbox/plugin/deleted-messages-vault/src/main/java/org/apache/james/vault/blob/BucketNameGenerator.java @@ -0,0 +1,40 @@ +/**************************************************************** + * 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.vault.blob; + +import java.time.Clock; +import java.time.ZonedDateTime; + +import org.apache.james.blob.api.BucketName; + +public class BucketNameGenerator { + private final Clock clock; + + public BucketNameGenerator(Clock clock) { + this.clock = clock; + } + + public BucketName currentBucket() { + ZonedDateTime now = ZonedDateTime.now(clock); + int month = now.getMonthValue(); + int year = now.getYear(); + return BucketName.of(String.format("deletedMessages-%d-%02d-01", year, month)); + } +} diff --git a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/blob/BlobStoreDeletedMessageVaultTest.java b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/blob/BlobStoreDeletedMessageVaultTest.java new file mode 100644 index 0000000..c4e18f9 --- /dev/null +++ b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/blob/BlobStoreDeletedMessageVaultTest.java @@ -0,0 +1,134 @@ +/**************************************************************** + * 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.vault.blob; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; + +import org.apache.james.blob.api.HashBlobId; +import org.apache.james.blob.memory.MemoryBlobStore; +import org.apache.james.vault.DeletedMessageVault; +import org.apache.james.vault.DeletedMessageVaultContract; +import org.apache.james.vault.memory.metadata.MemoryDeletedMessageMetadataVault; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; + +class BlobStoreDeletedMessageVaultTest implements DeletedMessageVaultContract { + private static final Instant NOW = Instant.parse("2007-12-03T10:15:30.00Z"); + private static final Clock CLOCK = Clock.fixed(NOW, ZoneId.of("UTC")); + + private BlobStoreDeletedMessageVault messageVault; + + @BeforeEach + void setUp() { + messageVault = new BlobStoreDeletedMessageVault(new MemoryDeletedMessageMetadataVault(), + new MemoryBlobStore(new HashBlobId.Factory()), + new BucketNameGenerator(CLOCK)); + } + + @Override + public DeletedMessageVault getVault() { + return messageVault; + } + + + @Disabled("Will be implemented later") + public void deleteShouldThrowOnNullMessageId() { + + } + + @Disabled("Will be implemented later") + public void deleteShouldThrowOnNullUser() { + + } + + @Disabled("Will be implemented in JAMES-2811") + @Override + public void deleteExpiredMessagesTaskShouldCompleteWhenNoMail() { + + } + + @Disabled("Will be implemented in JAMES-2811") + @Override + public void deleteExpiredMessagesTaskShouldCompleteWhenAllMailsDeleted() { + + } + + @Disabled("Will be implemented in JAMES-2811") + @Override + public void deleteExpiredMessagesTaskShouldCompleteWhenOnlyRecentMails() { + + } + + @Disabled("Will be implemented in JAMES-2811") + @Override + public void deleteExpiredMessagesTaskShouldDeleteOldMails() { + + } + + @Disabled("Will be implemented in JAMES-2811") + @Override + public void deleteExpiredMessagesTaskShouldNotDeleteRecentMails() { + + } + + @Disabled("Will be implemented in JAMES-2811") + @Override + public void deleteExpiredMessagesTaskShouldDoNothingWhenEmpty() { + + } + + @Disabled("Will be implemented in JAMES-2811") + @Override + public void deleteExpiredMessagesTaskShouldCompleteWhenOnlyOldMails() { + + } + + @Disabled("Will be implemented later") + @Override + public void deleteShouldRunSuccessfullyInAConcurrentContext() { + + } + + @Disabled("Will be implemented later") + @Override + public void usersWithVaultShouldReturnEmptyWhenNoItem() { + + } + + @Disabled("Will be implemented later") + @Override + public void usersWithVaultShouldReturnAllUsers() { + + } + + @Disabled("Will be implemented later") + @Override + public void searchAllShouldNotReturnDeletedItems() { + + } + + @Disabled("Will be implemented later") + @Override + public void loadMimeMessageShouldReturnEmptyWhenDeleted() { + + } +} \ No newline at end of file diff --git a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/blob/BucketNameGeneratorTest.java b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/blob/BucketNameGeneratorTest.java new file mode 100644 index 0000000..b2a2c6a --- /dev/null +++ b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/blob/BucketNameGeneratorTest.java @@ -0,0 +1,48 @@ +/**************************************************************** + * 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.vault.blob; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; + +import org.apache.james.blob.api.BucketName; +import org.junit.jupiter.api.Test; + +class BucketNameGeneratorTest { + private static final Instant NOW = Instant.parse("2007-12-03T10:15:30.00Z"); + private static final Instant DATE_2 = Instant.parse("2007-07-03T10:15:30.00Z"); + private static final Clock CLOCK = Clock.fixed(NOW, ZoneId.of("UTC")); + private static final Clock CLOCK_2 = Clock.fixed(DATE_2, ZoneId.of("UTC")); + + @Test + void currentBucketShouldReturnBucketFormattedOnFirstDayOfMonth() { + assertThat(new BucketNameGenerator(CLOCK).currentBucket()) + .isEqualTo(BucketName.of("deletedMessages-2007-12-01")); + } + + @Test + void monthShouldBeFormattedWithTwoDigits() { + assertThat(new BucketNameGenerator(CLOCK_2).currentBucket()) + .isEqualTo(BucketName.of("deletedMessages-2007-07-01")); + } +} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org