You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ad...@apache.org on 2018/08/23 12:50:02 UTC

[1/8] james-project git commit: JAMES-2525 ignores links & dirs generated by the james build

Repository: james-project
Updated Branches:
  refs/heads/master d125ba97a -> 8bfefda83


JAMES-2525 ignores links & dirs generated by the james build


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/23cbb7bb
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/23cbb7bb
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/23cbb7bb

Branch: refs/heads/master
Commit: 23cbb7bb42d08687da3beb341cb6af39a1c1c485
Parents: 1ac24c0
Author: Jean Helou <jh...@codamens.fr>
Authored: Mon Aug 20 16:48:26 2018 +0200
Committer: Jean Helou <jh...@codamens.fr>
Committed: Wed Aug 22 11:38:06 2018 +0200

----------------------------------------------------------------------
 .gitignore | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/23cbb7bb/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index a727d71..fbd0e38 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 target/
 dependency-reduced-pom.xml
-
+dockerfiles/run
+.m2


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[2/8] james-project git commit: JAMES-2525 changes ObjectStore#read to return an InputStream

Posted by ad...@apache.org.
JAMES-2525 changes ObjectStore#read to return an InputStream

The original method is renamed `readBytes` name and all
existing uses are changed to follow the rename.

The new method is implemented in the CassandraBlobsDAO and delegates to
the existing implementation.


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/86979704
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/86979704
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/86979704

Branch: refs/heads/master
Commit: 86979704d7467a9910dd571655e54bd29aaef128
Parents: 23cbb7b
Author: Jean Helou <jh...@codamens.fr>
Authored: Mon Aug 20 17:09:39 2018 +0200
Committer: Jean Helou <jh...@codamens.fr>
Committed: Thu Aug 23 14:18:49 2018 +0200

----------------------------------------------------------------------
 .../mail/CassandraAttachmentMapper.java         |  2 +-
 .../cassandra/mail/CassandraMessageDAO.java     |  2 +-
 .../migration/AttachmentV2MigrationTest.java    |  4 +-
 .../org/apache/james/blob/api/ObjectStore.java  |  5 +-
 .../james/blob/api/ObjectStoreException.java    | 31 ++++++++++
 .../james/blob/api/ObjectStoreContract.java     | 61 +++++++++++++++++---
 .../james/blob/cassandra/CassandraBlobsDAO.java | 31 +++++++++-
 .../blob/cassandra/CassandraBlobsDAOTest.java   |  4 +-
 .../cassandra/CassandraMailRepository.java      |  4 +-
 9 files changed, 125 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/86979704/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 678b10b..444ec85 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
@@ -87,7 +87,7 @@ public class CassandraAttachmentMapper implements AttachmentMapper {
             return CompletableFuture.completedFuture(Optional.empty());
         }
         DAOAttachment daoAttachment = daoAttachmentOptional.get();
-        return objectStore.read(daoAttachment.getBlobId())
+        return objectStore.readBytes(daoAttachment.getBlobId())
             .thenApply(bytes -> Optional.of(daoAttachment.toAttachment(bytes)));
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/86979704/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
index 8fe0284..a451adb 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageDAO.java
@@ -372,7 +372,7 @@ public class CassandraMessageDAO {
     }
 
     private CompletableFuture<byte[]> getFieldContent(String field, Row row) {
-        return objectStore.read(blobIdFactory.from(row.getString(field)));
+        return objectStore.readBytes(blobIdFactory.from(row.getString(field)));
     }
 
     public static MessageResult notFound(ComposedMessageIdWithMetaData id) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/86979704/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
index 26bcf94..8a45267 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
@@ -130,9 +130,9 @@ public class AttachmentV2MigrationTest {
             .contains(CassandraAttachmentDAOV2.from(attachment1, BLOB_ID_FACTORY.forPayload(attachment1.getBytes())));
         assertThat(attachmentDAOV2.getAttachment(ATTACHMENT_ID_2).join())
             .contains(CassandraAttachmentDAOV2.from(attachment2, BLOB_ID_FACTORY.forPayload(attachment2.getBytes())));
-        assertThat(blobsDAO.read(BLOB_ID_FACTORY.forPayload(attachment1.getBytes())).join())
+        assertThat(blobsDAO.readBytes(BLOB_ID_FACTORY.forPayload(attachment1.getBytes())).join())
             .isEqualTo(attachment1.getBytes());
-        assertThat(blobsDAO.read(BLOB_ID_FACTORY.forPayload(attachment2.getBytes())).join())
+        assertThat(blobsDAO.readBytes(BLOB_ID_FACTORY.forPayload(attachment2.getBytes())).join())
             .isEqualTo(attachment2.getBytes());
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/86979704/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStore.java
----------------------------------------------------------------------
diff --git a/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStore.java b/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStore.java
index c2bd88a..7582a2c 100644
--- a/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStore.java
+++ b/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStore.java
@@ -18,11 +18,14 @@
  ****************************************************************/
 package org.apache.james.blob.api;
 
+import java.io.InputStream;
 import java.util.concurrent.CompletableFuture;
 
 public interface ObjectStore {
 
     CompletableFuture<BlobId> save(byte[] data);
 
-    CompletableFuture<byte[]> read(BlobId blobId);
+    CompletableFuture<byte[]> readBytes(BlobId blobId);
+
+    InputStream read(BlobId blobId);
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/86979704/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStoreException.java
----------------------------------------------------------------------
diff --git a/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStoreException.java b/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStoreException.java
new file mode 100644
index 0000000..624a8e0
--- /dev/null
+++ b/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStoreException.java
@@ -0,0 +1,31 @@
+/****************************************************************
+ * 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.blob.api;
+
+public class ObjectStoreException extends RuntimeException {
+
+    public ObjectStoreException(String message) {
+        super(message);
+    }
+
+    public ObjectStoreException(String message, Throwable cause) {
+        super(message,cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/86979704/server/blob/blob-api/src/test/java/org/apache/james/blob/api/ObjectStoreContract.java
----------------------------------------------------------------------
diff --git a/server/blob/blob-api/src/test/java/org/apache/james/blob/api/ObjectStoreContract.java b/server/blob/blob-api/src/test/java/org/apache/james/blob/api/ObjectStoreContract.java
index bd4bd8e..bb51e14 100644
--- a/server/blob/blob-api/src/test/java/org/apache/james/blob/api/ObjectStoreContract.java
+++ b/server/blob/blob-api/src/test/java/org/apache/james/blob/api/ObjectStoreContract.java
@@ -21,9 +21,12 @@ package org.apache.james.blob.api;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 
+import org.apache.commons.io.IOUtils;
 import org.junit.jupiter.api.Test;
 
 import com.google.common.base.Strings;
@@ -44,7 +47,7 @@ public interface ObjectStoreContract {
     default void saveShouldSaveEmptyData() throws Exception {
         BlobId blobId = testee().save(new byte[]{}).join();
 
-        byte[] bytes = testee().read(blobId).join();
+        byte[] bytes = testee().readBytes(blobId).join();
 
         assertThat(new String(bytes, StandardCharsets.UTF_8)).isEmpty();
     }
@@ -57,39 +60,79 @@ public interface ObjectStoreContract {
     }
 
     @Test
-    default void readShouldBeEmptyWhenNoExisting() throws IOException {
-        byte[] bytes = testee().read(blobIdFactory().from("unknown")).join();
+    default void readBytesShouldBeEmptyWhenNoExisting() throws IOException {
+        byte[] bytes = testee().readBytes(blobIdFactory().from("unknown")).join();
 
         assertThat(bytes).isEmpty();
     }
 
     @Test
-    default void readShouldReturnSavedData() throws IOException {
+    default void readBytesShouldReturnSavedData() throws IOException {
         BlobId blobId = testee().save("toto".getBytes(StandardCharsets.UTF_8)).join();
 
-        byte[] bytes = testee().read(blobId).join();
+        byte[] bytes = testee().readBytes(blobId).join();
 
         assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo("toto");
     }
 
     @Test
-    default void readShouldReturnLongSavedData() throws IOException {
+    default void readBytesShouldReturnLongSavedData() throws IOException {
         String longString = Strings.repeat("0123456789\n", 1000);
         BlobId blobId = testee().save(longString.getBytes(StandardCharsets.UTF_8)).join();
 
-        byte[] bytes = testee().read(blobId).join();
+        byte[] bytes = testee().readBytes(blobId).join();
 
         assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo(longString);
     }
 
     @Test
-    default void readShouldReturnBigSavedData() throws IOException {
+    default void readBytesShouldReturnBigSavedData() throws IOException {
         // 12 MB of text
         String bigString = Strings.repeat("0123456789\r\n", 1024 * 1024);
         BlobId blobId = testee().save(bigString.getBytes(StandardCharsets.UTF_8)).join();
 
-        byte[] bytes = testee().read(blobId).join();
+        byte[] bytes = testee().readBytes(blobId).join();
 
         assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo(bigString);
     }
+
+    @Test
+    default void readShouldBeEmptyWhenNoExistingStream() throws IOException {
+        InputStream stream = testee().read(blobIdFactory().from("unknown"));
+
+        assertThat(stream.read()).isEqualTo(IOUtils.EOF);
+    }
+
+    @Test
+    default void readShouldReturnSavedData() throws IOException {
+        byte[] bytes = "toto".getBytes(StandardCharsets.UTF_8);
+        BlobId blobId = testee().save(bytes).join();
+
+        InputStream read = testee().read(blobId);
+
+        assertThat(read).hasSameContentAs(new ByteArrayInputStream(bytes));
+    }
+
+    @Test
+    default void readShouldReturnLongSavedData() throws IOException {
+        String longString = Strings.repeat("0123456789\n", 1000);
+        byte[] bytes = longString.getBytes(StandardCharsets.UTF_8);
+        BlobId blobId = testee().save(bytes).join();
+
+        InputStream read = testee().read(blobId);
+
+        assertThat(read).hasSameContentAs(new ByteArrayInputStream(bytes));
+    }
+
+    @Test
+    default void readShouldReturnBigSavedData() throws IOException {
+        // 12 MB of text
+        String bigString = Strings.repeat("0123456789\r\n", 1024 * 1024);
+        byte[] bytes = bigString.getBytes(StandardCharsets.UTF_8);
+        BlobId blobId = testee().save(bytes).join();
+
+        InputStream read = testee().read(blobId);
+
+        assertThat(read).hasSameContentAs(new ByteArrayInputStream(bytes));
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/86979704/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
----------------------------------------------------------------------
diff --git a/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java b/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
index 7c8eda8..3436d73 100644
--- a/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
+++ b/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
@@ -24,7 +24,11 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.Pipe;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.stream.IntStream;
@@ -37,6 +41,7 @@ import org.apache.james.backends.cassandra.init.configuration.CassandraConfigura
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
 import org.apache.james.blob.api.BlobId;
 import org.apache.james.blob.api.ObjectStore;
+import org.apache.james.blob.api.ObjectStoreException;
 import org.apache.james.blob.cassandra.BlobTable.BlobParts;
 import org.apache.james.blob.cassandra.utils.DataChunker;
 import org.apache.james.util.FluentFutureStream;
@@ -47,6 +52,8 @@ import org.slf4j.LoggerFactory;
 import com.datastax.driver.core.PreparedStatement;
 import com.datastax.driver.core.Row;
 import com.datastax.driver.core.Session;
+import com.github.fge.lambdas.Throwing;
+import com.github.fge.lambdas.consumers.ConsumerChainer;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
@@ -149,7 +156,7 @@ public class CassandraBlobsDAO implements ObjectStore {
     }
 
     @Override
-    public CompletableFuture<byte[]> read(BlobId blobId) {
+    public CompletableFuture<byte[]> readBytes(BlobId blobId) {
         return cassandraAsyncExecutor.executeSingleRow(
             select.bind()
                 .setString(BlobTable.ID, blobId.asString()))
@@ -209,4 +216,26 @@ public class CassandraBlobsDAO implements ObjectStore {
             this.row = row;
         }
     }
+
+    @Override
+    public InputStream read(BlobId blobId) {
+        try {
+            Pipe pipe = Pipe.open();
+            ConsumerChainer<ByteBuffer> consumer = Throwing.consumer(
+                bytes -> {
+                    try (Pipe.SinkChannel sink = pipe.sink()) {
+                        sink.write(bytes);
+                    }
+                }
+            );
+            readBytes(blobId)
+                .thenApply(ByteBuffer::wrap)
+                .thenAccept(consumer.sneakyThrow());
+            return Channels.newInputStream(pipe.source());
+        } catch (IOException cause) {
+            throw new ObjectStoreException(
+                "Failed to convert CompletableFuture<byte[]> to InputStream",
+                cause);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/86979704/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobsDAOTest.java
----------------------------------------------------------------------
diff --git a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobsDAOTest.java b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobsDAOTest.java
index 07af72f..cb7db4d 100644
--- a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobsDAOTest.java
+++ b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobsDAOTest.java
@@ -84,11 +84,11 @@ public class CassandraBlobsDAOTest implements ObjectStoreContract {
     }
 
     @Test
-    public void readShouldReturnSplitSavedDataByChunk() throws IOException {
+    public void readBytesShouldReturnSplitSavedDataByChunk() throws IOException {
         String longString = Strings.repeat("0123456789\n", MULTIPLE_CHUNK_SIZE);
         BlobId blobId = testee.save(longString.getBytes(StandardCharsets.UTF_8)).join();
 
-        byte[] bytes = testee.read(blobId).join();
+        byte[] bytes = testee.readBytes(blobId).join();
 
         assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo(longString);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/86979704/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
----------------------------------------------------------------------
diff --git a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
index c2e449d..9074481 100644
--- a/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
+++ b/server/mailrepository/mailrepository-cassandra/src/main/java/org/apache/james/mailrepository/cassandra/CassandraMailRepository.java
@@ -158,8 +158,8 @@ public class CassandraMailRepository implements MailRepository {
 
     public CompletableFuture<Mail> toMail(CassandraMailRepositoryMailDAO.MailDTO mailDTO) {
         return CompletableFutureUtil.combine(
-            objectStore.read(mailDTO.getHeaderBlobId()),
-            objectStore.read(mailDTO.getBodyBlobId()),
+            objectStore.readBytes(mailDTO.getHeaderBlobId()),
+            objectStore.readBytes(mailDTO.getBodyBlobId()),
             Bytes::concat)
             .thenApply(this::toMimeMessage)
             .thenApply(mimeMessage -> mailDTO.getMailBuilder()


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[7/8] james-project git commit: Merge remote-tracking branch 'jhelou/feat/objectstore-streams'

Posted by ad...@apache.org.
Merge remote-tracking branch 'jhelou/feat/objectstore-streams'


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/b6dcb510
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/b6dcb510
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/b6dcb510

Branch: refs/heads/master
Commit: b6dcb51043aff650b35221128264faf899f9ab48
Parents: d125ba9 e906b04
Author: Antoine Duprat <ad...@linagora.com>
Authored: Thu Aug 23 14:49:28 2018 +0200
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Thu Aug 23 14:49:28 2018 +0200

----------------------------------------------------------------------
 .gitignore                                      |  3 +-
 .../mail/CassandraAttachmentMapper.java         |  2 +-
 .../cassandra/mail/CassandraMessageDAO.java     |  2 +-
 .../migration/AttachmentV2MigrationTest.java    |  6 +-
 .../org/apache/james/blob/api/ObjectStore.java  |  7 +-
 .../james/blob/api/ObjectStoreException.java    | 31 +++++++
 .../james/blob/api/ObjectStoreContract.java     | 87 +++++++++++++++++---
 .../james/blob/cassandra/CassandraBlobsDAO.java | 40 ++++++++-
 .../blob/cassandra/CassandraBlobsDAOTest.java   |  4 +-
 .../cassandra/CassandraMailRepository.java      |  4 +-
 10 files changed, 164 insertions(+), 22 deletions(-)
----------------------------------------------------------------------



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[3/8] james-project git commit: JAMES-2525 adds ObjectStore#save(InputStream)

Posted by ad...@apache.org.
JAMES-2525 adds ObjectStore#save(InputStream)

Since this signature doesn't conflict with the original `save(byte[])`
the name is kept as is.

The implementatoin of the new method in the CassandraBlobDAO delegates
to the original save.


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/e906b04e
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/e906b04e
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/e906b04e

Branch: refs/heads/master
Commit: e906b04ee4bddc498547123291946b9a5797e260
Parents: 8697970
Author: Jean Helou <jh...@codamens.fr>
Authored: Mon Aug 20 17:31:15 2018 +0200
Committer: Jean Helou <jh...@codamens.fr>
Committed: Thu Aug 23 14:19:24 2018 +0200

----------------------------------------------------------------------
 .../migration/AttachmentV2MigrationTest.java    |  2 +-
 .../org/apache/james/blob/api/ObjectStore.java  |  2 ++
 .../james/blob/api/ObjectStoreContract.java     | 26 +++++++++++++++++++-
 .../james/blob/cassandra/CassandraBlobsDAO.java |  9 +++++++
 4 files changed, 37 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/e906b04e/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
index 8a45267..738045a 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2MigrationTest.java
@@ -171,7 +171,7 @@ public class AttachmentV2MigrationTest {
         when(attachmentDAO.retrieveAll()).thenReturn(Stream.of(
             attachment1,
             attachment2));
-        when(blobsDAO.save(any())).thenThrow(new RuntimeException());
+        when(blobsDAO.save(any(byte[].class))).thenThrow(new RuntimeException());
 
         assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e906b04e/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStore.java
----------------------------------------------------------------------
diff --git a/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStore.java b/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStore.java
index 7582a2c..8b22d55 100644
--- a/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStore.java
+++ b/server/blob/blob-api/src/main/java/org/apache/james/blob/api/ObjectStore.java
@@ -25,6 +25,8 @@ public interface ObjectStore {
 
     CompletableFuture<BlobId> save(byte[] data);
 
+    CompletableFuture<BlobId> save(InputStream data);
+
     CompletableFuture<byte[]> readBytes(BlobId blobId);
 
     InputStream read(BlobId blobId);

http://git-wip-us.apache.org/repos/asf/james-project/blob/e906b04e/server/blob/blob-api/src/test/java/org/apache/james/blob/api/ObjectStoreContract.java
----------------------------------------------------------------------
diff --git a/server/blob/blob-api/src/test/java/org/apache/james/blob/api/ObjectStoreContract.java b/server/blob/blob-api/src/test/java/org/apache/james/blob/api/ObjectStoreContract.java
index bb51e14..dfd7038 100644
--- a/server/blob/blob-api/src/test/java/org/apache/james/blob/api/ObjectStoreContract.java
+++ b/server/blob/blob-api/src/test/java/org/apache/james/blob/api/ObjectStoreContract.java
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
+
 package org.apache.james.blob.api;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -39,7 +40,13 @@ public interface ObjectStoreContract {
 
     @Test
     default void saveShouldReturnEmptyWhenNullData() throws Exception {
-        assertThatThrownBy(() -> testee().save(null))
+        assertThatThrownBy(() -> testee().save((byte[]) null))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    default void saveShouldReturnEmptyWhenNullInputStream() throws Exception {
+        assertThatThrownBy(() -> testee().save((InputStream) null))
             .isInstanceOf(NullPointerException.class);
     }
 
@@ -53,6 +60,15 @@ public interface ObjectStoreContract {
     }
 
     @Test
+    default void saveShouldSaveEmptyInputStream() throws Exception {
+        BlobId blobId = testee().save(new ByteArrayInputStream(new byte[]{})).join();
+
+        byte[] bytes = testee().readBytes(blobId).join();
+
+        assertThat(new String(bytes, StandardCharsets.UTF_8)).isEmpty();
+    }
+
+    @Test
     default void saveShouldReturnBlobId() throws Exception {
         BlobId blobId = testee().save("toto".getBytes(StandardCharsets.UTF_8)).join();
 
@@ -60,6 +76,14 @@ public interface ObjectStoreContract {
     }
 
     @Test
+    default void saveShouldReturnBlobIdOfInputStream() throws Exception {
+        BlobId blobId =
+            testee().save(new ByteArrayInputStream("toto".getBytes(StandardCharsets.UTF_8))).join();
+
+        assertThat(blobId).isEqualTo(blobIdFactory().from("31f7a65e315586ac198bd798b6629ce4903d0899476d5741a9f32e2e521b6a66"));
+    }
+
+    @Test
     default void readBytesShouldBeEmptyWhenNoExisting() throws IOException {
         byte[] bytes = testee().readBytes(blobIdFactory().from("unknown")).join();
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/e906b04e/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
----------------------------------------------------------------------
diff --git a/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java b/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
index 3436d73..d37bf4f 100644
--- a/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
+++ b/server/blob/blob-cassandra/src/main/java/org/apache/james/blob/cassandra/CassandraBlobsDAO.java
@@ -36,6 +36,7 @@ import java.util.stream.Stream;
 
 import javax.inject.Inject;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
@@ -238,4 +239,12 @@ public class CassandraBlobsDAO implements ObjectStore {
                 cause);
         }
     }
+
+    @Override
+    public CompletableFuture<BlobId> save(InputStream data) {
+        Preconditions.checkNotNull(data);
+        return CompletableFuture
+            .supplyAsync(Throwing.supplier(() -> IOUtils.toByteArray(data)).sneakyThrow())
+            .thenCompose(this::save);
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[4/8] james-project git commit: JAMES-2528 implementation of a FilteringManagement API using Event Sourcing

Posted by ad...@apache.org.
JAMES-2528 implementation of a FilteringManagement API using Event Sourcing


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/58f0f800
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/58f0f800
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/58f0f800

Branch: refs/heads/master
Commit: 58f0f800632189fda5fd1a4b9d5cfd89e991f2c4
Parents: d125ba9
Author: Matthieu Baechler <ma...@apache.org>
Authored: Wed Aug 22 16:08:23 2018 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Thu Aug 23 14:29:33 2018 +0200

----------------------------------------------------------------------
 server/data/data-jmap/pom.xml                   | 23 ++++-
 .../jmap/api/filtering/FilteringManagement.java | 32 +++++++
 .../apache/james/jmap/api/filtering/Rule.java   | 67 +++++++++++++
 .../api/filtering/impl/DefineRulesCommand.java  | 76 +++++++++++++++
 .../impl/DefineRulesCommandHandler.java         | 52 +++++++++++
 .../impl/EventSourcingFilteringManagement.java  | 69 ++++++++++++++
 .../api/filtering/impl/FilteringAggregate.java  | 90 ++++++++++++++++++
 .../filtering/impl/FilteringAggregateId.java    | 73 +++++++++++++++
 .../jmap/api/filtering/impl/RuleSetDefined.java | 85 +++++++++++++++++
 .../api/filtering/FilteringAggregateIdTest.java | 86 +++++++++++++++++
 .../filtering/FilteringManagementContract.java  | 98 ++++++++++++++++++++
 .../james/jmap/api/filtering/RuleTest.java      | 41 ++++++++
 .../filtering/impl/DefineRulesCommandTest.java  | 51 ++++++++++
 .../EventSourcingFilteringManagementTest.java   | 32 +++++++
 14 files changed, 873 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/pom.xml
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/pom.xml b/server/data/data-jmap/pom.xml
index 7c7f049..169120b 100644
--- a/server/data/data-jmap/pom.xml
+++ b/server/data/data-jmap/pom.xml
@@ -42,6 +42,15 @@
             <artifactId>james-server-util</artifactId>
         </dependency>
         <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>event-sourcing-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>event-sourcing-event-store-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
             <scope>test</scope>
@@ -55,8 +64,8 @@
             <artifactId>javax.inject</artifactId>
         </dependency>
         <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
+            <groupId>nl.jqno.equalsverifier</groupId>
+            <artifactId>equalsverifier</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -74,6 +83,16 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.vintage</groupId>
+            <artifactId>junit-vintage-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java
new file mode 100644
index 0000000..a8b1c4b
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/FilteringManagement.java
@@ -0,0 +1,32 @@
+/****************************************************************
+ * 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.jmap.api.filtering;
+
+import java.util.List;
+
+import org.apache.james.core.User;
+
+public interface FilteringManagement {
+
+    void defineRulesForUser(User user, List<Rule> rules);
+
+    List<Rule> listRulesForUser(User user);
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
new file mode 100644
index 0000000..8bca30a
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/Rule.java
@@ -0,0 +1,67 @@
+/****************************************************************
+ * 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.jmap.api.filtering;
+
+import java.util.Objects;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class Rule {
+
+    private final String id;
+
+    public static Rule of(String id) {
+        return new Rule(id);
+    }
+
+    public Rule(String id) {
+        Preconditions.checkNotNull(id);
+
+        this.id = id;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof Rule) {
+            Rule rule = (Rule) o;
+
+            return Objects.equals(this.id, rule.id);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(id);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("id", id)
+            .toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommand.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommand.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommand.java
new file mode 100644
index 0000000..0cd256c
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommand.java
@@ -0,0 +1,76 @@
+/****************************************************************
+ * 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.jmap.api.filtering.impl;
+
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.james.core.User;
+import org.apache.james.eventsourcing.Command;
+import org.apache.james.jmap.api.filtering.Rule;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class DefineRulesCommand implements Command {
+
+    private final User user;
+    private final List<Rule> rules;
+
+    public DefineRulesCommand(User user, List<Rule> rules) {
+        Preconditions.checkNotNull(user);
+        Preconditions.checkNotNull(rules);
+
+        this.user = user;
+        this.rules = rules;
+    }
+
+    public List<Rule> getRules() {
+        return rules;
+    }
+
+    public User getUser() {
+        return user;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof DefineRulesCommand) {
+            DefineRulesCommand that = (DefineRulesCommand) o;
+
+            return Objects.equals(this.user, that.user)
+                && Objects.equals(this.rules, that.rules);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(user, rules);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("user", user)
+            .add("rules", rules)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandHandler.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandHandler.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandHandler.java
new file mode 100644
index 0000000..a613893
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandHandler.java
@@ -0,0 +1,52 @@
+/****************************************************************
+ * 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.jmap.api.filtering.impl;
+
+import java.util.List;
+
+import org.apache.james.eventsourcing.CommandHandler;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+
+public class DefineRulesCommandHandler implements CommandHandler<DefineRulesCommand> {
+
+    private final EventStore eventStore;
+
+    public DefineRulesCommandHandler(EventStore eventStore) {
+        this.eventStore = eventStore;
+    }
+
+    @Override
+    public Class<DefineRulesCommand> handledClass() {
+        return DefineRulesCommand.class;
+    }
+
+    @Override
+    public List<? extends Event> handle(DefineRulesCommand storeCommand) {
+        FilteringAggregateId aggregateId = new FilteringAggregateId(storeCommand.getUser());
+
+        return FilteringAggregate
+            .load(
+                aggregateId,
+                eventStore.getEventsOfAggregate(aggregateId))
+            .defineRules(storeCommand.getRules());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java
new file mode 100644
index 0000000..2fbba65
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagement.java
@@ -0,0 +1,69 @@
+/****************************************************************
+ * 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.jmap.api.filtering.impl;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.james.core.User;
+import org.apache.james.eventsourcing.EventSourcingSystem;
+import org.apache.james.eventsourcing.Subscriber;
+import org.apache.james.eventsourcing.eventstore.EventStore;
+import org.apache.james.jmap.api.filtering.FilteringManagement;
+import org.apache.james.jmap.api.filtering.Rule;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+
+public class EventSourcingFilteringManagement implements FilteringManagement {
+
+    private static final ImmutableSet<Subscriber> NO_SUBSCRIBER = ImmutableSet.of();
+
+    private final EventStore eventStore;
+    private final EventSourcingSystem eventSourcingSystem;
+
+    @Inject
+    public EventSourcingFilteringManagement(EventStore eventStore) {
+        this.eventSourcingSystem = new EventSourcingSystem(
+            ImmutableSet.of(new DefineRulesCommandHandler(eventStore)),
+            NO_SUBSCRIBER,
+            eventStore);
+        this.eventStore = eventStore;
+    }
+
+    @Override
+    public void defineRulesForUser(User user, List<Rule> rules) {
+        eventSourcingSystem.dispatch(new DefineRulesCommand(user, rules));
+    }
+
+    @Override
+    public List<Rule> listRulesForUser(User user) {
+        Preconditions.checkNotNull(user);
+
+        FilteringAggregateId aggregateId = new FilteringAggregateId(user);
+
+        return FilteringAggregate
+            .load(
+                aggregateId,
+                eventStore.getEventsOfAggregate(aggregateId))
+            .listRules();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregate.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregate.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregate.java
new file mode 100644
index 0000000..33970f2
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregate.java
@@ -0,0 +1,90 @@
+/****************************************************************
+ * 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.jmap.api.filtering.impl;
+
+import java.util.List;
+
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.eventstore.History;
+import org.apache.james.jmap.api.filtering.Rule;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+public class FilteringAggregate {
+
+    public static FilteringAggregate load(FilteringAggregateId aggregateId, History eventsOfAggregate) {
+        return new FilteringAggregate(aggregateId, eventsOfAggregate);
+    }
+
+    private static class State {
+
+        static State initial() {
+            return new State(ImmutableList.of());
+        }
+
+        final ImmutableList<Rule> rules;
+
+        private State(ImmutableList<Rule> rules) {
+            this.rules = rules;
+        }
+
+        State set(ImmutableList<Rule> rules) {
+            return new State(rules);
+        }
+    }
+
+    private final FilteringAggregateId aggregateId;
+    private final History history;
+    private State state;
+
+    private FilteringAggregate(FilteringAggregateId aggregateId, History history) {
+        this.aggregateId = aggregateId;
+        this.state = State.initial();
+        history.getEvents().forEach(this::apply);
+        this.history = history;
+    }
+
+    public List<? extends Event> defineRules(List<Rule> rules) {
+        Preconditions.checkArgument(shouldNotContainDuplicates(rules));
+        ImmutableList<RuleSetDefined> events = ImmutableList.of(
+            new RuleSetDefined(aggregateId, history.getNextEventId(), ImmutableList.copyOf(rules)));
+        events.forEach(this::apply);
+        return events;
+    }
+
+    private boolean shouldNotContainDuplicates(List<Rule> rules) {
+        long uniqueIdCount = rules.stream()
+            .map(Rule::getId)
+            .distinct()
+            .count();
+        return uniqueIdCount == rules.size();
+    }
+
+    public List<Rule> listRules() {
+        return state.rules;
+    }
+
+    private void apply(Event event) {
+        if (event instanceof RuleSetDefined) {
+            state = state.set(((RuleSetDefined)event).getRules());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregateId.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregateId.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregateId.java
new file mode 100644
index 0000000..635f045
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/FilteringAggregateId.java
@@ -0,0 +1,73 @@
+/****************************************************************
+ * 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.jmap.api.filtering.impl;
+
+import java.util.Objects;
+
+import org.apache.james.core.User;
+import org.apache.james.eventsourcing.AggregateId;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class FilteringAggregateId implements AggregateId {
+    private static final String SEPARATOR = "/";
+    private static final String PREFIX = "FilteringRule";
+
+    public static final FilteringAggregateId parse(String rawString) {
+        Preconditions.checkArgument(rawString.startsWith(PREFIX + SEPARATOR));
+        return new FilteringAggregateId(User.fromUsername(rawString.substring(PREFIX.length() + SEPARATOR.length())));
+    }
+
+    private final User user;
+
+    public FilteringAggregateId(User user) {
+        Preconditions.checkNotNull(user);
+
+        this.user = user;
+    }
+
+    @Override
+    public String asAggregateKey() {
+        return PREFIX + SEPARATOR + user.asString();
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof FilteringAggregateId) {
+            FilteringAggregateId that = (FilteringAggregateId) o;
+
+            return Objects.equals(this.user, that.user);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(user);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("user", user)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/RuleSetDefined.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/RuleSetDefined.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/RuleSetDefined.java
new file mode 100644
index 0000000..dacba35
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/filtering/impl/RuleSetDefined.java
@@ -0,0 +1,85 @@
+/****************************************************************
+ * 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.jmap.api.filtering.impl;
+
+import java.util.Objects;
+
+import org.apache.james.eventsourcing.AggregateId;
+import org.apache.james.eventsourcing.Event;
+import org.apache.james.eventsourcing.EventId;
+import org.apache.james.jmap.api.filtering.Rule;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+
+public class RuleSetDefined implements Event {
+
+    private final FilteringAggregateId aggregateId;
+    private final EventId eventId;
+    private final ImmutableList<Rule> rules;
+
+    RuleSetDefined(FilteringAggregateId aggregateId, EventId eventId, ImmutableList<Rule> rules) {
+        this.aggregateId = aggregateId;
+        this.eventId = eventId;
+        this.rules = rules;
+    }
+
+    @Override
+    public EventId eventId() {
+        return eventId;
+    }
+
+    @Override
+    public AggregateId getAggregateId() {
+        return aggregateId;
+    }
+
+    public ImmutableList<Rule> getRules() {
+        return rules;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        RuleSetDefined that = (RuleSetDefined) o;
+        return Objects.equals(aggregateId, that.aggregateId) &&
+            Objects.equals(eventId, that.eventId) &&
+            Objects.equals(rules, that.rules);
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(aggregateId, eventId, rules);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("aggregateId", aggregateId)
+            .add("eventId", eventId)
+            .add("rules", rules)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringAggregateIdTest.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringAggregateIdTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringAggregateIdTest.java
new file mode 100644
index 0000000..8588938
--- /dev/null
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringAggregateIdTest.java
@@ -0,0 +1,86 @@
+/****************************************************************
+ * 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.jmap.api.filtering;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.core.User;
+
+import org.apache.james.jmap.api.filtering.impl.FilteringAggregateId;
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class FilteringAggregateIdTest {
+
+    @Test
+    void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(FilteringAggregateId.class).verify();
+    }
+
+    @Test
+    void constructorShouldThrowWhenNullDomain() {
+        assertThatThrownBy(() -> new FilteringAggregateId(null))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    void asAggregateKeyShouldReturnAStringContainingThePrefixAndTheDomain() {
+        assertThat(new FilteringAggregateId(User.fromUsername("foo@bar.space")).asAggregateKey())
+            .isEqualTo("FilteringRule/foo@bar.space");
+    }
+
+    @Test
+    void parseShouldThrowWhenNullString() {
+        assertThatThrownBy(() -> FilteringAggregateId.parse(null))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    void parseShouldThrowWhenStringDoesntMatchPrefix() {
+        assertThatThrownBy(() -> FilteringAggregateId.parse("WrongPrefix/foo"))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    void parseShouldThrowWhenStringDoesntContainSeparator() {
+        assertThatThrownBy(() -> FilteringAggregateId.parse("WrongPrefix"))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    void parseShouldThrowWhenStringDoesntContainUser() {
+        assertThatThrownBy(() -> FilteringAggregateId.parse("FilteringRule/"))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    void parseShouldThrowWhenStringDoesntHavePrefix() {
+        assertThatThrownBy(() -> FilteringAggregateId.parse("FilteringRulefoo"))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    void parseShouldKeepSlashInUsername() {
+        assertThat(FilteringAggregateId.parse("FilteringRule/f/oo@bar.space").asAggregateKey())
+            .isEqualTo("FilteringRule/f/oo@bar.space");
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
new file mode 100644
index 0000000..98683b8
--- /dev/null
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
@@ -0,0 +1,98 @@
+/****************************************************************
+ * 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.jmap.api.filtering;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.core.User;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public interface FilteringManagementContract {
+
+    String BART_SIMPSON_CARTOON = "bart@simpson.cartoon";
+    Rule RULE_1 = Rule.of("1");
+    Rule RULE_2 = Rule.of("2");
+    Rule RULE_3 = Rule.of("3");
+
+    FilteringManagement instanciateFilteringManagement();
+
+    @Test
+    default void listingRulesForUnknownUserShouldReturnEmptyList() {
+        User user = User.fromUsername(BART_SIMPSON_CARTOON);
+        assertThat(instanciateFilteringManagement().listRulesForUser(user)).isEmpty();
+    }
+
+    @Test
+    default void listingRulesShouldThrowWhenNullUser() {
+        User user = null;
+        assertThatThrownBy(() -> instanciateFilteringManagement().listRulesForUser(user)).isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    default void listingRulesShouldReturnDefinedRules() {
+        User user = User.fromUsername(BART_SIMPSON_CARTOON);
+        FilteringManagement testee = instanciateFilteringManagement();
+        testee.defineRulesForUser(user, ImmutableList.of(RULE_1, RULE_2));
+        assertThat(testee.listRulesForUser(user)).containsExactly(RULE_1, RULE_2);
+    }
+
+    @Test
+    default void listingRulesShouldReturnLastDefinedRules() {
+        User user = User.fromUsername(BART_SIMPSON_CARTOON);
+        FilteringManagement testee = instanciateFilteringManagement();
+        testee.defineRulesForUser(user, ImmutableList.of(RULE_1, RULE_2));
+        testee.defineRulesForUser(user, ImmutableList.of(RULE_2, RULE_1));
+        assertThat(testee.listRulesForUser(user)).containsExactly(RULE_2, RULE_1);
+    }
+
+    @Test
+    default void definingRulesShouldThrowWhenDuplicateRules() {
+        User user = User.fromUsername(BART_SIMPSON_CARTOON);
+        FilteringManagement testee = instanciateFilteringManagement();
+        assertThatThrownBy(() -> testee.defineRulesForUser(user, ImmutableList.of(RULE_1, RULE_1)))
+            .isInstanceOf(IllegalArgumentException.class);
+    }
+
+    @Test
+    default void definingRulesShouldThrowWhenNullUser() {
+        FilteringManagement testee = instanciateFilteringManagement();
+        assertThatThrownBy(() -> testee.defineRulesForUser(null, ImmutableList.of(RULE_1, RULE_1)))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    default void definingRulesShouldThrowWhenNullRuleList() {
+        User user = User.fromUsername(BART_SIMPSON_CARTOON);
+        FilteringManagement testee = instanciateFilteringManagement();
+        assertThatThrownBy(() -> testee.defineRulesForUser(user, null))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    default void definingRulesShouldKeepOrdering() {
+        User user = User.fromUsername(BART_SIMPSON_CARTOON);
+        FilteringManagement testee = instanciateFilteringManagement();
+        testee.defineRulesForUser(user, ImmutableList.of(RULE_3, RULE_2, RULE_1));
+        assertThat(testee.listRulesForUser(user)).containsExactly(RULE_3, RULE_2, RULE_1);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java
new file mode 100644
index 0000000..fc10f6a
--- /dev/null
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/RuleTest.java
@@ -0,0 +1,41 @@
+/****************************************************************
+ * 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.jmap.api.filtering;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class RuleTest {
+
+    @Test
+    void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(Rule.class)
+            .verify();
+    }
+
+    @Test
+    void constructorShouldThrowWhenNullId() {
+        assertThatThrownBy(() -> new Rule(null))
+            .isInstanceOf(NullPointerException.class);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java
new file mode 100644
index 0000000..a917fdd
--- /dev/null
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/DefineRulesCommandTest.java
@@ -0,0 +1,51 @@
+/****************************************************************
+ * 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.jmap.api.filtering.impl;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.core.User;
+import org.apache.james.jmap.api.filtering.Rule;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class DefineRulesCommandTest {
+
+    @Test
+    void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(DefineRulesCommand.class)
+            .verify();
+    }
+
+    @Test
+    void constructorShouldThrowWhenNullUser() {
+        assertThatThrownBy(() -> new DefineRulesCommand(null, ImmutableList.of(Rule.of("1"), Rule.of("2"))))
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    void constructorShouldThrowWhenNullRuleList() {
+        assertThatThrownBy(() -> new DefineRulesCommand(User.fromUsername("adam@james.org"), null))
+            .isInstanceOf(NullPointerException.class);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/58f0f800/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagementTest.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagementTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagementTest.java
new file mode 100644
index 0000000..45120c3
--- /dev/null
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/impl/EventSourcingFilteringManagementTest.java
@@ -0,0 +1,32 @@
+/****************************************************************
+ * 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.jmap.api.filtering.impl;
+
+import org.apache.james.eventsourcing.eventstore.memory.InMemoryEventStore;
+import org.apache.james.jmap.api.filtering.FilteringManagement;
+import org.apache.james.jmap.api.filtering.FilteringManagementContract;
+
+public class EventSourcingFilteringManagementTest implements FilteringManagementContract {
+
+    @Override
+    public FilteringManagement instanciateFilteringManagement() {
+        return new EventSourcingFilteringManagement(new InMemoryEventStore());
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[6/8] james-project git commit: JAMES-2528 some checkstyle fixes

Posted by ad...@apache.org.
JAMES-2528 some checkstyle fixes


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/8790fe6a
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/8790fe6a
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/8790fe6a

Branch: refs/heads/master
Commit: 8790fe6afa3a1e6b660af1475afae2edf19d3a55
Parents: 61a1164
Author: Matthieu Baechler <ma...@apache.org>
Authored: Wed Aug 22 16:39:59 2018 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Thu Aug 23 14:30:37 2018 +0200

----------------------------------------------------------------------
 .../src/test/java/org/apache/james/ESReporterTest.java       | 8 ++++----
 .../test/java/org/apache/james/jmap/TestingConstants.java    | 6 +++---
 .../jmap/methods/integration/ForwardIntegrationTest.java     | 6 +++---
 .../james/webadmin/routes/MailRepositoriesRoutesTest.java    | 2 +-
 4 files changed, 11 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/8790fe6a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/ESReporterTest.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/ESReporterTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/ESReporterTest.java
index d9b709c..f7cab75 100644
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/ESReporterTest.java
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/ESReporterTest.java
@@ -25,10 +25,6 @@ import static org.apache.james.jmap.HttpJmapAuthentication.authenticateJamesUser
 import static org.apache.james.jmap.JmapURIBuilder.baseUri;
 import static org.awaitility.Awaitility.await;
 
-import io.restassured.RestAssured;
-import io.restassured.builder.RequestSpecBuilder;
-import io.restassured.http.ContentType;
-
 import java.net.InetAddress;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
@@ -52,6 +48,10 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import io.restassured.RestAssured;
+import io.restassured.builder.RequestSpecBuilder;
+import io.restassured.http.ContentType;
+
 public class ESReporterTest {
 
     private static final int IMAP_PORT = 1143;

http://git-wip-us.apache.org/repos/asf/james-project/blob/8790fe6a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/TestingConstants.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/TestingConstants.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/TestingConstants.java
index bb9705a..54f10b3 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/TestingConstants.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/TestingConstants.java
@@ -22,9 +22,6 @@ package org.apache.james.jmap;
 import static io.restassured.config.EncoderConfig.encoderConfig;
 import static io.restassured.config.RestAssuredConfig.newConfig;
 
-import io.restassured.builder.RequestSpecBuilder;
-import io.restassured.http.ContentType;
-
 import java.nio.charset.StandardCharsets;
 import java.util.concurrent.TimeUnit;
 
@@ -32,6 +29,9 @@ import org.awaitility.Awaitility;
 import org.awaitility.Duration;
 import org.awaitility.core.ConditionFactory;
 
+import io.restassured.builder.RequestSpecBuilder;
+import io.restassured.http.ContentType;
+
 public interface TestingConstants {
     Duration slowPacedPollInterval = Duration.ONE_HUNDRED_MILLISECONDS;
     Duration ONE_MILLISECOND = new Duration(1, TimeUnit.MILLISECONDS);

http://git-wip-us.apache.org/repos/asf/james-project/blob/8790fe6a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/ForwardIntegrationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/ForwardIntegrationTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/ForwardIntegrationTest.java
index 00264be..fe8cf43 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/ForwardIntegrationTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/ForwardIntegrationTest.java
@@ -39,9 +39,6 @@ import static org.apache.james.jmap.TestingConstants.jmapRequestSpecBuilder;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasSize;
 
-import io.restassured.RestAssured;
-import io.restassured.specification.RequestSpecification;
-
 import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 
@@ -59,6 +56,9 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
+import io.restassured.RestAssured;
+import io.restassured.specification.RequestSpecification;
+
 public abstract class ForwardIntegrationTest {
 
     @Rule

http://git-wip-us.apache.org/repos/asf/james-project/blob/8790fe6a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
index 6cee9b7..4ea84f7 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/test/java/org/apache/james/webadmin/routes/MailRepositoriesRoutesTest.java
@@ -727,7 +727,7 @@ public class MailRepositoriesRoutesTest {
     }
 
     @Test
-    public void retrievingAMailShouldFailWhenUnknown() throws Exception{
+    public void retrievingAMailShouldFailWhenUnknown() throws Exception {
         mailRepositoryStore.create(URL_MY_REPO);
 
         String name = "name";


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[8/8] james-project git commit: Merge remote-tracking branch 'trantienduchn/JAMES-2528'

Posted by ad...@apache.org.
Merge remote-tracking branch 'trantienduchn/JAMES-2528'


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/8bfefda8
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/8bfefda8
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/8bfefda8

Branch: refs/heads/master
Commit: 8bfefda83f1ccf0db8bdecc5dc60d6f5764f747f
Parents: b6dcb51 8790fe6
Author: Antoine Duprat <ad...@linagora.com>
Authored: Thu Aug 23 14:49:47 2018 +0200
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Thu Aug 23 14:49:47 2018 +0200

----------------------------------------------------------------------
 .../java/org/apache/james/ESReporterTest.java   |   8 +-
 server/data/data-jmap/pom.xml                   |  23 +++-
 .../jmap/api/filtering/FilteringManagement.java |  32 ++++++
 .../apache/james/jmap/api/filtering/Rule.java   |  67 ++++++++++++
 .../api/filtering/impl/DefineRulesCommand.java  |  76 +++++++++++++
 .../impl/DefineRulesCommandHandler.java         |  52 +++++++++
 .../impl/EventSourcingFilteringManagement.java  |  69 ++++++++++++
 .../api/filtering/impl/FilteringAggregate.java  |  90 ++++++++++++++++
 .../filtering/impl/FilteringAggregateId.java    |  73 +++++++++++++
 .../jmap/api/filtering/impl/RuleSetDefined.java |  85 +++++++++++++++
 .../api/filtering/FilteringAggregateIdTest.java |  86 +++++++++++++++
 .../filtering/FilteringManagementContract.java  | 107 +++++++++++++++++++
 .../james/jmap/api/filtering/RuleTest.java      |  41 +++++++
 .../filtering/impl/DefineRulesCommandTest.java  |  51 +++++++++
 .../EventSourcingFilteringManagementTest.java   |  32 ++++++
 .../org/apache/james/jmap/TestingConstants.java |   6 +-
 .../integration/ForwardIntegrationTest.java     |   6 +-
 .../routes/MailRepositoriesRoutesTest.java      |   2 +-
 18 files changed, 893 insertions(+), 13 deletions(-)
----------------------------------------------------------------------



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[5/8] james-project git commit: JAMES-2528 adding a test case of removing of existing rules

Posted by ad...@apache.org.
JAMES-2528 adding a test case of removing of existing rules


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/61a1164c
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/61a1164c
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/61a1164c

Branch: refs/heads/master
Commit: 61a1164c1fef74b8d1000f7388a0f2f9f7d03adf
Parents: 58f0f80
Author: Matthieu Baechler <ma...@apache.org>
Authored: Wed Aug 22 16:16:40 2018 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Thu Aug 23 14:30:37 2018 +0200

----------------------------------------------------------------------
 .../jmap/api/filtering/FilteringManagementContract.java     | 9 +++++++++
 1 file changed, 9 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/61a1164c/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
----------------------------------------------------------------------
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
index 98683b8..21718e8 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/filtering/FilteringManagementContract.java
@@ -95,4 +95,13 @@ public interface FilteringManagementContract {
         assertThat(testee.listRulesForUser(user)).containsExactly(RULE_3, RULE_2, RULE_1);
     }
 
+    @Test
+    default void definingEmptyRuleListShouldRemoveExistingRules() {
+        User user = User.fromUsername(BART_SIMPSON_CARTOON);
+        FilteringManagement testee = instanciateFilteringManagement();
+        testee.defineRulesForUser(user, ImmutableList.of(RULE_3, RULE_2, RULE_1));
+        testee.defineRulesForUser(user, ImmutableList.of());
+        assertThat(testee.listRulesForUser(user)).isEmpty();
+    }
+
 }
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org