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 bt...@apache.org on 2018/01/04 08:13:16 UTC

[01/21] james-project git commit: JAMES-2272 Introduce a generic Task

Repository: james-project
Updated Branches:
  refs/heads/master 7875cc08f -> 7d15ef0e6


JAMES-2272 Introduce a generic Task

Migration is a Task


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

Branch: refs/heads/master
Commit: 3f26590127a811c578104816d4b12937322a0c48
Parents: 7875cc0
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 11:14:01 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:00:42 2018 +0700

----------------------------------------------------------------------
 backends-common/cassandra/pom.xml               |  4 ++
 .../backends/cassandra/migration/Migration.java | 26 ++++++++++
 mailbox/cassandra/pom.xml                       |  4 ++
 .../migration/AttachmentMessageIdCreation.java  | 18 ++++---
 .../mail/migration/AttachmentV2Migration.java   | 13 ++---
 .../cassandra/mail/migration/Migration.java     | 43 ----------------
 .../AttachmentMessageIdCreationTest.java        | 11 ++--
 .../migration/AttachmentV2MigrationTest.java    | 15 +++---
 pom.xml                                         |  5 ++
 .../modules/server/CassandraRoutesModule.java   |  4 +-
 server/pom.xml                                  |  1 +
 .../service/CassandraMigrationServiceTest.java  | 12 ++---
 server/task/pom.xml                             | 54 ++++++++++++++++++++
 .../main/java/org/apache/james/task/Task.java   | 44 ++++++++++++++++
 .../java/org/apache/james/task/TaskTest.java    | 52 +++++++++++++++++++
 15 files changed, 229 insertions(+), 77 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/backends-common/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/pom.xml b/backends-common/cassandra/pom.xml
index 66d3bb3..36aa204 100644
--- a/backends-common/cassandra/pom.xml
+++ b/backends-common/cassandra/pom.xml
@@ -37,6 +37,10 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>james-server-task</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>james-server-util-java8</artifactId>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/Migration.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/Migration.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/Migration.java
new file mode 100644
index 0000000..b4f15f4
--- /dev/null
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/Migration.java
@@ -0,0 +1,26 @@
+/****************************************************************
+ * 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.backends.cassandra.migration;
+
+import org.apache.james.task.Task;
+
+public interface Migration extends Task {
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/mailbox/cassandra/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/pom.xml b/mailbox/cassandra/pom.xml
index 73b5d45..5bffe2b 100644
--- a/mailbox/cassandra/pom.xml
+++ b/mailbox/cassandra/pom.xml
@@ -64,6 +64,10 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>james-server-task</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>james-server-util</artifactId>
             <scope>test</scope>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
index adcc1ff..37e8358 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
@@ -21,6 +21,7 @@ package org.apache.james.mailbox.cassandra.mail.migration;
 
 import javax.inject.Inject;
 
+import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO.MessageIdAttachmentIds;
@@ -40,27 +41,28 @@ public class AttachmentMessageIdCreation implements Migration {
     }
 
     @Override
-    public MigrationResult run() {
+    public Result run() {
         try {
             return cassandraMessageDAO.retrieveAllMessageIdAttachmentIds()
                 .join()
                 .map(this::createIndex)
-                .reduce(MigrationResult.COMPLETED, Migration::combine);
+                .reduce(Result.COMPLETED, Migration::combine);
         } catch (Exception e) {
             LOGGER.error("Error while creation attachmentId -> messageIds index", e);
-            return MigrationResult.PARTIAL;
+            return Result.PARTIAL;
         }
     }
 
-    private MigrationResult createIndex(MessageIdAttachmentIds message) {
+    private Result createIndex(MessageIdAttachmentIds message) {
         try {
             message.getAttachmentId()
-                .stream()
-                .forEach(attachmentId -> attachmentMessageIdDAO.storeAttachmentForMessageId(attachmentId, message.getMessageId()).join());
-            return MigrationResult.COMPLETED;
+                .forEach(attachmentId -> attachmentMessageIdDAO
+                    .storeAttachmentForMessageId(attachmentId, message.getMessageId())
+                    .join());
+            return Result.COMPLETED;
         } catch (Exception e) {
             LOGGER.error("Error while creation attachmentId -> messageIds index", e);
-            return MigrationResult.PARTIAL;
+            return Result.PARTIAL;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
index 8290deb..ca5c116 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
@@ -21,6 +21,7 @@ package org.apache.james.mailbox.cassandra.mail.migration;
 
 import javax.inject.Inject;
 
+import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraBlobsDAO;
@@ -44,28 +45,28 @@ public class AttachmentV2Migration implements Migration {
     }
 
     @Override
-    public MigrationResult run() {
+    public Result run() {
         try {
             return attachmentDAOV1.retrieveAll()
                 .map(this::migrateAttachment)
-                .reduce(MigrationResult.COMPLETED, Migration::combine);
+                .reduce(Result.COMPLETED, Migration::combine);
         } catch (Exception e) {
             LOGGER.error("Error while performing attachmentDAO V2 migration", e);
-            return MigrationResult.PARTIAL;
+            return Result.PARTIAL;
         }
     }
 
-    private MigrationResult migrateAttachment(Attachment attachment) {
+    private Result migrateAttachment(Attachment attachment) {
         try {
             blobsDAO.save(attachment.getBytes())
                 .thenApply(blobId -> CassandraAttachmentDAOV2.from(attachment, blobId))
                 .thenCompose(attachmentDAOV2::storeAttachment)
                 .thenCompose(any -> attachmentDAOV1.deleteAttachment(attachment.getAttachmentId()))
                 .join();
-            return MigrationResult.COMPLETED;
+            return Result.COMPLETED;
         } catch (Exception e) {
             LOGGER.error("Error while performing attachmentDAO V2 migration", e);
-            return MigrationResult.PARTIAL;
+            return Result.PARTIAL;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/Migration.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/Migration.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/Migration.java
deleted file mode 100644
index 247c72a..0000000
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/Migration.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.mailbox.cassandra.mail.migration;
-
-public interface Migration {
-
-    enum MigrationResult {
-        COMPLETED,
-        PARTIAL
-    }
-
-    static MigrationResult combine(MigrationResult result1, MigrationResult result2) {
-        if (result1 == MigrationResult.COMPLETED
-            && result2 == MigrationResult.COMPLETED) {
-            return MigrationResult.COMPLETED;
-        }
-        return MigrationResult.PARTIAL;
-    }
-
-    /**
-     * Runs the migration
-     *
-     * @return Return true if fully migrated. Returns false otherwise.
-     */
-    MigrationResult run();
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreationTest.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreationTest.java
index e333368..b4ec37e 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreationTest.java
@@ -37,6 +37,7 @@ import javax.mail.util.SharedByteArrayInputStream;
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.DockerCassandraRule;
 import org.apache.james.backends.cassandra.init.CassandraModuleComposite;
+import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
@@ -99,7 +100,7 @@ public class AttachmentMessageIdCreationTest {
     @Test
     public void emptyMigrationShouldSucceed() {
         assertThat(migration.run())
-            .isEqualTo(Migration.MigrationResult.COMPLETED);
+            .isEqualTo(Migration.Result.COMPLETED);
     }
 
     @Test
@@ -110,7 +111,7 @@ public class AttachmentMessageIdCreationTest {
         cassandraMessageDAO.save(message).join();
 
         assertThat(migration.run())
-            .isEqualTo(Migration.MigrationResult.COMPLETED);
+            .isEqualTo(Migration.Result.COMPLETED);
     }
 
     @Test
@@ -121,7 +122,7 @@ public class AttachmentMessageIdCreationTest {
         cassandraMessageDAO.save(message).join();
 
         assertThat(migration.run())
-            .isEqualTo(Migration.MigrationResult.COMPLETED);
+            .isEqualTo(Migration.Result.COMPLETED);
     }
 
     @Test
@@ -145,7 +146,7 @@ public class AttachmentMessageIdCreationTest {
 
         when(cassandraMessageDAO.retrieveAllMessageIdAttachmentIds()).thenThrow(new RuntimeException());
 
-        assertThat(migration.run()).isEqualTo(Migration.MigrationResult.PARTIAL);
+        assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }
 
     @Test
@@ -162,7 +163,7 @@ public class AttachmentMessageIdCreationTest {
         when(attachmentMessageIdDAO.storeAttachmentForMessageId(any(AttachmentId.class), any(MessageId.class)))
             .thenThrow(new RuntimeException());
 
-        assertThat(migration.run()).isEqualTo(Migration.MigrationResult.PARTIAL);
+        assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }
 
     private SimpleMailboxMessage createMessage(MessageId messageId, Collection<MessageAttachment> attachments) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/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 1b92747..0f456ac 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
@@ -32,6 +32,7 @@ import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.DockerCassandraRule;
 import org.apache.james.backends.cassandra.init.CassandraConfiguration;
 import org.apache.james.backends.cassandra.init.CassandraModuleComposite;
+import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.mailbox.cassandra.ids.BlobId;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAO;
@@ -91,7 +92,7 @@ public class AttachmentV2MigrationTest {
     @Test
     public void emptyMigrationShouldSucceed() {
         assertThat(migration.run())
-            .isEqualTo(Migration.MigrationResult.COMPLETED);
+            .isEqualTo(Migration.Result.COMPLETED);
     }
 
     @Test
@@ -100,7 +101,7 @@ public class AttachmentV2MigrationTest {
         attachmentDAO.storeAttachment(attachment2).join();
 
         assertThat(migration.run())
-            .isEqualTo(Migration.MigrationResult.COMPLETED);
+            .isEqualTo(Migration.Result.COMPLETED);
     }
 
     @Test
@@ -142,7 +143,7 @@ public class AttachmentV2MigrationTest {
 
         when(attachmentDAO.retrieveAll()).thenThrow(new RuntimeException());
 
-        assertThat(migration.run()).isEqualTo(Migration.MigrationResult.PARTIAL);
+        assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }
 
     @Test
@@ -157,7 +158,7 @@ public class AttachmentV2MigrationTest {
             attachment2));
         when(blobsDAO.save(any())).thenThrow(new RuntimeException());
 
-        assertThat(migration.run()).isEqualTo(Migration.MigrationResult.PARTIAL);
+        assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }
 
     @Test
@@ -176,7 +177,7 @@ public class AttachmentV2MigrationTest {
             .thenReturn(CompletableFuture.completedFuture(BlobId.forPayload(attachment2.getBytes())));
         when(attachmentDAOV2.storeAttachment(any())).thenThrow(new RuntimeException());
 
-        assertThat(migration.run()).isEqualTo(Migration.MigrationResult.PARTIAL);
+        assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }
 
     @Test
@@ -196,7 +197,7 @@ public class AttachmentV2MigrationTest {
         when(attachmentDAOV2.storeAttachment(any())).thenReturn(CompletableFuture.completedFuture(null));
         when(attachmentDAO.deleteAttachment(any())).thenThrow(new RuntimeException());
 
-        assertThat(migration.run()).isEqualTo(Migration.MigrationResult.PARTIAL);
+        assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }
 
     @Test
@@ -216,7 +217,7 @@ public class AttachmentV2MigrationTest {
         when(attachmentDAOV2.storeAttachment(any())).thenReturn(CompletableFuture.completedFuture(null));
         when(attachmentDAO.deleteAttachment(any())).thenReturn(CompletableFuture.completedFuture(null));
 
-        assertThat(migration.run()).isEqualTo(Migration.MigrationResult.PARTIAL);
+        assertThat(migration.run()).isEqualTo(Migration.Result.PARTIAL);
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 8956ad0..fdd34c0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1316,6 +1316,11 @@
             </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
+                <artifactId>james-server-task</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
                 <artifactId>james-server-util</artifactId>
                 <version>${project.version}</version>
             </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java b/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
index ae2340f..6fe2792 100644
--- a/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
+++ b/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
@@ -19,10 +19,10 @@
 
 package org.apache.james.modules.server;
 
+import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.mailbox.cassandra.mail.migration.AttachmentMessageIdCreation;
 import org.apache.james.mailbox.cassandra.mail.migration.AttachmentV2Migration;
-import org.apache.james.mailbox.cassandra.mail.migration.Migration;
 import org.apache.james.webadmin.Routes;
 import org.apache.james.webadmin.routes.CassandraMigrationRoutes;
 import org.apache.james.webadmin.service.CassandraMigrationService;
@@ -47,7 +47,7 @@ public class CassandraRoutesModule extends AbstractModule {
         routesMultibinder.addBinding().to(CassandraMigrationRoutes.class);
 
         MapBinder<Integer, Migration> allMigrationClazzBinder = MapBinder.newMapBinder(binder(), Integer.class, Migration.class);
-        allMigrationClazzBinder.addBinding(FROM_V2_TO_V3).toInstance(() -> Migration.MigrationResult.COMPLETED);
+        allMigrationClazzBinder.addBinding(FROM_V2_TO_V3).toInstance(() -> Migration.Result.COMPLETED);
         allMigrationClazzBinder.addBinding(FROM_V3_TO_V4).to(AttachmentV2Migration.class);
         allMigrationClazzBinder.addBinding(FROM_V4_TO_V5).to(AttachmentMessageIdCreation.class);
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/server/pom.xml
----------------------------------------------------------------------
diff --git a/server/pom.xml b/server/pom.xml
index cff65bb..3414224 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -98,6 +98,7 @@
         <module>queue/queue-file</module>
         <module>queue/queue-jms</module>
 
+        <module>task</module>
         <module>testing</module>
     </modules>
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/service/CassandraMigrationServiceTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/service/CassandraMigrationServiceTest.java b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/service/CassandraMigrationServiceTest.java
index 677f5d8..0e7496f 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/service/CassandraMigrationServiceTest.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/service/CassandraMigrationServiceTest.java
@@ -38,8 +38,8 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.commons.lang.NotImplementedException;
+import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
-import org.apache.james.mailbox.cassandra.mail.migration.Migration;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -66,7 +66,7 @@ public class CassandraMigrationServiceTest {
     public void setUp() throws Exception {
         schemaVersionDAO = mock(CassandraSchemaVersionDAO.class);
         successfulMigration = mock(Migration.class);
-        when(successfulMigration.run()).thenReturn(Migration.MigrationResult.COMPLETED);
+        when(successfulMigration.run()).thenReturn(Migration.Result.COMPLETED);
         Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
             .put(OLDER_VERSION, successfulMigration)
             .put(CURRENT_VERSION, successfulMigration)
@@ -167,7 +167,7 @@ public class CassandraMigrationServiceTest {
         Migration wait1SecondMigration = mock(Migration.class);
         doAnswer(invocation -> {
             Thread.sleep(1000);
-            return Migration.MigrationResult.COMPLETED;
+            return Migration.Result.COMPLETED;
         }).when(wait1SecondMigration).run();
         Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
             .put(OLDER_VERSION, wait1SecondMigration)
@@ -201,7 +201,7 @@ public class CassandraMigrationServiceTest {
     @Test
     public void partialMigrationShouldThrow() throws Exception {
         Migration migration1 = mock(Migration.class);
-        when(migration1.run()).thenReturn(Migration.MigrationResult.PARTIAL);
+        when(migration1.run()).thenReturn(Migration.Result.PARTIAL);
         Migration migration2 = successfulMigration;
 
         Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
@@ -218,9 +218,9 @@ public class CassandraMigrationServiceTest {
     @Test
     public void partialMigrationShouldAbortMigrations() throws Exception {
         Migration migration1 = mock(Migration.class);
-        when(migration1.run()).thenReturn(Migration.MigrationResult.PARTIAL);
+        when(migration1.run()).thenReturn(Migration.Result.PARTIAL);
         Migration migration2 = mock(Migration.class);
-        when(migration2.run()).thenReturn(Migration.MigrationResult.COMPLETED);
+        when(migration2.run()).thenReturn(Migration.Result.COMPLETED);
 
         Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
             .put(OLDER_VERSION, migration1)

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/server/task/pom.xml
----------------------------------------------------------------------
diff --git a/server/task/pom.xml b/server/task/pom.xml
new file mode 100644
index 0000000..96a049d
--- /dev/null
+++ b/server/task/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>james-server</artifactId>
+        <groupId>org.apache.james</groupId>
+        <version>3.1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>james-server-task</artifactId>
+    <name>Apache James :: Server :: Task</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>james-server-util-java8</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>nl.jqno.equalsverifier</groupId>
+            <artifactId>equalsverifier</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/server/task/src/main/java/org/apache/james/task/Task.java
----------------------------------------------------------------------
diff --git a/server/task/src/main/java/org/apache/james/task/Task.java b/server/task/src/main/java/org/apache/james/task/Task.java
new file mode 100644
index 0000000..87ce233
--- /dev/null
+++ b/server/task/src/main/java/org/apache/james/task/Task.java
@@ -0,0 +1,44 @@
+/****************************************************************
+ * 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.task;
+
+public interface Task {
+
+    enum Result {
+        COMPLETED,
+        PARTIAL
+    }
+
+    static Result combine(Result result1, Result result2) {
+        if (result1 == Result.COMPLETED
+            && result2 == Result.COMPLETED) {
+            return Result.COMPLETED;
+        }
+        return Result.PARTIAL;
+    }
+
+    /**
+     * Runs the migration
+     *
+     * @return Return true if fully migrated. Returns false otherwise.
+     */
+    Result run();
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/3f265901/server/task/src/test/java/org/apache/james/task/TaskTest.java
----------------------------------------------------------------------
diff --git a/server/task/src/test/java/org/apache/james/task/TaskTest.java b/server/task/src/test/java/org/apache/james/task/TaskTest.java
new file mode 100644
index 0000000..55ec2f4
--- /dev/null
+++ b/server/task/src/test/java/org/apache/james/task/TaskTest.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.task;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Test;
+
+public class TaskTest {
+
+    @Test
+    public void combineShouldReturnCompletedWhenBothCompleted() {
+        assertThat(Task.combine(Task.Result.COMPLETED, Task.Result.COMPLETED))
+            .isEqualTo(Task.Result.COMPLETED);
+    }
+
+    @Test
+    public void combineShouldReturnPartialWhenPartialLeft() {
+        assertThat(Task.combine(Task.Result.PARTIAL, Task.Result.COMPLETED))
+            .isEqualTo(Task.Result.PARTIAL);
+    }
+
+    @Test
+    public void combineShouldReturnPartialWhenPartialRight() {
+        assertThat(Task.combine(Task.Result.COMPLETED, Task.Result.PARTIAL))
+            .isEqualTo(Task.Result.PARTIAL);
+    }
+
+    @Test
+    public void combineShouldReturnPartialWhenBothPartial() {
+        assertThat(Task.combine(Task.Result.PARTIAL, Task.Result.PARTIAL))
+            .isEqualTo(Task.Result.PARTIAL);
+    }
+
+}
\ 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


[14/21] james-project git commit: JAMES-2274 Packaging generation is product specific

Posted by bt...@apache.org.
JAMES-2274 Packaging generation is product specific


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

Branch: refs/heads/master
Commit: 64d2d19b0b2777ac3db611468261947d6d4aabca
Parents: e4af1a8
Author: benwa <bt...@linagora.com>
Authored: Thu Dec 28 10:56:47 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:12:47 2018 +0700

----------------------------------------------------------------------
 README.adoc                                     |   2 +-
 dockerfiles/packaging/Dockerfile                |  24 ----
 .../packaging/guice/cassandra/Dockerfile        |  24 ++++
 .../packaging/guice/cassandra/james.postinst    |   6 +
 .../guice/cassandra/james.rpm.postinst          |   8 ++
 .../guice/cassandra/james.rpm.postremove        |   7 +
 .../guice/cassandra/james.rpm.postupgrade       |   5 +
 .../packaging/guice/cassandra/james.service     |  34 +++++
 .../packaging/guice/cassandra/package.sh        |  61 ++++++++
 .../etc/james/templates/cassandra.properties    |   6 +
 .../package/etc/james/templates/dnsservice.xml  |  29 ++++
 .../package/etc/james/templates/domainlist.xml  |  28 ++++
 .../james/templates/elasticsearch.properties    |  42 ++++++
 .../package/etc/james/templates/imapserver.xml  |  54 +++++++
 .../package/etc/james/templates/jmap.properties |  13 ++
 .../package/etc/james/templates/jmx.properties  |  28 ++++
 .../package/etc/james/templates/jwt_publickey   |   3 +
 .../package/etc/james/templates/lmtpserver.xml  |  41 ++++++
 .../package/etc/james/templates/logback.xml     |  30 ++++
 .../etc/james/templates/mailetcontainer.xml     | 144 +++++++++++++++++++
 .../etc/james/templates/mailrepositorystore.xml |  34 +++++
 .../etc/james/templates/managesieveserver.xml   |  65 +++++++++
 .../package/etc/james/templates/pop3server.xml  |  42 ++++++
 .../package/etc/james/templates/quota.xml       |  53 +++++++
 .../james/templates/recipientrewritetable.xml   |  26 ++++
 .../package/etc/james/templates/smtpserver.xml  | 105 ++++++++++++++
 .../etc/james/templates/usersrepository.xml     |  26 ++++
 .../etc/james/templates/webadmin.properties     |  41 ++++++
 .../guice/cassandra/package/usr/lib/.gitkeep    |   0
 .../cassandra/package/usr/share/james/.gitkeep  |   0
 .../cassandra/package/var/lib/james/.gitkeep    |   0
 .../cassandra/package/var/log/james/.gitkeep    |   0
 dockerfiles/packaging/james.postinst            |   6 -
 dockerfiles/packaging/james.rpm.postinst        |   8 --
 dockerfiles/packaging/james.rpm.postremove      |   7 -
 dockerfiles/packaging/james.rpm.postupgrade     |   5 -
 dockerfiles/packaging/james.service             |  34 -----
 dockerfiles/packaging/package.sh                |  61 --------
 .../etc/james/templates/cassandra.properties    |   6 -
 .../package/etc/james/templates/dnsservice.xml  |  29 ----
 .../package/etc/james/templates/domainlist.xml  |  28 ----
 .../james/templates/elasticsearch.properties    |  42 ------
 .../package/etc/james/templates/imapserver.xml  |  54 -------
 .../package/etc/james/templates/jmap.properties |  13 --
 .../package/etc/james/templates/jmx.properties  |  28 ----
 .../package/etc/james/templates/jwt_publickey   |   3 -
 .../package/etc/james/templates/lmtpserver.xml  |  41 ------
 .../package/etc/james/templates/logback.xml     |  30 ----
 .../etc/james/templates/mailetcontainer.xml     | 144 -------------------
 .../etc/james/templates/mailrepositorystore.xml |  34 -----
 .../etc/james/templates/managesieveserver.xml   |  65 ---------
 .../package/etc/james/templates/pop3server.xml  |  42 ------
 .../package/etc/james/templates/quota.xml       |  53 -------
 .../james/templates/recipientrewritetable.xml   |  26 ----
 .../package/etc/james/templates/smtpserver.xml  | 105 --------------
 .../etc/james/templates/usersrepository.xml     |  26 ----
 .../etc/james/templates/webadmin.properties     |  41 ------
 dockerfiles/packaging/package/usr/lib/.gitkeep  |   0
 .../packaging/package/usr/share/james/.gitkeep  |   0
 .../packaging/package/var/lib/james/.gitkeep    |   0
 .../packaging/package/var/log/james/.gitkeep    |   0
 61 files changed, 956 insertions(+), 956 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/README.adoc
----------------------------------------------------------------------
diff --git a/README.adoc b/README.adoc
index 321cff8..3df60ec 100644
--- a/README.adoc
+++ b/README.adoc
@@ -357,7 +357,7 @@ You can generate a deb package and an RPM package for James by using the followi
 
 First step, you have to build the Docker image used to generate the package
 
-    $ docker build -t build-james-packages --build-arg RELEASE=3.0-beta6 --build-arg ITERATION=1 dockerfiles/packaging/
+    $ docker build -t build-james-packages --build-arg RELEASE=3.0-beta6 --build-arg ITERATION=1 dockerfiles/packaging/guice/cassandra
 
 Where:
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/Dockerfile
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/Dockerfile b/dockerfiles/packaging/Dockerfile
deleted file mode 100644
index eed4b0f..0000000
--- a/dockerfiles/packaging/Dockerfile
+++ /dev/null
@@ -1,24 +0,0 @@
-FROM linagora/james-project:latest as source
-
-FROM debian:8.1
-
-RUN apt-get update
-RUN apt-get install -y ruby-dev ruby build-essential
-RUN gem install fpm
-RUN apt-get install -y rpm
-
-ADD . /packages
-
-COPY james.service /packages/package/usr/share/james/
-COPY --from=source /root/*.jar /packages/package/usr/share/james/
-COPY --from=source /root/james-server-cassandra-guice.lib/ /packages/package/usr/share/james/james-server-cassandra-guice.lib/
-COPY --from=source /root/james-server-cli.lib/ /packages/package/usr/share/james/james-server-cli.lib/
-
-ARG RELEASE
-ENV RELEASE $RELEASE
-ARG ITERATION
-ENV ITERATION $ITERATION
-
-WORKDIR /packages
-
-ENTRYPOINT [ "sh", "-c", "/packages/package.sh $RELEASE $ITERATION" ]

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/Dockerfile
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/Dockerfile b/dockerfiles/packaging/guice/cassandra/Dockerfile
new file mode 100644
index 0000000..eed4b0f
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/Dockerfile
@@ -0,0 +1,24 @@
+FROM linagora/james-project:latest as source
+
+FROM debian:8.1
+
+RUN apt-get update
+RUN apt-get install -y ruby-dev ruby build-essential
+RUN gem install fpm
+RUN apt-get install -y rpm
+
+ADD . /packages
+
+COPY james.service /packages/package/usr/share/james/
+COPY --from=source /root/*.jar /packages/package/usr/share/james/
+COPY --from=source /root/james-server-cassandra-guice.lib/ /packages/package/usr/share/james/james-server-cassandra-guice.lib/
+COPY --from=source /root/james-server-cli.lib/ /packages/package/usr/share/james/james-server-cli.lib/
+
+ARG RELEASE
+ENV RELEASE $RELEASE
+ARG ITERATION
+ENV ITERATION $ITERATION
+
+WORKDIR /packages
+
+ENTRYPOINT [ "sh", "-c", "/packages/package.sh $RELEASE $ITERATION" ]

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/james.postinst
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/james.postinst b/dockerfiles/packaging/guice/cassandra/james.postinst
new file mode 100644
index 0000000..82306a7
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/james.postinst
@@ -0,0 +1,6 @@
+#! /bin/sh -e
+
+ln -s /etc/james /var/lib/james/conf
+
+systemctl enable james
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/james.rpm.postinst
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/james.rpm.postinst b/dockerfiles/packaging/guice/cassandra/james.rpm.postinst
new file mode 100644
index 0000000..447b4c1
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/james.rpm.postinst
@@ -0,0 +1,8 @@
+#! /bin/sh -e
+ 
+ln -s /etc/james /var/lib/james/conf
+
+#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
+cp /usr/share/james/james.service /etc/systemd/system/
+systemctl enable james
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/james.rpm.postremove
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/james.rpm.postremove b/dockerfiles/packaging/guice/cassandra/james.rpm.postremove
new file mode 100644
index 0000000..d70a3ed
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/james.rpm.postremove
@@ -0,0 +1,7 @@
+#! /bin/sh -e
+ 
+#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
+systemctl stop james
+systemctl disable james
+rm /etc/systemd/system/james.service
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/james.rpm.postupgrade
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/james.rpm.postupgrade b/dockerfiles/packaging/guice/cassandra/james.rpm.postupgrade
new file mode 100644
index 0000000..8e2c81c
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/james.rpm.postupgrade
@@ -0,0 +1,5 @@
+#! /bin/sh -e
+ 
+#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
+systemctl try-restart james
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/james.service
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/james.service b/dockerfiles/packaging/guice/cassandra/james.service
new file mode 100644
index 0000000..2c55df6
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/james.service
@@ -0,0 +1,34 @@
+[Unit]
+Description=James stands for Java Apache Mail Enterprise Server! It has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.
+Documentation=http://james.apache.org
+Wants=network-online.target cassandra.service elasticsearch.service
+After=network-online.target cassandra.service elasticsearch.service
+
+[Service]
+Environment=WORKING_DIRECTORY=/var/lib/james
+Environment=XMX=1024m
+
+User=root
+Group=root
+
+ExecStart=/usr/lib/jvm/java-8-openjdk-amd64/bin/java -Dworking.directory=${WORKING_DIRECTORY} -Xmx${XMX} -Dlogback.configurationFile=/etc/james/logback.xml -jar /usr/share/james/james-server.jar 
+
+StandardOutput=journal
+StandardError=inherit
+
+# Specifies the maximum number of bytes of memory that may be locked into RAM
+# Set to "infinity" if you use the 'bootstrap.mlockall: true' option
+# in elasticsearch.yml and 'MAX_LOCKED_MEMORY=unlimited' in /etc/default/elasticsearch
+#LimitMEMLOCK=infinity
+
+# SIGTERM signal is used to stop the Java process
+KillSignal=SIGTERM
+
+# Java process is never killed
+SendSIGKILL=no
+
+# When a JVM receives a SIGTERM signal it exits with code 143
+SuccessExitStatus=143
+
+[Install]
+WantedBy=multi-user.target

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package.sh
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package.sh b/dockerfiles/packaging/guice/cassandra/package.sh
new file mode 100755
index 0000000..ce89168
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package.sh
@@ -0,0 +1,61 @@
+#!/bin/sh -e
+
+printUsage() {
+   echo "Usage : "
+   echo "./package.sh RELEASE ITERATION"
+   echo "    RELEASE  : The release to be generated."
+   echo "    ITERATION: The iteration to give to the package."
+   exit 1
+}
+
+if [ "$#" -ne 2 ]; then
+    printUsage
+fi
+
+RELEASE=$1
+ITERATION=$2
+
+fpm -s dir -t deb \
+ -n james \
+ -v $RELEASE \
+ -a x86_64 \
+ -d openjdk-8-jre \
+ -C package \
+ --deb-systemd james.service \
+ --after-install james.postinst \
+ --provides mail-transport-agent \
+ --provides default-mta \
+ --iteration $ITERATION \
+ --license http://www.apache.org/licenses/LICENSE-2.0 \
+ --description "$(printf "James stands for Java Apache Mail Enterprise Server!\nIt has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.")" \
+ --vendor "Apache" \
+ --maintainer "Apache" \
+ --url http://james.apache.org/ \
+ --category web \
+ .
+
+#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
+cp james.service.rhel package/usr/share/james/james.service
+
+fpm -s dir -t rpm \
+ -n james \
+ -v $RELEASE \
+ -a x86_64 \
+ -d java-1.8.0-openjdk-headless \
+ -C package \
+ --after-install james.rpm.postinst \
+ --after-upgrade james.rpm.postupgrade \
+ --after-remove james.rpm.postremove \
+ --provides mail-transport-agent \
+ --provides default-mta \
+ --iteration $ITERATION \
+ --license http://www.apache.org/licenses/LICENSE-2.0 \
+ --description "$(printf "James stands for Java Apache Mail Enterprise Server!\nIt has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.")" \
+ --vendor "Apache" \
+ --maintainer "Apache" \
+ --url http://james.apache.org/ \
+ --category web \
+ .
+
+cp /packages/james*.deb /result/
+cp /packages/james*.rpm /result/

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/cassandra.properties
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/cassandra.properties b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/cassandra.properties
new file mode 100644
index 0000000..426a35c
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/cassandra.properties
@@ -0,0 +1,6 @@
+# Configuration file for cassandra mailbox
+cassandra.nodes=127.0.0.1
+cassandra.keyspace=apache_james
+cassandra.replication.factor=1
+cassandra.retryConnection.maxRetries=10
+cassandra.retryConnection.minDelay=5000

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/dnsservice.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/dnsservice.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/dnsservice.xml
new file mode 100644
index 0000000..0978a00
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/dnsservice.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one   
+  or more contributor license agreements.  See the NOTICE file 
+  distributed with this work for additional information        
+  regarding copyright ownership.  The ASF licenses this file   
+  to you under the Apache License, Version 2.0 (the            
+  "License"); you may not use this file except in compliance   
+  with the License.  You may obtain a copy of the License at   
+                                                               
+    http://www.apache.org/licenses/LICENSE-2.0                 
+                                                               
+  Unless required by applicable law or agreed to in writing,   
+  software distributed under the License is distributed on an  
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
+  KIND, either express or implied.  See the License for the    
+  specific language governing permissions and limitations      
+  under the License.                                           
+ -->
+
+<dnsservice>
+  <servers>
+    <server>8.8.8.8</server>
+    <server>62.210.16.6</server>
+  </servers>
+  <autodiscover>false</autodiscover>
+  <authoritative>false</authoritative>
+  <maxcachesize>50000</maxcachesize>
+</dnsservice>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/domainlist.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/domainlist.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/domainlist.xml
new file mode 100644
index 0000000..a9e3da7
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/domainlist.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one   
+  or more contributor license agreements.  See the NOTICE file 
+  distributed with this work for additional information        
+  regarding copyright ownership.  The ASF licenses this file   
+  to you under the Apache License, Version 2.0 (the            
+  "License"); you may not use this file except in compliance   
+  with the License.  You may obtain a copy of the License at   
+                                                               
+    http://www.apache.org/licenses/LICENSE-2.0                 
+                                                               
+  Unless required by applicable law or agreed to in writing,   
+  software distributed under the License is distributed on an  
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
+  KIND, either express or implied.  See the License for the    
+  specific language governing permissions and limitations      
+  under the License.                                           
+ -->
+
+<domainlist>
+    <domainnames>
+        <domainname>yourdomain.org</domainname>
+    </domainnames>
+    <autodetect>true</autodetect>
+    <autodetectIP>true</autodetectIP>
+    <defaultDomain>localhost</defaultDomain>
+</domainlist>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/elasticsearch.properties
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/elasticsearch.properties b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/elasticsearch.properties
new file mode 100644
index 0000000..cf1daac
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/elasticsearch.properties
@@ -0,0 +1,42 @@
+#  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.
+
+#  This template file can be used as example for James Server configuration
+#  DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
+
+# Configuration file for ElasticSearch
+
+elasticsearch.masterHost=127.0.0.1
+elasticsearch.port=9300
+
+# You can alternatively provide a list of hosts following this format :
+# elasticsearch.hosts=host1:9300,host2:9300
+
+elasticsearch.nb.shards=1
+elasticsearch.nb.replica=0
+elasticsearch.retryConnection.maxRetries=7
+elasticsearch.retryConnection.minDelay=3000
+# Index or not attachments (default value: true)
+elasticsearch.indexAttachments=true
+
+# Reports for metrics into ElasticSearch
+# Defaults to elasticsearch.masterHost : on which server to publish metrics
+elasticsearch.http.host=elasticsearch
+elasticsearch.http.port=9200
+elasticsearch.metrics.reports.enabled=true
+elasticsearch.metrics.reports.period=30
+elasticsearch.metrics.reports.index=james-metrics

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/imapserver.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/imapserver.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/imapserver.xml
new file mode 100644
index 0000000..8ccb117
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/imapserver.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+
+<imapservers>
+	<imapserver enabled="true">
+		<jmxName>imapserver</jmxName>
+		<bind>0.0.0.0:143</bind>
+		<connectionBacklog>200</connectionBacklog>
+		<tls socketTLS="false" startTLS="true">
+			<!-- To create a new keystore execute:
+            keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
+              -->
+			<keystore>file://conf/keystore</keystore>
+			<secret>james72laBalle</secret>
+			<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+		</tls>
+		<connectionLimit>0</connectionLimit>
+		<connectionLimitPerIP>0</connectionLimitPerIP>
+	</imapserver>
+	<imapserver enabled="true">
+		<jmxName>imapserver-ssl</jmxName>
+		<bind>0.0.0.0:993</bind>
+		<connectionBacklog>200</connectionBacklog>
+		<tls socketTLS="true" startTLS="false">
+			<!-- To create a new keystore execute:
+              keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
+             -->
+			<keystore>file://conf/keystore</keystore>
+			<secret>james72laBalle</secret>
+			<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+		</tls>
+		<connectionLimit>0</connectionLimit>
+		<connectionLimitPerIP>0</connectionLimitPerIP>
+	</imapserver>
+</imapservers>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jmap.properties
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jmap.properties b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jmap.properties
new file mode 100644
index 0000000..6c2f219
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jmap.properties
@@ -0,0 +1,13 @@
+# Configuration file for JMAP
+
+enabled=false
+
+tls.keystoreURL=file://conf/your_keystore
+tls.secret=your_keystore_secret
+
+#
+# If you wish to use OAuth authentication, you should provide a valid JWT public key.
+# The following entry specify the link to the URL of the public key file,
+# which should be a PEM format file.
+#
+jwt.publickeypem.url=file://conf/jwt_publickey

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jmx.properties
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jmx.properties b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jmx.properties
new file mode 100644
index 0000000..a1dbdf8
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jmx.properties
@@ -0,0 +1,28 @@
+#  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.
+#
+
+#  This template file can be used as example for James Server configuration
+#  DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
+
+#  This template file can be used as example for James Server configuration
+#  DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
+
+# See http://james.apache.org/server/3/config.html for usage
+
+jmx.address=127.0.0.1
+jmx.port=9999

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jwt_publickey
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jwt_publickey b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jwt_publickey
new file mode 100644
index 0000000..f00e64b
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/jwt_publickey
@@ -0,0 +1,3 @@
+-----BEGIN PUBLIC KEY-----
+Your JWT public key
+-----END PUBLIC KEY-----

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/lmtpserver.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/lmtpserver.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/lmtpserver.xml
new file mode 100644
index 0000000..ce079b0
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/lmtpserver.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one   
+  or more contributor license agreements.  See the NOTICE file 
+  distributed with this work for additional information        
+  regarding copyright ownership.  The ASF licenses this file   
+  to you under the Apache License, Version 2.0 (the            
+  "License"); you may not use this file except in compliance   
+  with the License.  You may obtain a copy of the License at   
+                                                               
+    http://www.apache.org/licenses/LICENSE-2.0                 
+                                                               
+  Unless required by applicable law or agreed to in writing,   
+  software distributed under the License is distributed on an  
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
+  KIND, either express or implied.  See the License for the    
+  specific language governing permissions and limitations      
+  under the License.                                           
+ -->
+
+<lmtpservers>
+
+    <lmtpserver enabled="false">
+        <jmxName>lmtpserver</jmxName>
+        <!-- LMTP should not be reachable from outside your network so bind it to loopback-->
+        <bind>127.0.0.1:24</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <connectiontimeout>1200</connectiontimeout>
+        <!-- Set the maximum simultaneous incoming connections for this service -->
+        <connectionLimit>0</connectionLimit>
+        <!-- Set the maximum simultaneous incoming connections per IP for this service -->
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <!--  This sets the maximum allowed message size (in kilobytes) for this -->
+        <!--  LMTP service. If unspecified, the value defaults to 0, which means no limit. -->
+        <maxmessagesize>0</maxmessagesize>
+        <handlerchain>
+            <handler class="org.apache.james.lmtpserver.CoreCmdHandlerLoader"/>
+        </handlerchain>
+    </lmtpserver>
+
+</lmtpservers>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/logback.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/logback.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/logback.xml
new file mode 100644
index 0000000..94a639f
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/logback.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+        <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
+                <resetJUL>true</resetJUL>
+        </contextListener>
+
+        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+                <encoder>
+                        <pattern>%d{HH:mm:ss.SSS} %highlight([%-5level]) %logger{15} - %msg%n%rEx</pattern>
+                        <immediateFlush>false</immediateFlush>
+                </encoder>
+        </appender>
+
+        <appender name="LOG_FILE" class="ch.qos.logback.core.FileAppender">
+                <file>/logs/james.log</file>
+                <encoder>
+                        <pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
+                        <immediateFlush>false</immediateFlush>
+                </encoder>
+        </appender>
+
+        <root level="INFO">
+                <appender-ref ref="CONSOLE" />
+                <appender-ref ref="LOG_FILE" />
+        </root>
+
+        <logger name="com.datastax.driver.core.QueryLogger.SLOW" level="DEBUG" />
+
+</configuration>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/mailetcontainer.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/mailetcontainer.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/mailetcontainer.xml
new file mode 100644
index 0000000..681b966
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/mailetcontainer.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+ -->
+
+<mailetcontainer enableJmx="true">
+
+    <context>
+        <postmaster>postmaster@james.minet.net</postmaster>
+    </context>
+
+    <spooler>
+        <threads>20</threads>
+    </spooler>
+
+    <processors>
+        <processor state="root" enableJmx="true">
+            <mailet match="All" class="PostmasterAlias"/>
+            <mailet match="RelayLimit=30" class="Null"/>
+            <mailet match="All" class="ToProcessor">
+                <processor>transport</processor>
+            </mailet>
+        </processor>
+
+        <processor state="error" enableJmx="true">
+            <mailet match="All" class="MetricsMailet">
+                <metricName>mailetContainerErrors</metricName>
+            </mailet>
+            <mailet match="All" class="Bounce"/>
+            <mailet match="All" class="ToRepository">
+                <repositoryPath>file://var/mail/error/</repositoryPath>
+            </mailet>
+        </processor>
+
+        <processor state="transport" enableJmx="true">
+            <mailet match="SMTPAuthSuccessful" class="SetMimeHeader">
+                <name>X-UserIsAuth</name>
+                <value>true</value>
+            </mailet>
+            <mailet match="HasMailAttribute=org.apache.james.SMIMECheckSignature" class="SetMimeHeader">
+                <name>X-WasSigned</name>
+                <value>true</value>
+            </mailet>
+            <mailet match="All" class="RemoveMimeHeader">
+                <name>bcc</name>
+            </mailet>
+            <mailet match="All" class="RecipientRewriteTable" />
+            <mailet match="RecipientIsLocal" class="org.apache.james.jmap.mailet.VacationMailet"/>
+            <mailet match="RecipientIsLocal" class="Sieve"/>
+            <mailet match="RecipientIsLocal" class="AddDeliveredToHeader"/>
+            <mailet match="RecipientIsLocal" class="LocalDelivery"/>
+            <mailet match="HostIsLocal" class="ToProcessor">
+                <processor>local-address-error</processor>
+                <notice>550 - Requested action not taken: no such user here</notice>
+            </mailet>
+
+            <mailet match="SMTPAuthSuccessful" class="ToProcessor">
+                <processor>relay</processor>
+            </mailet>
+            <mailet match="HasMailAttribute=org.apache.james.jmap.send.MailMetaData.messageId" class="ToProcessor">
+                <processor>relay</processor>
+            </mailet>
+
+            <mailet match="All" class="ToProcessor">
+                <processor>relay-denied</processor>
+            </mailet>
+        </processor>
+
+        <processor state="relay" enableJmx="true">
+            <mailet match="All" class="RemoteDelivery">
+                <outgoingQueue>outgoing</outgoingQueue>
+                <delayTime>5000, 100000, 500000</delayTime>
+                <maxRetries>25</maxRetries>
+                <maxDnsProblemRetries>0</maxDnsProblemRetries>
+                <deliveryThreads>10</deliveryThreads>
+                <sendpartial>true</sendpartial>
+                <bounceProcessor>bounces</bounceProcessor>
+            </mailet>
+        </processor>
+
+        <processor state="spam" enableJmx="true">
+            <mailet match="All" class="MetricsMailet">
+                <metricName>mailetContainerSpam</metricName>
+            </mailet>
+            <mailet match="All" class="ToRepository">
+                <repositoryPath>file://var/mail/spam/</repositoryPath>
+            </mailet>
+        </processor>
+
+        <processor state="local-address-error" enableJmx="true">
+            <mailet match="All" class="MetricsMailet">
+                <metricName>mailetContainerLocalAddressError</metricName>
+            </mailet>
+            <mailet match="All" class="Bounce">
+                <attachment>none</attachment>
+            </mailet>
+            <mailet match="All" class="ToRepository">
+                <repositoryPath>file://var/mail/address-error/</repositoryPath>
+            </mailet>
+        </processor>
+
+        <processor state="relay-denied" enableJmx="true">
+            <mailet match="All" class="MetricsMailet">
+                <metricName>mailetContainerRelayDenied</metricName>
+            </mailet>
+            <mailet match="All" class="Bounce">
+                <attachment>none</attachment>
+            </mailet>
+            <mailet match="All" class="ToRepository">
+                <repositoryPath>file://var/mail/relay-denied/</repositoryPath>
+                <notice>Warning: You are sending an e-mail to a remote server. You must be authenticated to perform such an operation</notice>
+            </mailet>
+        </processor>
+
+        <processor state="bounces" enableJmx="true">
+            <mailet match="All" class="MetricsMailet">
+                <metricName>bounces</metricName>
+            </mailet>
+            <mailet match="All" class="DSNBounce">
+                <passThrough>false</passThrough>
+            </mailet>
+        </processor>
+
+    </processors>
+
+</mailetcontainer>
+
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/mailrepositorystore.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/mailrepositorystore.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/mailrepositorystore.xml
new file mode 100644
index 0000000..acca810
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/mailrepositorystore.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+ -->
+
+<mailrepositorystore>
+    <mailrepositories>
+        <!-- File based repositories.  These repositories store all message data -->
+        <!-- in the file system. -->
+        <mailrepository class="org.apache.james.mailrepository.file.FileMailRepository">
+            <protocols>
+                <protocol>file</protocol>
+            </protocols>
+            <!-- Set if the messages should be listed sorted. False by default -->
+            <config FIFO="false" CACHEKEYS="true"/>
+        </mailrepository>
+    </mailrepositories>
+</mailrepositorystore>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/managesieveserver.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/managesieveserver.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/managesieveserver.xml
new file mode 100644
index 0000000..7b0b85a
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/managesieveserver.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one   
+  or more contributor license agreements.  See the NOTICE file 
+  distributed with this work for additional information        
+  regarding copyright ownership.  The ASF licenses this file   
+  to you under the Apache License, Version 2.0 (the            
+  "License"); you may not use this file except in compliance   
+  with the License.  You may obtain a copy of the License at   
+                                                               
+    http://www.apache.org/licenses/LICENSE-2.0                 
+                                                               
+  Unless required by applicable law or agreed to in writing,   
+  software distributed under the License is distributed on an  
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
+  KIND, either express or implied.  See the License for the    
+  specific language governing permissions and limitations      
+  under the License.                                           
+ -->
+ 
+<!--
+   This template file can be used as example for James Server configuration
+   DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
+-->
+ 
+<!-- See http://james.apache.org/server/3/config.html for usage -->
+
+<managesieveservers>
+
+   <managesieveserver enabled="false">
+
+     <jmxName>managesieveserver</jmxName>
+
+     <bind>0.0.0.0:4190</bind>
+
+     <connectionBacklog>200</connectionBacklog>
+
+     <tls socketTLS="false" startTLS="false">
+       <!-- To create a new keystore execute:
+        keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
+         -->
+       <keystore>file://conf/keystore</keystore>
+       <secret>james72laBalle</secret>
+       <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+       <!-- The algorithm is optional and only needs to be specified when using something other
+        than the Sun JCE provider - You could use IbmX509 with IBM Java runtime. -->
+       <algorithm>SunX509</algorithm>
+     </tls>
+         
+        <!-- connection timeout in secconds -->
+        <connectiontimeout>360</connectiontimeout>
+
+        <!-- Set the maximum simultaneous incoming connections for this service -->
+        <connectionLimit>0</connectionLimit>
+         
+        <!-- Set the maximum simultaneous incoming connections per IP for this service -->
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <maxmessagesize>0</maxmessagesize>
+        <addressBracketsEnforcement>true</addressBracketsEnforcement>
+  
+   </managesieveserver>
+
+</managesieveservers>
+
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/pop3server.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/pop3server.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/pop3server.xml
new file mode 100644
index 0000000..df8fbef
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/pop3server.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one   
+  or more contributor license agreements.  See the NOTICE file 
+  distributed with this work for additional information        
+  regarding copyright ownership.  The ASF licenses this file   
+  to you under the Apache License, Version 2.0 (the            
+  "License"); you may not use this file except in compliance   
+  with the License.  You may obtain a copy of the License at   
+                                                               
+    http://www.apache.org/licenses/LICENSE-2.0                 
+                                                               
+  Unless required by applicable law or agreed to in writing,   
+  software distributed under the License is distributed on an  
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
+  KIND, either express or implied.  See the License for the    
+  specific language governing permissions and limitations      
+  under the License.                                           
+ -->
+
+
+<pop3servers>
+    <pop3server enabled="false">
+        <jmxName>pop3server</jmxName>
+        <bind>0.0.0.0:110</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <tls socketTLS="false" startTLS="false">
+            <!-- To create a new keystore execute:
+                  keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
+             -->
+            <keystore>file://conf/keystore</keystore>
+            <secret>james72laBalle</secret>
+            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+        </tls>
+        <connectiontimeout>1200</connectiontimeout>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <handlerchain>
+            <handler class="org.apache.james.pop3server.core.CoreCmdHandlerLoader"/>
+        </handlerchain>
+    </pop3server>
+</pop3servers>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/quota.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/quota.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/quota.xml
new file mode 100644
index 0000000..70162e0
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/quota.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+ -->
+
+<!--
+   This template file can be used as example for James Server configuration
+   DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
+-->
+
+<!-- See http://james.apache.org/server/3/config.html for usage -->
+
+<!--
+        This configuration file allows you to customize the way quota are handled on this server.
+        You need to rename it in quota.xml so that it gets interpreted by James on startup.
+
+        The different configuration options are detailed here.
+
+        Read RFC-2087 for full details.
+-->
+
+<quota>
+    <quotaRootResolver>
+        <provider>default</provider>
+    </quotaRootResolver>
+    <currentQuotaManager>
+        <provider>cassandra</provider>
+    </currentQuotaManager>
+    <maxQuotaManager>
+        <provider>cassandra</provider>
+    </maxQuotaManager>
+    <quotaManager>
+        <provider>store</provider>
+    </quotaManager>
+    <updates>
+        <provider>event</provider>
+    </updates>
+</quota>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/recipientrewritetable.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/recipientrewritetable.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/recipientrewritetable.xml
new file mode 100644
index 0000000..3d44578
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/recipientrewritetable.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one   
+  or more contributor license agreements.  See the NOTICE file 
+  distributed with this work for additional information        
+  regarding copyright ownership.  The ASF licenses this file   
+  to you under the Apache License, Version 2.0 (the            
+  "License"); you may not use this file except in compliance   
+  with the License.  You may obtain a copy of the License at   
+                                                               
+    http://www.apache.org/licenses/LICENSE-2.0                 
+                                                               
+  Unless required by applicable law or agreed to in writing,   
+  software distributed under the License is distributed on an  
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
+  KIND, either express or implied.  See the License for the    
+  specific language governing permissions and limitations      
+  under the License.                                           
+ -->
+
+<!-- The default table for storing James' RecipientRewriteTable mappings. -->
+<recipientrewritetable>
+  <recursiveMapping>true</recursiveMapping>
+  <mappingLimit>10</mappingLimit>
+</recipientrewritetable>
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/smtpserver.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/smtpserver.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/smtpserver.xml
new file mode 100644
index 0000000..bc609be
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/smtpserver.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+ -->
+
+<smtpservers>
+    <smtpserver enabled="true">
+        <jmxName>smtpserver-global</jmxName>
+        <bind>0.0.0.0:25</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <tls socketTLS="false" startTLS="false">
+            <keystore>file://conf/keystore</keystore>
+            <secret>james72laBalle</secret>
+            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+            <algorithm>SunX509</algorithm>
+        </tls>
+        <connectiontimeout>360</connectiontimeout>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <authRequired>false</authRequired>
+        <authorizedAddresses>0.0.0.0/0</authorizedAddresses>
+        <verifyIdentity>true</verifyIdentity>
+        <maxmessagesize>0</maxmessagesize>
+        <addressBracketsEnforcement>true</addressBracketsEnforcement>
+        <smtpGreeting>JAMES Linagora's SMTP awesome Server</smtpGreeting>
+        <handlerchain>
+            <handler class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
+            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
+        </handlerchain>
+    </smtpserver>
+    <smtpserver enabled="true">
+        <jmxName>smtpserver-TLS</jmxName>
+        <bind>0.0.0.0:465</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <tls socketTLS="true" startTLS="false">
+            <keystore>file://conf/keystore</keystore>
+            <secret>james72laBalle</secret>
+            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+            <algorithm>SunX509</algorithm>
+        </tls>
+        <connectiontimeout>360</connectiontimeout>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <!--
+           Authorize only local users
+        -->
+        <authRequired>true</authRequired>
+        <authorizedAddresses>0.0.0.0/0</authorizedAddresses>
+        <!-- Trust authenticated users -->
+        <verifyIdentity>false</verifyIdentity>
+        <maxmessagesize>0</maxmessagesize>
+        <addressBracketsEnforcement>true</addressBracketsEnforcement>
+        <smtpGreeting>JAMES Linagora's SMTP awesome Server</smtpGreeting>
+        <handlerchain>
+            <handler class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
+            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
+        </handlerchain>
+    </smtpserver>
+    <smtpserver enabled="true">
+        <jmxName>smtpserver-authenticated</jmxName>
+        <bind>0.0.0.0:587</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <tls socketTLS="false" startTLS="true">
+            <keystore>file://conf/keystore</keystore>
+            <secret>james72laBalle</secret>
+            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+            <algorithm>SunX509</algorithm>
+        </tls>
+        <connectiontimeout>360</connectiontimeout>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <!--
+           Authorize only local users
+        -->
+        <authRequired>true</authRequired>
+        <authorizedAddresses>0.0.0.0/0</authorizedAddresses>
+        <!-- Trust authenticated users -->
+        <verifyIdentity>false</verifyIdentity>
+        <maxmessagesize>0</maxmessagesize>
+        <addressBracketsEnforcement>true</addressBracketsEnforcement>
+        <smtpGreeting>JAMES Linagora's SMTP awesome Server</smtpGreeting>
+        <handlerchain>
+            <handler class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
+            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
+        </handlerchain>
+    </smtpserver>
+</smtpservers>
+
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/usersrepository.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/usersrepository.xml b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/usersrepository.xml
new file mode 100644
index 0000000..c745677
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/usersrepository.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one   
+  or more contributor license agreements.  See the NOTICE file 
+  distributed with this work for additional information        
+  regarding copyright ownership.  The ASF licenses this file   
+  to you under the Apache License, Version 2.0 (the            
+  "License"); you may not use this file except in compliance   
+  with the License.  You may obtain a copy of the License at   
+                                                               
+    http://www.apache.org/licenses/LICENSE-2.0                 
+                                                               
+  Unless required by applicable law or agreed to in writing,   
+  software distributed under the License is distributed on an  
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
+  KIND, either express or implied.  See the License for the    
+  specific language governing permissions and limitations      
+  under the License.                                           
+ -->
+
+<usersrepository name="LocalUsers">
+    <algorithm>MD5</algorithm>
+    <enableVirtualHosting>true</enableVirtualHosting>    
+    <enableForwarding>true</enableForwarding>
+</usersrepository>
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/webadmin.properties
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/webadmin.properties b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/webadmin.properties
new file mode 100644
index 0000000..36b6f1e
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/package/etc/james/templates/webadmin.properties
@@ -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.
+
+#  This template file can be used as example for James Server configuration
+#  DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
+
+enabled=true
+port=8000
+host=localhost
+
+# Defaults to false
+https.enabled=false
+
+# Compulsory when enabling HTTPS
+#https.keystore=/path/to/keystore
+#https.password=password
+
+# Optional when enabling HTTPS (self signed)
+#https.trust.keystore
+#https.trust.password
+
+# Defaults to false
+#jwt.enabled=true
+
+# Defaults to false
+#cors.enable=true
+#cors.origin
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/usr/lib/.gitkeep
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/usr/lib/.gitkeep b/dockerfiles/packaging/guice/cassandra/package/usr/lib/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/usr/share/james/.gitkeep
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/usr/share/james/.gitkeep b/dockerfiles/packaging/guice/cassandra/package/usr/share/james/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/var/lib/james/.gitkeep
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/var/lib/james/.gitkeep b/dockerfiles/packaging/guice/cassandra/package/var/lib/james/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/guice/cassandra/package/var/log/james/.gitkeep
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package/var/log/james/.gitkeep b/dockerfiles/packaging/guice/cassandra/package/var/log/james/.gitkeep
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/james.postinst
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/james.postinst b/dockerfiles/packaging/james.postinst
deleted file mode 100644
index 82306a7..0000000
--- a/dockerfiles/packaging/james.postinst
+++ /dev/null
@@ -1,6 +0,0 @@
-#! /bin/sh -e
-
-ln -s /etc/james /var/lib/james/conf
-
-systemctl enable james
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/james.rpm.postinst
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/james.rpm.postinst b/dockerfiles/packaging/james.rpm.postinst
deleted file mode 100644
index 447b4c1..0000000
--- a/dockerfiles/packaging/james.rpm.postinst
+++ /dev/null
@@ -1,8 +0,0 @@
-#! /bin/sh -e
- 
-ln -s /etc/james /var/lib/james/conf
-
-#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
-cp /usr/share/james/james.service /etc/systemd/system/
-systemctl enable james
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/james.rpm.postremove
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/james.rpm.postremove b/dockerfiles/packaging/james.rpm.postremove
deleted file mode 100644
index d70a3ed..0000000
--- a/dockerfiles/packaging/james.rpm.postremove
+++ /dev/null
@@ -1,7 +0,0 @@
-#! /bin/sh -e
- 
-#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
-systemctl stop james
-systemctl disable james
-rm /etc/systemd/system/james.service
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/james.rpm.postupgrade
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/james.rpm.postupgrade b/dockerfiles/packaging/james.rpm.postupgrade
deleted file mode 100644
index 8e2c81c..0000000
--- a/dockerfiles/packaging/james.rpm.postupgrade
+++ /dev/null
@@ -1,5 +0,0 @@
-#! /bin/sh -e
- 
-#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
-systemctl try-restart james
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/james.service
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/james.service b/dockerfiles/packaging/james.service
deleted file mode 100644
index 2c55df6..0000000
--- a/dockerfiles/packaging/james.service
+++ /dev/null
@@ -1,34 +0,0 @@
-[Unit]
-Description=James stands for Java Apache Mail Enterprise Server! It has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.
-Documentation=http://james.apache.org
-Wants=network-online.target cassandra.service elasticsearch.service
-After=network-online.target cassandra.service elasticsearch.service
-
-[Service]
-Environment=WORKING_DIRECTORY=/var/lib/james
-Environment=XMX=1024m
-
-User=root
-Group=root
-
-ExecStart=/usr/lib/jvm/java-8-openjdk-amd64/bin/java -Dworking.directory=${WORKING_DIRECTORY} -Xmx${XMX} -Dlogback.configurationFile=/etc/james/logback.xml -jar /usr/share/james/james-server.jar 
-
-StandardOutput=journal
-StandardError=inherit
-
-# Specifies the maximum number of bytes of memory that may be locked into RAM
-# Set to "infinity" if you use the 'bootstrap.mlockall: true' option
-# in elasticsearch.yml and 'MAX_LOCKED_MEMORY=unlimited' in /etc/default/elasticsearch
-#LimitMEMLOCK=infinity
-
-# SIGTERM signal is used to stop the Java process
-KillSignal=SIGTERM
-
-# Java process is never killed
-SendSIGKILL=no
-
-# When a JVM receives a SIGTERM signal it exits with code 143
-SuccessExitStatus=143
-
-[Install]
-WantedBy=multi-user.target

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package.sh
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package.sh b/dockerfiles/packaging/package.sh
deleted file mode 100755
index ce89168..0000000
--- a/dockerfiles/packaging/package.sh
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/sh -e
-
-printUsage() {
-   echo "Usage : "
-   echo "./package.sh RELEASE ITERATION"
-   echo "    RELEASE  : The release to be generated."
-   echo "    ITERATION: The iteration to give to the package."
-   exit 1
-}
-
-if [ "$#" -ne 2 ]; then
-    printUsage
-fi
-
-RELEASE=$1
-ITERATION=$2
-
-fpm -s dir -t deb \
- -n james \
- -v $RELEASE \
- -a x86_64 \
- -d openjdk-8-jre \
- -C package \
- --deb-systemd james.service \
- --after-install james.postinst \
- --provides mail-transport-agent \
- --provides default-mta \
- --iteration $ITERATION \
- --license http://www.apache.org/licenses/LICENSE-2.0 \
- --description "$(printf "James stands for Java Apache Mail Enterprise Server!\nIt has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.")" \
- --vendor "Apache" \
- --maintainer "Apache" \
- --url http://james.apache.org/ \
- --category web \
- .
-
-#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
-cp james.service.rhel package/usr/share/james/james.service
-
-fpm -s dir -t rpm \
- -n james \
- -v $RELEASE \
- -a x86_64 \
- -d java-1.8.0-openjdk-headless \
- -C package \
- --after-install james.rpm.postinst \
- --after-upgrade james.rpm.postupgrade \
- --after-remove james.rpm.postremove \
- --provides mail-transport-agent \
- --provides default-mta \
- --iteration $ITERATION \
- --license http://www.apache.org/licenses/LICENSE-2.0 \
- --description "$(printf "James stands for Java Apache Mail Enterprise Server!\nIt has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.")" \
- --vendor "Apache" \
- --maintainer "Apache" \
- --url http://james.apache.org/ \
- --category web \
- .
-
-cp /packages/james*.deb /result/
-cp /packages/james*.rpm /result/

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/cassandra.properties
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/cassandra.properties b/dockerfiles/packaging/package/etc/james/templates/cassandra.properties
deleted file mode 100644
index 426a35c..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/cassandra.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-# Configuration file for cassandra mailbox
-cassandra.nodes=127.0.0.1
-cassandra.keyspace=apache_james
-cassandra.replication.factor=1
-cassandra.retryConnection.maxRetries=10
-cassandra.retryConnection.minDelay=5000

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/dnsservice.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/dnsservice.xml b/dockerfiles/packaging/package/etc/james/templates/dnsservice.xml
deleted file mode 100644
index 0978a00..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/dnsservice.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one   
-  or more contributor license agreements.  See the NOTICE file 
-  distributed with this work for additional information        
-  regarding copyright ownership.  The ASF licenses this file   
-  to you under the Apache License, Version 2.0 (the            
-  "License"); you may not use this file except in compliance   
-  with the License.  You may obtain a copy of the License at   
-                                                               
-    http://www.apache.org/licenses/LICENSE-2.0                 
-                                                               
-  Unless required by applicable law or agreed to in writing,   
-  software distributed under the License is distributed on an  
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
-  KIND, either express or implied.  See the License for the    
-  specific language governing permissions and limitations      
-  under the License.                                           
- -->
-
-<dnsservice>
-  <servers>
-    <server>8.8.8.8</server>
-    <server>62.210.16.6</server>
-  </servers>
-  <autodiscover>false</autodiscover>
-  <authoritative>false</authoritative>
-  <maxcachesize>50000</maxcachesize>
-</dnsservice>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/domainlist.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/domainlist.xml b/dockerfiles/packaging/package/etc/james/templates/domainlist.xml
deleted file mode 100644
index a9e3da7..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/domainlist.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one   
-  or more contributor license agreements.  See the NOTICE file 
-  distributed with this work for additional information        
-  regarding copyright ownership.  The ASF licenses this file   
-  to you under the Apache License, Version 2.0 (the            
-  "License"); you may not use this file except in compliance   
-  with the License.  You may obtain a copy of the License at   
-                                                               
-    http://www.apache.org/licenses/LICENSE-2.0                 
-                                                               
-  Unless required by applicable law or agreed to in writing,   
-  software distributed under the License is distributed on an  
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
-  KIND, either express or implied.  See the License for the    
-  specific language governing permissions and limitations      
-  under the License.                                           
- -->
-
-<domainlist>
-    <domainnames>
-        <domainname>yourdomain.org</domainname>
-    </domainnames>
-    <autodetect>true</autodetect>
-    <autodetectIP>true</autodetectIP>
-    <defaultDomain>localhost</defaultDomain>
-</domainlist>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/elasticsearch.properties
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/elasticsearch.properties b/dockerfiles/packaging/package/etc/james/templates/elasticsearch.properties
deleted file mode 100644
index cf1daac..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/elasticsearch.properties
+++ /dev/null
@@ -1,42 +0,0 @@
-#  Licensed to the Apache Software Foundation (ASF) under one
-#  or more contributor license agreements.  See the NOTICE file
-#  distributed with this work for additional information
-#  regarding copyright ownership.  The ASF licenses this file
-#  to you under the Apache License, Version 2.0 (the
-#  "License"); you may not use this file except in compliance
-#  with the License.  You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing,
-#  software distributed under the License is distributed on an
-#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#  KIND, either express or implied.  See the License for the
-#  specific language governing permissions and limitations
-#  under the License.
-
-#  This template file can be used as example for James Server configuration
-#  DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
-
-# Configuration file for ElasticSearch
-
-elasticsearch.masterHost=127.0.0.1
-elasticsearch.port=9300
-
-# You can alternatively provide a list of hosts following this format :
-# elasticsearch.hosts=host1:9300,host2:9300
-
-elasticsearch.nb.shards=1
-elasticsearch.nb.replica=0
-elasticsearch.retryConnection.maxRetries=7
-elasticsearch.retryConnection.minDelay=3000
-# Index or not attachments (default value: true)
-elasticsearch.indexAttachments=true
-
-# Reports for metrics into ElasticSearch
-# Defaults to elasticsearch.masterHost : on which server to publish metrics
-elasticsearch.http.host=elasticsearch
-elasticsearch.http.port=9200
-elasticsearch.metrics.reports.enabled=true
-elasticsearch.metrics.reports.period=30
-elasticsearch.metrics.reports.index=james-metrics

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/imapserver.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/imapserver.xml b/dockerfiles/packaging/package/etc/james/templates/imapserver.xml
deleted file mode 100644
index 8ccb117..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/imapserver.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-
-<imapservers>
-	<imapserver enabled="true">
-		<jmxName>imapserver</jmxName>
-		<bind>0.0.0.0:143</bind>
-		<connectionBacklog>200</connectionBacklog>
-		<tls socketTLS="false" startTLS="true">
-			<!-- To create a new keystore execute:
-            keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
-              -->
-			<keystore>file://conf/keystore</keystore>
-			<secret>james72laBalle</secret>
-			<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
-		</tls>
-		<connectionLimit>0</connectionLimit>
-		<connectionLimitPerIP>0</connectionLimitPerIP>
-	</imapserver>
-	<imapserver enabled="true">
-		<jmxName>imapserver-ssl</jmxName>
-		<bind>0.0.0.0:993</bind>
-		<connectionBacklog>200</connectionBacklog>
-		<tls socketTLS="true" startTLS="false">
-			<!-- To create a new keystore execute:
-              keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
-             -->
-			<keystore>file://conf/keystore</keystore>
-			<secret>james72laBalle</secret>
-			<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
-		</tls>
-		<connectionLimit>0</connectionLimit>
-		<connectionLimitPerIP>0</connectionLimitPerIP>
-	</imapserver>
-</imapservers>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/jmap.properties
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/jmap.properties b/dockerfiles/packaging/package/etc/james/templates/jmap.properties
deleted file mode 100644
index 6c2f219..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/jmap.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-# Configuration file for JMAP
-
-enabled=false
-
-tls.keystoreURL=file://conf/your_keystore
-tls.secret=your_keystore_secret
-
-#
-# If you wish to use OAuth authentication, you should provide a valid JWT public key.
-# The following entry specify the link to the URL of the public key file,
-# which should be a PEM format file.
-#
-jwt.publickeypem.url=file://conf/jwt_publickey

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/jmx.properties
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/jmx.properties b/dockerfiles/packaging/package/etc/james/templates/jmx.properties
deleted file mode 100644
index a1dbdf8..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/jmx.properties
+++ /dev/null
@@ -1,28 +0,0 @@
-#  Licensed to the Apache Software Foundation (ASF) under one
-#  or more contributor license agreements.  See the NOTICE file
-#  distributed with this work for additional information
-#  regarding copyright ownership.  The ASF licenses this file
-#  to you under the Apache License, Version 2.0 (the
-#  "License"); you may not use this file except in compliance
-#  with the License.  You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing,
-#  software distributed under the License is distributed on an
-#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#  KIND, either express or implied.  See the License for the
-#  specific language governing permissions and limitations
-#  under the License.
-#
-
-#  This template file can be used as example for James Server configuration
-#  DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
-
-#  This template file can be used as example for James Server configuration
-#  DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
-
-# See http://james.apache.org/server/3/config.html for usage
-
-jmx.address=127.0.0.1
-jmx.port=9999

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/jwt_publickey
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/jwt_publickey b/dockerfiles/packaging/package/etc/james/templates/jwt_publickey
deleted file mode 100644
index f00e64b..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/jwt_publickey
+++ /dev/null
@@ -1,3 +0,0 @@
------BEGIN PUBLIC KEY-----
-Your JWT public key
------END PUBLIC KEY-----

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/lmtpserver.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/lmtpserver.xml b/dockerfiles/packaging/package/etc/james/templates/lmtpserver.xml
deleted file mode 100644
index ce079b0..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/lmtpserver.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one   
-  or more contributor license agreements.  See the NOTICE file 
-  distributed with this work for additional information        
-  regarding copyright ownership.  The ASF licenses this file   
-  to you under the Apache License, Version 2.0 (the            
-  "License"); you may not use this file except in compliance   
-  with the License.  You may obtain a copy of the License at   
-                                                               
-    http://www.apache.org/licenses/LICENSE-2.0                 
-                                                               
-  Unless required by applicable law or agreed to in writing,   
-  software distributed under the License is distributed on an  
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
-  KIND, either express or implied.  See the License for the    
-  specific language governing permissions and limitations      
-  under the License.                                           
- -->
-
-<lmtpservers>
-
-    <lmtpserver enabled="false">
-        <jmxName>lmtpserver</jmxName>
-        <!-- LMTP should not be reachable from outside your network so bind it to loopback-->
-        <bind>127.0.0.1:24</bind>
-        <connectionBacklog>200</connectionBacklog>
-        <connectiontimeout>1200</connectiontimeout>
-        <!-- Set the maximum simultaneous incoming connections for this service -->
-        <connectionLimit>0</connectionLimit>
-        <!-- Set the maximum simultaneous incoming connections per IP for this service -->
-        <connectionLimitPerIP>0</connectionLimitPerIP>
-        <!--  This sets the maximum allowed message size (in kilobytes) for this -->
-        <!--  LMTP service. If unspecified, the value defaults to 0, which means no limit. -->
-        <maxmessagesize>0</maxmessagesize>
-        <handlerchain>
-            <handler class="org.apache.james.lmtpserver.CoreCmdHandlerLoader"/>
-        </handlerchain>
-    </lmtpserver>
-
-</lmtpservers>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/logback.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/logback.xml b/dockerfiles/packaging/package/etc/james/templates/logback.xml
deleted file mode 100644
index 94a639f..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/logback.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration>
-
-        <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
-                <resetJUL>true</resetJUL>
-        </contextListener>
-
-        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
-                <encoder>
-                        <pattern>%d{HH:mm:ss.SSS} %highlight([%-5level]) %logger{15} - %msg%n%rEx</pattern>
-                        <immediateFlush>false</immediateFlush>
-                </encoder>
-        </appender>
-
-        <appender name="LOG_FILE" class="ch.qos.logback.core.FileAppender">
-                <file>/logs/james.log</file>
-                <encoder>
-                        <pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
-                        <immediateFlush>false</immediateFlush>
-                </encoder>
-        </appender>
-
-        <root level="INFO">
-                <appender-ref ref="CONSOLE" />
-                <appender-ref ref="LOG_FILE" />
-        </root>
-
-        <logger name="com.datastax.driver.core.QueryLogger.SLOW" level="DEBUG" />
-
-</configuration>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/mailetcontainer.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/mailetcontainer.xml b/dockerfiles/packaging/package/etc/james/templates/mailetcontainer.xml
deleted file mode 100644
index 681b966..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/mailetcontainer.xml
+++ /dev/null
@@ -1,144 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
- -->
-
-<mailetcontainer enableJmx="true">
-
-    <context>
-        <postmaster>postmaster@james.minet.net</postmaster>
-    </context>
-
-    <spooler>
-        <threads>20</threads>
-    </spooler>
-
-    <processors>
-        <processor state="root" enableJmx="true">
-            <mailet match="All" class="PostmasterAlias"/>
-            <mailet match="RelayLimit=30" class="Null"/>
-            <mailet match="All" class="ToProcessor">
-                <processor>transport</processor>
-            </mailet>
-        </processor>
-
-        <processor state="error" enableJmx="true">
-            <mailet match="All" class="MetricsMailet">
-                <metricName>mailetContainerErrors</metricName>
-            </mailet>
-            <mailet match="All" class="Bounce"/>
-            <mailet match="All" class="ToRepository">
-                <repositoryPath>file://var/mail/error/</repositoryPath>
-            </mailet>
-        </processor>
-
-        <processor state="transport" enableJmx="true">
-            <mailet match="SMTPAuthSuccessful" class="SetMimeHeader">
-                <name>X-UserIsAuth</name>
-                <value>true</value>
-            </mailet>
-            <mailet match="HasMailAttribute=org.apache.james.SMIMECheckSignature" class="SetMimeHeader">
-                <name>X-WasSigned</name>
-                <value>true</value>
-            </mailet>
-            <mailet match="All" class="RemoveMimeHeader">
-                <name>bcc</name>
-            </mailet>
-            <mailet match="All" class="RecipientRewriteTable" />
-            <mailet match="RecipientIsLocal" class="org.apache.james.jmap.mailet.VacationMailet"/>
-            <mailet match="RecipientIsLocal" class="Sieve"/>
-            <mailet match="RecipientIsLocal" class="AddDeliveredToHeader"/>
-            <mailet match="RecipientIsLocal" class="LocalDelivery"/>
-            <mailet match="HostIsLocal" class="ToProcessor">
-                <processor>local-address-error</processor>
-                <notice>550 - Requested action not taken: no such user here</notice>
-            </mailet>
-
-            <mailet match="SMTPAuthSuccessful" class="ToProcessor">
-                <processor>relay</processor>
-            </mailet>
-            <mailet match="HasMailAttribute=org.apache.james.jmap.send.MailMetaData.messageId" class="ToProcessor">
-                <processor>relay</processor>
-            </mailet>
-
-            <mailet match="All" class="ToProcessor">
-                <processor>relay-denied</processor>
-            </mailet>
-        </processor>
-
-        <processor state="relay" enableJmx="true">
-            <mailet match="All" class="RemoteDelivery">
-                <outgoingQueue>outgoing</outgoingQueue>
-                <delayTime>5000, 100000, 500000</delayTime>
-                <maxRetries>25</maxRetries>
-                <maxDnsProblemRetries>0</maxDnsProblemRetries>
-                <deliveryThreads>10</deliveryThreads>
-                <sendpartial>true</sendpartial>
-                <bounceProcessor>bounces</bounceProcessor>
-            </mailet>
-        </processor>
-
-        <processor state="spam" enableJmx="true">
-            <mailet match="All" class="MetricsMailet">
-                <metricName>mailetContainerSpam</metricName>
-            </mailet>
-            <mailet match="All" class="ToRepository">
-                <repositoryPath>file://var/mail/spam/</repositoryPath>
-            </mailet>
-        </processor>
-
-        <processor state="local-address-error" enableJmx="true">
-            <mailet match="All" class="MetricsMailet">
-                <metricName>mailetContainerLocalAddressError</metricName>
-            </mailet>
-            <mailet match="All" class="Bounce">
-                <attachment>none</attachment>
-            </mailet>
-            <mailet match="All" class="ToRepository">
-                <repositoryPath>file://var/mail/address-error/</repositoryPath>
-            </mailet>
-        </processor>
-
-        <processor state="relay-denied" enableJmx="true">
-            <mailet match="All" class="MetricsMailet">
-                <metricName>mailetContainerRelayDenied</metricName>
-            </mailet>
-            <mailet match="All" class="Bounce">
-                <attachment>none</attachment>
-            </mailet>
-            <mailet match="All" class="ToRepository">
-                <repositoryPath>file://var/mail/relay-denied/</repositoryPath>
-                <notice>Warning: You are sending an e-mail to a remote server. You must be authenticated to perform such an operation</notice>
-            </mailet>
-        </processor>
-
-        <processor state="bounces" enableJmx="true">
-            <mailet match="All" class="MetricsMailet">
-                <metricName>bounces</metricName>
-            </mailet>
-            <mailet match="All" class="DSNBounce">
-                <passThrough>false</passThrough>
-            </mailet>
-        </processor>
-
-    </processors>
-
-</mailetcontainer>
-
-


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


[20/21] james-project git commit: JAMES-2274 Script helper for per-commit packages generation

Posted by bt...@apache.org.
JAMES-2274 Script helper for per-commit packages generation


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

Branch: refs/heads/master
Commit: fe9c62560d3eea74edce46228b38bbd4cba1e7fb
Parents: 0e6e17d
Author: benwa <bt...@linagora.com>
Authored: Thu Dec 28 13:52:00 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:12:47 2018 +0700

----------------------------------------------------------------------
 README.adoc                                     |  5 ++
 .../packaging/guice/cassandra/Dockerfile        |  4 +-
 .../packaging/guice/cassandra/james.postinst    |  6 --
 .../guice/cassandra/james.rpm.postinst          |  8 ---
 .../guice/cassandra/james.rpm.postremove        |  7 --
 .../guice/cassandra/james.rpm.postupgrade       |  5 --
 .../packaging/guice/cassandra/james.service     | 34 ----------
 .../packaging/guice/cassandra/package.sh        | 68 +++++++-------------
 .../guice/cassandra/scripts/james.postinst      |  6 ++
 .../guice/cassandra/scripts/james.rpm.postinst  |  8 +++
 .../cassandra/scripts/james.rpm.postremove      |  7 ++
 .../cassandra/scripts/james.rpm.postupgrade     |  5 ++
 .../guice/cassandra/scripts/james.service       | 34 ++++++++++
 .../guice/cassandra/scripts/james.service.rhel  | 34 ++++++++++
 .../guice/cassandra/scripts/package.sh          | 61 ++++++++++++++++++
 dockerfiles/packaging/james.service.rhel        | 34 ----------
 16 files changed, 186 insertions(+), 140 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/README.adoc
----------------------------------------------------------------------
diff --git a/README.adoc b/README.adoc
index 7e3acc9..7245fb2 100644
--- a/README.adoc
+++ b/README.adoc
@@ -375,3 +375,8 @@ Then, you have to run the container:
 Where:
 
 - $PWD/result is the folder where the deb and the RPM packages will be copied
+
+Note: A helper script is provided for the generation of packages for a specific git commit. For instance:
+
+    $ sh dockerfiles/packaging/guice/cassandra/package.sh 3.0.1 1 c298195e84 $PWD/result
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/Dockerfile
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/Dockerfile b/dockerfiles/packaging/guice/cassandra/Dockerfile
index 21b99c6..632a40d 100644
--- a/dockerfiles/packaging/guice/cassandra/Dockerfile
+++ b/dockerfiles/packaging/guice/cassandra/Dockerfile
@@ -8,9 +8,9 @@ RUN apt-get install -y ruby-dev ruby build-essential
 RUN gem install fpm
 RUN apt-get install -y rpm
 
-ADD . /packages
+ADD scripts/ /packages
 
-COPY james.service /packages/package/usr/share/james/
+COPY scripts/james.service /packages/package/usr/share/james/
 COPY --from=source /root/*.jar /packages/package/usr/share/james/
 COPY --from=source /root/james-server-cassandra-guice.lib/ /packages/package/usr/share/james/james-server-cassandra-guice.lib/
 COPY --from=source /root/james-server-cli.lib/ /packages/package/usr/share/james/james-server-cli.lib/

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/james.postinst
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/james.postinst b/dockerfiles/packaging/guice/cassandra/james.postinst
deleted file mode 100644
index 82306a7..0000000
--- a/dockerfiles/packaging/guice/cassandra/james.postinst
+++ /dev/null
@@ -1,6 +0,0 @@
-#! /bin/sh -e
-
-ln -s /etc/james /var/lib/james/conf
-
-systemctl enable james
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/james.rpm.postinst
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/james.rpm.postinst b/dockerfiles/packaging/guice/cassandra/james.rpm.postinst
deleted file mode 100644
index 447b4c1..0000000
--- a/dockerfiles/packaging/guice/cassandra/james.rpm.postinst
+++ /dev/null
@@ -1,8 +0,0 @@
-#! /bin/sh -e
- 
-ln -s /etc/james /var/lib/james/conf
-
-#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
-cp /usr/share/james/james.service /etc/systemd/system/
-systemctl enable james
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/james.rpm.postremove
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/james.rpm.postremove b/dockerfiles/packaging/guice/cassandra/james.rpm.postremove
deleted file mode 100644
index d70a3ed..0000000
--- a/dockerfiles/packaging/guice/cassandra/james.rpm.postremove
+++ /dev/null
@@ -1,7 +0,0 @@
-#! /bin/sh -e
- 
-#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
-systemctl stop james
-systemctl disable james
-rm /etc/systemd/system/james.service
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/james.rpm.postupgrade
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/james.rpm.postupgrade b/dockerfiles/packaging/guice/cassandra/james.rpm.postupgrade
deleted file mode 100644
index 8e2c81c..0000000
--- a/dockerfiles/packaging/guice/cassandra/james.rpm.postupgrade
+++ /dev/null
@@ -1,5 +0,0 @@
-#! /bin/sh -e
- 
-#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
-systemctl try-restart james
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/james.service
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/james.service b/dockerfiles/packaging/guice/cassandra/james.service
deleted file mode 100644
index 2c55df6..0000000
--- a/dockerfiles/packaging/guice/cassandra/james.service
+++ /dev/null
@@ -1,34 +0,0 @@
-[Unit]
-Description=James stands for Java Apache Mail Enterprise Server! It has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.
-Documentation=http://james.apache.org
-Wants=network-online.target cassandra.service elasticsearch.service
-After=network-online.target cassandra.service elasticsearch.service
-
-[Service]
-Environment=WORKING_DIRECTORY=/var/lib/james
-Environment=XMX=1024m
-
-User=root
-Group=root
-
-ExecStart=/usr/lib/jvm/java-8-openjdk-amd64/bin/java -Dworking.directory=${WORKING_DIRECTORY} -Xmx${XMX} -Dlogback.configurationFile=/etc/james/logback.xml -jar /usr/share/james/james-server.jar 
-
-StandardOutput=journal
-StandardError=inherit
-
-# Specifies the maximum number of bytes of memory that may be locked into RAM
-# Set to "infinity" if you use the 'bootstrap.mlockall: true' option
-# in elasticsearch.yml and 'MAX_LOCKED_MEMORY=unlimited' in /etc/default/elasticsearch
-#LimitMEMLOCK=infinity
-
-# SIGTERM signal is used to stop the Java process
-KillSignal=SIGTERM
-
-# Java process is never killed
-SendSIGKILL=no
-
-# When a JVM receives a SIGTERM signal it exits with code 143
-SuccessExitStatus=143
-
-[Install]
-WantedBy=multi-user.target

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/package.sh
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/package.sh b/dockerfiles/packaging/guice/cassandra/package.sh
old mode 100755
new mode 100644
index ce89168..2d4805d
--- a/dockerfiles/packaging/guice/cassandra/package.sh
+++ b/dockerfiles/packaging/guice/cassandra/package.sh
@@ -2,60 +2,40 @@
 
 printUsage() {
    echo "Usage : "
-   echo "./package.sh RELEASE ITERATION"
+   echo "./package.sh RELEASE ITERATION SHA1 DIRECTORY"
    echo "    RELEASE  : The release to be generated."
    echo "    ITERATION: The iteration to give to the package."
+   echo "    SHA1: The SHA-1 to build packages against"
+   echo "    DIRECTORY: The directory where to put build results"
    exit 1
 }
 
-if [ "$#" -ne 2 ]; then
+
+if [ "$#" -ne 4 ]; then
     printUsage
 fi
 
 RELEASE=$1
 ITERATION=$2
+SHA1=$3
+DIRECTORY=$4
 
-fpm -s dir -t deb \
- -n james \
- -v $RELEASE \
- -a x86_64 \
- -d openjdk-8-jre \
- -C package \
- --deb-systemd james.service \
- --after-install james.postinst \
- --provides mail-transport-agent \
- --provides default-mta \
- --iteration $ITERATION \
- --license http://www.apache.org/licenses/LICENSE-2.0 \
- --description "$(printf "James stands for Java Apache Mail Enterprise Server!\nIt has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.")" \
- --vendor "Apache" \
- --maintainer "Apache" \
- --url http://james.apache.org/ \
- --category web \
- .
-
-#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
-cp james.service.rhel package/usr/share/james/james.service
+# Compile James
+docker build -t james/project dockerfiles/compilation/java-8
+docker run \
+   --rm \
+   --volume $PWD/.m2:/root/.m2 \
+   --volume $PWD:/origin \
+   --volume $PWD/dockerfiles/run/guice/cassandra/destination:/cassandra/destination \
+   -t james/project -s $SHA1
 
-fpm -s dir -t rpm \
- -n james \
- -v $RELEASE \
- -a x86_64 \
- -d java-1.8.0-openjdk-headless \
- -C package \
- --after-install james.rpm.postinst \
- --after-upgrade james.rpm.postupgrade \
- --after-remove james.rpm.postremove \
- --provides mail-transport-agent \
- --provides default-mta \
- --iteration $ITERATION \
- --license http://www.apache.org/licenses/LICENSE-2.0 \
- --description "$(printf "James stands for Java Apache Mail Enterprise Server!\nIt has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.")" \
- --vendor "Apache" \
- --maintainer "Apache" \
- --url http://james.apache.org/ \
- --category web \
- .
+# Build image
+docker build -t james_run dockerfiles/run/guice/cassandra
 
-cp /packages/james*.deb /result/
-cp /packages/james*.rpm /result/
+# Build packages
+docker build -t build-james-packages \
+  --build-arg RELEASE=$RELEASE-$SHA1 \
+  --build-arg ITERATION=$ITERATION \
+  --build-arg BASE=james_run \
+  dockerfiles/packaging/guice/cassandra
+docker run --rm --name james-packages -v $DIRECTORY:/result build-james-packages
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/scripts/james.postinst
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/scripts/james.postinst b/dockerfiles/packaging/guice/cassandra/scripts/james.postinst
new file mode 100644
index 0000000..82306a7
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/scripts/james.postinst
@@ -0,0 +1,6 @@
+#! /bin/sh -e
+
+ln -s /etc/james /var/lib/james/conf
+
+systemctl enable james
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postinst
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postinst b/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postinst
new file mode 100644
index 0000000..447b4c1
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postinst
@@ -0,0 +1,8 @@
+#! /bin/sh -e
+ 
+ln -s /etc/james /var/lib/james/conf
+
+#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
+cp /usr/share/james/james.service /etc/systemd/system/
+systemctl enable james
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postremove
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postremove b/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postremove
new file mode 100644
index 0000000..d70a3ed
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postremove
@@ -0,0 +1,7 @@
+#! /bin/sh -e
+ 
+#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
+systemctl stop james
+systemctl disable james
+rm /etc/systemd/system/james.service
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postupgrade
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postupgrade b/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postupgrade
new file mode 100644
index 0000000..8e2c81c
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/scripts/james.rpm.postupgrade
@@ -0,0 +1,5 @@
+#! /bin/sh -e
+ 
+#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
+systemctl try-restart james
+

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/scripts/james.service
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/scripts/james.service b/dockerfiles/packaging/guice/cassandra/scripts/james.service
new file mode 100644
index 0000000..2c55df6
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/scripts/james.service
@@ -0,0 +1,34 @@
+[Unit]
+Description=James stands for Java Apache Mail Enterprise Server! It has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.
+Documentation=http://james.apache.org
+Wants=network-online.target cassandra.service elasticsearch.service
+After=network-online.target cassandra.service elasticsearch.service
+
+[Service]
+Environment=WORKING_DIRECTORY=/var/lib/james
+Environment=XMX=1024m
+
+User=root
+Group=root
+
+ExecStart=/usr/lib/jvm/java-8-openjdk-amd64/bin/java -Dworking.directory=${WORKING_DIRECTORY} -Xmx${XMX} -Dlogback.configurationFile=/etc/james/logback.xml -jar /usr/share/james/james-server.jar 
+
+StandardOutput=journal
+StandardError=inherit
+
+# Specifies the maximum number of bytes of memory that may be locked into RAM
+# Set to "infinity" if you use the 'bootstrap.mlockall: true' option
+# in elasticsearch.yml and 'MAX_LOCKED_MEMORY=unlimited' in /etc/default/elasticsearch
+#LimitMEMLOCK=infinity
+
+# SIGTERM signal is used to stop the Java process
+KillSignal=SIGTERM
+
+# Java process is never killed
+SendSIGKILL=no
+
+# When a JVM receives a SIGTERM signal it exits with code 143
+SuccessExitStatus=143
+
+[Install]
+WantedBy=multi-user.target

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/scripts/james.service.rhel
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/scripts/james.service.rhel b/dockerfiles/packaging/guice/cassandra/scripts/james.service.rhel
new file mode 100644
index 0000000..af48a62
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/scripts/james.service.rhel
@@ -0,0 +1,34 @@
+[Unit]
+Description=James stands for Java Apache Mail Enterprise Server! It has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.
+Documentation=http://james.apache.org
+Wants=network-online.target cassandra.service elasticsearch.service
+After=network-online.target cassandra.service elasticsearch.service
+
+[Service]
+Environment=WORKING_DIRECTORY=/var/lib/james
+Environment=XMX=1024m
+
+User=root
+Group=root
+
+ExecStart=/usr/lib/jvm/jre-1.8.0-openjdk/bin/java -Dworking.directory=${WORKING_DIRECTORY} -Xmx${XMX} -Dlogback.configurationFile=/etc/james/logback.xml -jar /usr/share/james/james-server.jar 
+
+StandardOutput=journal
+StandardError=inherit
+
+# Specifies the maximum number of bytes of memory that may be locked into RAM
+# Set to "infinity" if you use the 'bootstrap.mlockall: true' option
+# in elasticsearch.yml and 'MAX_LOCKED_MEMORY=unlimited' in /etc/default/elasticsearch
+#LimitMEMLOCK=infinity
+
+# SIGTERM signal is used to stop the Java process
+KillSignal=SIGTERM
+
+# Java process is never killed
+SendSIGKILL=no
+
+# When a JVM receives a SIGTERM signal it exits with code 143
+SuccessExitStatus=143
+
+[Install]
+WantedBy=multi-user.target

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/guice/cassandra/scripts/package.sh
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/scripts/package.sh b/dockerfiles/packaging/guice/cassandra/scripts/package.sh
new file mode 100755
index 0000000..da86f36
--- /dev/null
+++ b/dockerfiles/packaging/guice/cassandra/scripts/package.sh
@@ -0,0 +1,61 @@
+#!/bin/sh -e
+
+printUsage() {
+   echo "Usage : "
+   echo "./package.sh RELEASE ITERATION"
+   echo "    RELEASE  : The release to be generated."
+   echo "    ITERATION: The iteration to give to the package."
+   exit 1
+}
+
+if [ "$#" -ne 2 ]; then
+    printUsage
+fi
+
+RELEASE=$1
+ITERATION=$2
+
+fpm -s dir -t deb \
+ -n james \
+ -v $RELEASE \
+ -a x86_64 \
+ -d openjdk-8-jre \
+ -C package \
+ --deb-systemd james.service \
+ --after-install james.postinst \
+ --provides mail-transport-agent \
+ --provides default-mta \
+ --iteration $ITERATION \
+ --license http://www.apache.org/licenses/LICENSE-2.0 \
+ --description "$(printf "James stands for Java Apache Mail Enterprise Server!\nIt has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.")" \
+ --vendor "Apache" \
+ --maintainer "Apache" \
+ --url http://james.apache.org/ \
+ --category web \
+ .
+
+#Workaround waiting for https://github.com/jordansissel/fpm/issues/1163 to be released
+cp james.service.rhel package/usr/share/james/james.service
+
+fpm -s dir -t rpm \
+ -n james \
+ -v $RELEASE \
+ -a x86_64 \
+ -d java-1.8.0-openjdk-headless \
+ -C package \
+ --after-install james.rpm.postinst \
+ --after-upgrade james.rpm.postupgrade \
+ --after-remove james.rpm.postremove \
+ --provides mail-transport-agent \
+ --provides default-mta \
+ --iteration $ITERATION \
+ --license http://www.apache.org/licenses/LICENSE-2.0 \
+ --description "$(printf "James stands for Java Apache Mail Enterprise Server!\nIt has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.")" \
+ --vendor "Apache" \
+ --maintainer "Apache" \
+ --url http://james.apache.org/ \
+ --category web \
+ .
+
+cp /packages/james*.deb /result/
+cp /packages/james*.rpm /result/
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/fe9c6256/dockerfiles/packaging/james.service.rhel
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/james.service.rhel b/dockerfiles/packaging/james.service.rhel
deleted file mode 100644
index af48a62..0000000
--- a/dockerfiles/packaging/james.service.rhel
+++ /dev/null
@@ -1,34 +0,0 @@
-[Unit]
-Description=James stands for Java Apache Mail Enterprise Server! It has a modular architecture based on a rich set of modern and efficient components which provides at the end complete, stable, secure and extendable Mail Servers running on the JVM.
-Documentation=http://james.apache.org
-Wants=network-online.target cassandra.service elasticsearch.service
-After=network-online.target cassandra.service elasticsearch.service
-
-[Service]
-Environment=WORKING_DIRECTORY=/var/lib/james
-Environment=XMX=1024m
-
-User=root
-Group=root
-
-ExecStart=/usr/lib/jvm/jre-1.8.0-openjdk/bin/java -Dworking.directory=${WORKING_DIRECTORY} -Xmx${XMX} -Dlogback.configurationFile=/etc/james/logback.xml -jar /usr/share/james/james-server.jar 
-
-StandardOutput=journal
-StandardError=inherit
-
-# Specifies the maximum number of bytes of memory that may be locked into RAM
-# Set to "infinity" if you use the 'bootstrap.mlockall: true' option
-# in elasticsearch.yml and 'MAX_LOCKED_MEMORY=unlimited' in /etc/default/elasticsearch
-#LimitMEMLOCK=infinity
-
-# SIGTERM signal is used to stop the Java process
-KillSignal=SIGTERM
-
-# Java process is never killed
-SendSIGKILL=no
-
-# When a JVM receives a SIGTERM signal it exits with code 143
-SuccessExitStatus=143
-
-[Install]
-WantedBy=multi-user.target


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


[13/21] james-project git commit: JAMES-2274 Packaging generation is product specific

Posted by bt...@apache.org.
http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/mailrepositorystore.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/mailrepositorystore.xml b/dockerfiles/packaging/package/etc/james/templates/mailrepositorystore.xml
deleted file mode 100644
index acca810..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/mailrepositorystore.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
- -->
-
-<mailrepositorystore>
-    <mailrepositories>
-        <!-- File based repositories.  These repositories store all message data -->
-        <!-- in the file system. -->
-        <mailrepository class="org.apache.james.mailrepository.file.FileMailRepository">
-            <protocols>
-                <protocol>file</protocol>
-            </protocols>
-            <!-- Set if the messages should be listed sorted. False by default -->
-            <config FIFO="false" CACHEKEYS="true"/>
-        </mailrepository>
-    </mailrepositories>
-</mailrepositorystore>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/managesieveserver.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/managesieveserver.xml b/dockerfiles/packaging/package/etc/james/templates/managesieveserver.xml
deleted file mode 100644
index 7b0b85a..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/managesieveserver.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one   
-  or more contributor license agreements.  See the NOTICE file 
-  distributed with this work for additional information        
-  regarding copyright ownership.  The ASF licenses this file   
-  to you under the Apache License, Version 2.0 (the            
-  "License"); you may not use this file except in compliance   
-  with the License.  You may obtain a copy of the License at   
-                                                               
-    http://www.apache.org/licenses/LICENSE-2.0                 
-                                                               
-  Unless required by applicable law or agreed to in writing,   
-  software distributed under the License is distributed on an  
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
-  KIND, either express or implied.  See the License for the    
-  specific language governing permissions and limitations      
-  under the License.                                           
- -->
- 
-<!--
-   This template file can be used as example for James Server configuration
-   DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
--->
- 
-<!-- See http://james.apache.org/server/3/config.html for usage -->
-
-<managesieveservers>
-
-   <managesieveserver enabled="false">
-
-     <jmxName>managesieveserver</jmxName>
-
-     <bind>0.0.0.0:4190</bind>
-
-     <connectionBacklog>200</connectionBacklog>
-
-     <tls socketTLS="false" startTLS="false">
-       <!-- To create a new keystore execute:
-        keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
-         -->
-       <keystore>file://conf/keystore</keystore>
-       <secret>james72laBalle</secret>
-       <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
-       <!-- The algorithm is optional and only needs to be specified when using something other
-        than the Sun JCE provider - You could use IbmX509 with IBM Java runtime. -->
-       <algorithm>SunX509</algorithm>
-     </tls>
-         
-        <!-- connection timeout in secconds -->
-        <connectiontimeout>360</connectiontimeout>
-
-        <!-- Set the maximum simultaneous incoming connections for this service -->
-        <connectionLimit>0</connectionLimit>
-         
-        <!-- Set the maximum simultaneous incoming connections per IP for this service -->
-        <connectionLimitPerIP>0</connectionLimitPerIP>
-        <maxmessagesize>0</maxmessagesize>
-        <addressBracketsEnforcement>true</addressBracketsEnforcement>
-  
-   </managesieveserver>
-
-</managesieveservers>
-
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/pop3server.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/pop3server.xml b/dockerfiles/packaging/package/etc/james/templates/pop3server.xml
deleted file mode 100644
index df8fbef..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/pop3server.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one   
-  or more contributor license agreements.  See the NOTICE file 
-  distributed with this work for additional information        
-  regarding copyright ownership.  The ASF licenses this file   
-  to you under the Apache License, Version 2.0 (the            
-  "License"); you may not use this file except in compliance   
-  with the License.  You may obtain a copy of the License at   
-                                                               
-    http://www.apache.org/licenses/LICENSE-2.0                 
-                                                               
-  Unless required by applicable law or agreed to in writing,   
-  software distributed under the License is distributed on an  
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
-  KIND, either express or implied.  See the License for the    
-  specific language governing permissions and limitations      
-  under the License.                                           
- -->
-
-
-<pop3servers>
-    <pop3server enabled="false">
-        <jmxName>pop3server</jmxName>
-        <bind>0.0.0.0:110</bind>
-        <connectionBacklog>200</connectionBacklog>
-        <tls socketTLS="false" startTLS="false">
-            <!-- To create a new keystore execute:
-                  keytool -genkey -alias james -keyalg RSA -keystore /path/to/james/conf/keystore
-             -->
-            <keystore>file://conf/keystore</keystore>
-            <secret>james72laBalle</secret>
-            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
-        </tls>
-        <connectiontimeout>1200</connectiontimeout>
-        <connectionLimit>0</connectionLimit>
-        <connectionLimitPerIP>0</connectionLimitPerIP>
-        <handlerchain>
-            <handler class="org.apache.james.pop3server.core.CoreCmdHandlerLoader"/>
-        </handlerchain>
-    </pop3server>
-</pop3servers>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/quota.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/quota.xml b/dockerfiles/packaging/package/etc/james/templates/quota.xml
deleted file mode 100644
index 70162e0..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/quota.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
- -->
-
-<!--
-   This template file can be used as example for James Server configuration
-   DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
--->
-
-<!-- See http://james.apache.org/server/3/config.html for usage -->
-
-<!--
-        This configuration file allows you to customize the way quota are handled on this server.
-        You need to rename it in quota.xml so that it gets interpreted by James on startup.
-
-        The different configuration options are detailed here.
-
-        Read RFC-2087 for full details.
--->
-
-<quota>
-    <quotaRootResolver>
-        <provider>default</provider>
-    </quotaRootResolver>
-    <currentQuotaManager>
-        <provider>cassandra</provider>
-    </currentQuotaManager>
-    <maxQuotaManager>
-        <provider>cassandra</provider>
-    </maxQuotaManager>
-    <quotaManager>
-        <provider>store</provider>
-    </quotaManager>
-    <updates>
-        <provider>event</provider>
-    </updates>
-</quota>

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/recipientrewritetable.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/recipientrewritetable.xml b/dockerfiles/packaging/package/etc/james/templates/recipientrewritetable.xml
deleted file mode 100644
index 3d44578..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/recipientrewritetable.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one   
-  or more contributor license agreements.  See the NOTICE file 
-  distributed with this work for additional information        
-  regarding copyright ownership.  The ASF licenses this file   
-  to you under the Apache License, Version 2.0 (the            
-  "License"); you may not use this file except in compliance   
-  with the License.  You may obtain a copy of the License at   
-                                                               
-    http://www.apache.org/licenses/LICENSE-2.0                 
-                                                               
-  Unless required by applicable law or agreed to in writing,   
-  software distributed under the License is distributed on an  
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
-  KIND, either express or implied.  See the License for the    
-  specific language governing permissions and limitations      
-  under the License.                                           
- -->
-
-<!-- The default table for storing James' RecipientRewriteTable mappings. -->
-<recipientrewritetable>
-  <recursiveMapping>true</recursiveMapping>
-  <mappingLimit>10</mappingLimit>
-</recipientrewritetable>
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/smtpserver.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/smtpserver.xml b/dockerfiles/packaging/package/etc/james/templates/smtpserver.xml
deleted file mode 100644
index bc609be..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/smtpserver.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
- -->
-
-<smtpservers>
-    <smtpserver enabled="true">
-        <jmxName>smtpserver-global</jmxName>
-        <bind>0.0.0.0:25</bind>
-        <connectionBacklog>200</connectionBacklog>
-        <tls socketTLS="false" startTLS="false">
-            <keystore>file://conf/keystore</keystore>
-            <secret>james72laBalle</secret>
-            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
-            <algorithm>SunX509</algorithm>
-        </tls>
-        <connectiontimeout>360</connectiontimeout>
-        <connectionLimit>0</connectionLimit>
-        <connectionLimitPerIP>0</connectionLimitPerIP>
-        <authRequired>false</authRequired>
-        <authorizedAddresses>0.0.0.0/0</authorizedAddresses>
-        <verifyIdentity>true</verifyIdentity>
-        <maxmessagesize>0</maxmessagesize>
-        <addressBracketsEnforcement>true</addressBracketsEnforcement>
-        <smtpGreeting>JAMES Linagora's SMTP awesome Server</smtpGreeting>
-        <handlerchain>
-            <handler class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
-            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
-        </handlerchain>
-    </smtpserver>
-    <smtpserver enabled="true">
-        <jmxName>smtpserver-TLS</jmxName>
-        <bind>0.0.0.0:465</bind>
-        <connectionBacklog>200</connectionBacklog>
-        <tls socketTLS="true" startTLS="false">
-            <keystore>file://conf/keystore</keystore>
-            <secret>james72laBalle</secret>
-            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
-            <algorithm>SunX509</algorithm>
-        </tls>
-        <connectiontimeout>360</connectiontimeout>
-        <connectionLimit>0</connectionLimit>
-        <connectionLimitPerIP>0</connectionLimitPerIP>
-        <!--
-           Authorize only local users
-        -->
-        <authRequired>true</authRequired>
-        <authorizedAddresses>0.0.0.0/0</authorizedAddresses>
-        <!-- Trust authenticated users -->
-        <verifyIdentity>false</verifyIdentity>
-        <maxmessagesize>0</maxmessagesize>
-        <addressBracketsEnforcement>true</addressBracketsEnforcement>
-        <smtpGreeting>JAMES Linagora's SMTP awesome Server</smtpGreeting>
-        <handlerchain>
-            <handler class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
-            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
-        </handlerchain>
-    </smtpserver>
-    <smtpserver enabled="true">
-        <jmxName>smtpserver-authenticated</jmxName>
-        <bind>0.0.0.0:587</bind>
-        <connectionBacklog>200</connectionBacklog>
-        <tls socketTLS="false" startTLS="true">
-            <keystore>file://conf/keystore</keystore>
-            <secret>james72laBalle</secret>
-            <provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
-            <algorithm>SunX509</algorithm>
-        </tls>
-        <connectiontimeout>360</connectiontimeout>
-        <connectionLimit>0</connectionLimit>
-        <connectionLimitPerIP>0</connectionLimitPerIP>
-        <!--
-           Authorize only local users
-        -->
-        <authRequired>true</authRequired>
-        <authorizedAddresses>0.0.0.0/0</authorizedAddresses>
-        <!-- Trust authenticated users -->
-        <verifyIdentity>false</verifyIdentity>
-        <maxmessagesize>0</maxmessagesize>
-        <addressBracketsEnforcement>true</addressBracketsEnforcement>
-        <smtpGreeting>JAMES Linagora's SMTP awesome Server</smtpGreeting>
-        <handlerchain>
-            <handler class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
-            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
-        </handlerchain>
-    </smtpserver>
-</smtpservers>
-
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/usersrepository.xml
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/usersrepository.xml b/dockerfiles/packaging/package/etc/james/templates/usersrepository.xml
deleted file mode 100644
index c745677..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/usersrepository.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one   
-  or more contributor license agreements.  See the NOTICE file 
-  distributed with this work for additional information        
-  regarding copyright ownership.  The ASF licenses this file   
-  to you under the Apache License, Version 2.0 (the            
-  "License"); you may not use this file except in compliance   
-  with the License.  You may obtain a copy of the License at   
-                                                               
-    http://www.apache.org/licenses/LICENSE-2.0                 
-                                                               
-  Unless required by applicable law or agreed to in writing,   
-  software distributed under the License is distributed on an  
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       
-  KIND, either express or implied.  See the License for the    
-  specific language governing permissions and limitations      
-  under the License.                                           
- -->
-
-<usersrepository name="LocalUsers">
-    <algorithm>MD5</algorithm>
-    <enableVirtualHosting>true</enableVirtualHosting>    
-    <enableForwarding>true</enableForwarding>
-</usersrepository>
-

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/etc/james/templates/webadmin.properties
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/etc/james/templates/webadmin.properties b/dockerfiles/packaging/package/etc/james/templates/webadmin.properties
deleted file mode 100644
index 36b6f1e..0000000
--- a/dockerfiles/packaging/package/etc/james/templates/webadmin.properties
+++ /dev/null
@@ -1,41 +0,0 @@
-#  Licensed to the Apache Software Foundation (ASF) under one
-#  or more contributor license agreements.  See the NOTICE file
-#  distributed with this work for additional information
-#  regarding copyright ownership.  The ASF licenses this file
-#  to you under the Apache License, Version 2.0 (the
-#  "License"); you may not use this file except in compliance
-#  with the License.  You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing,
-#  software distributed under the License is distributed on an
-#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#  KIND, either express or implied.  See the License for the
-#  specific language governing permissions and limitations
-#  under the License.
-
-#  This template file can be used as example for James Server configuration
-#  DO NOT USE IT AS SUCH AND ADAPT IT TO YOUR NEEDS
-
-enabled=true
-port=8000
-host=localhost
-
-# Defaults to false
-https.enabled=false
-
-# Compulsory when enabling HTTPS
-#https.keystore=/path/to/keystore
-#https.password=password
-
-# Optional when enabling HTTPS (self signed)
-#https.trust.keystore
-#https.trust.password
-
-# Defaults to false
-#jwt.enabled=true
-
-# Defaults to false
-#cors.enable=true
-#cors.origin
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/usr/lib/.gitkeep
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/usr/lib/.gitkeep b/dockerfiles/packaging/package/usr/lib/.gitkeep
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/usr/share/james/.gitkeep
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/usr/share/james/.gitkeep b/dockerfiles/packaging/package/usr/share/james/.gitkeep
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/var/lib/james/.gitkeep
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/var/lib/james/.gitkeep b/dockerfiles/packaging/package/var/lib/james/.gitkeep
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/james-project/blob/64d2d19b/dockerfiles/packaging/package/var/log/james/.gitkeep
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/package/var/log/james/.gitkeep b/dockerfiles/packaging/package/var/log/james/.gitkeep
deleted file mode 100644
index e69de29..0000000


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


[06/21] james-project git commit: JAMES-2272 Webadmin should expose a task management API

Posted by bt...@apache.org.
JAMES-2272 Webadmin should expose a task management API


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

Branch: refs/heads/master
Commit: d9d73f801fa61dc311fce2a3566994bc32068a22
Parents: 1b7e8d7
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 12:16:17 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:03:36 2018 +0700

----------------------------------------------------------------------
 .../james/modules/server/TaskRoutesModule.java  |  37 +++
 .../modules/server/WebAdminServerModule.java    |   2 +
 server/protocols/webadmin/webadmin-core/pom.xml |   9 +
 .../james/webadmin/dto/ExecutionDetailsDto.java |  95 +++++++
 .../apache/james/webadmin/dto/TaskIdDto.java    |  40 +++
 .../james/webadmin/routes/TasksRoutes.java      | 127 +++++++++
 .../james/webadmin/utils/ErrorResponder.java    |   1 +
 .../james/webadmin/utils/JsonExtractor.java     |   6 +-
 .../james/webadmin/routes/TasksRoutesTest.java  | 277 +++++++++++++++++++
 9 files changed, 592 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/d9d73f80/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/TaskRoutesModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/TaskRoutesModule.java b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/TaskRoutesModule.java
new file mode 100644
index 0000000..390bb17
--- /dev/null
+++ b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/TaskRoutesModule.java
@@ -0,0 +1,37 @@
+/****************************************************************
+ * 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.modules.server;
+
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.routes.TasksRoutes;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Scopes;
+import com.google.inject.multibindings.Multibinder;
+
+public class TaskRoutesModule extends AbstractModule {
+    @Override
+    protected void configure() {
+        bind(TasksRoutes.class).in(Scopes.SINGLETON);
+
+        Multibinder<Routes> routesMultibinder = Multibinder.newSetBinder(binder(), Routes.class);
+        routesMultibinder.addBinding().to(TasksRoutes.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/d9d73f80/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java
index 1a140ee..6142be1 100644
--- a/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java
+++ b/server/container/guice/protocols/webadmin/src/main/java/org/apache/james/modules/server/WebAdminServerModule.java
@@ -69,6 +69,8 @@ public class WebAdminServerModule extends AbstractModule {
 
     @Override
     protected void configure() {
+        install(new TaskRoutesModule());
+
         bind(JsonTransformer.class).in(Scopes.SINGLETON);
         bind(WebAdminServer.class).in(Scopes.SINGLETON);
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/d9d73f80/server/protocols/webadmin/webadmin-core/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/pom.xml b/server/protocols/webadmin/webadmin-core/pom.xml
index 56bcda1..e86562d 100644
--- a/server/protocols/webadmin/webadmin-core/pom.xml
+++ b/server/protocols/webadmin/webadmin-core/pom.xml
@@ -55,6 +55,10 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>james-server-task</artifactId>
+        </dependency>
+        <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
         </dependency>
@@ -75,6 +79,11 @@
             <artifactId>guava</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.jayway.restassured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>com.sparkjava</groupId>
             <artifactId>spark-core</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/d9d73f80/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/ExecutionDetailsDto.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/ExecutionDetailsDto.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/ExecutionDetailsDto.java
new file mode 100644
index 0000000..7069e8b
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/ExecutionDetailsDto.java
@@ -0,0 +1,95 @@
+/****************************************************************
+ * 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.webadmin.dto;
+
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+import org.apache.james.task.TaskExecutionDetails;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.github.steveash.guavate.Guavate;
+
+public class ExecutionDetailsDto {
+    public static List<ExecutionDetailsDto> from(List<TaskExecutionDetails> tasksDetails) {
+        return tasksDetails.stream()
+            .map(ExecutionDetailsDto::new)
+            .collect(Guavate.toImmutableList());
+    }
+
+    public static ExecutionDetailsDto from(TaskExecutionDetails taskDetails) {
+        return new ExecutionDetailsDto(taskDetails);
+    }
+
+    private final TaskExecutionDetails executionDetails;
+
+    private ExecutionDetailsDto(TaskExecutionDetails executionDetails) {
+        this.executionDetails = executionDetails;
+    }
+
+    public UUID getTaskId() {
+        return executionDetails.getTaskId().getValue();
+    }
+
+    public String getType() {
+        return executionDetails.getType();
+    }
+
+    public String getStatus() {
+        return executionDetails.getStatus().getValue();
+    }
+
+    public Optional<TaskExecutionDetails.AdditionalInformation> getAdditionalInformation() {
+        return executionDetails.getAdditionalInformation();
+    }
+
+    @JsonInclude(JsonInclude.Include.NON_ABSENT)
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
+    public Optional<ZonedDateTime> getSubmitDate() {
+        return executionDetails.getSubmitDate();
+    }
+
+    @JsonInclude(JsonInclude.Include.NON_ABSENT)
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
+    public Optional<ZonedDateTime> getStartedDate() {
+        return executionDetails.getStartedDate();
+    }
+
+    @JsonInclude(JsonInclude.Include.NON_ABSENT)
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
+    public Optional<ZonedDateTime> getCompletedDate() {
+        return executionDetails.getCompletedDate();
+    }
+
+    @JsonInclude(JsonInclude.Include.NON_ABSENT)
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
+    public Optional<ZonedDateTime> getCanceledDate() {
+        return executionDetails.getCanceledDate();
+    }
+
+    @JsonInclude(JsonInclude.Include.NON_ABSENT)
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
+    public Optional<ZonedDateTime> getFailedDate() {
+        return executionDetails.getFailedDate();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/d9d73f80/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/TaskIdDto.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/TaskIdDto.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/TaskIdDto.java
new file mode 100644
index 0000000..231d051
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/TaskIdDto.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.webadmin.dto;
+
+import java.util.UUID;
+
+import org.apache.james.task.TaskId;
+
+public class TaskIdDto {
+    public static TaskIdDto from(TaskId id) {
+        return new TaskIdDto(id.getValue());
+    }
+
+    private final UUID uuid;
+
+    public TaskIdDto(UUID uuid) {
+        this.uuid = uuid;
+    }
+
+    public UUID getTaskId() {
+        return uuid;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/d9d73f80/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
new file mode 100644
index 0000000..99bd2df
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
@@ -0,0 +1,127 @@
+/****************************************************************
+ * 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.webadmin.routes;
+
+import java.util.Optional;
+import java.util.UUID;
+import java.util.function.Supplier;
+
+import javax.inject.Inject;
+
+import org.apache.james.task.TaskExecutionDetails;
+import org.apache.james.task.TaskId;
+import org.apache.james.task.TaskManager;
+import org.apache.james.task.TaskNotFoundException;
+import org.apache.james.webadmin.Constants;
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.dto.ExecutionDetailsDto;
+import org.apache.james.webadmin.utils.ErrorResponder;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.eclipse.jetty.http.HttpStatus;
+
+import spark.Request;
+import spark.Response;
+import spark.Service;
+
+public class TasksRoutes implements Routes {
+    public static final String BASE = "/tasks";
+    private final TaskManager taskManager;
+    private final JsonTransformer jsonTransformer;
+
+    @Inject
+    public TasksRoutes(TaskManager taskManager, JsonTransformer jsonTransformer) {
+        this.taskManager = taskManager;
+        this.jsonTransformer = jsonTransformer;
+    }
+
+    @Override
+    public void define(Service service) {
+        service.get(BASE + "/:id", this::getStatus, jsonTransformer);
+
+        service.get(BASE + "/:id/await", this::await, jsonTransformer);
+
+        service.delete(BASE + "/:id", this::cancel, jsonTransformer);
+
+        service.get(BASE, this::list, jsonTransformer);
+    }
+
+    private Object list(Request req, Response response) {
+        try {
+            return ExecutionDetailsDto.from(
+                Optional.ofNullable(req.queryParams("status"))
+                .map(TaskManager.Status::fromString)
+                .map(taskManager::list)
+                .orElse(taskManager.list()));
+        } catch (IllegalArgumentException e) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .cause(e)
+                .message("Invalid status query parameter")
+                .haltError();
+        }
+    }
+
+    private Object getStatus(Request req, Response response) {
+        TaskId taskId = getTaskId(req);
+        return respondStatus(taskId,
+            () -> taskManager.getExecutionDetails(getTaskId(req)));
+    }
+
+    private Object await(Request req, Response response) {
+        TaskId taskId = getTaskId(req);
+        return respondStatus(taskId,
+            () -> taskManager.await(getTaskId(req)));
+    }
+
+    private Object respondStatus(TaskId taskId, Supplier<TaskExecutionDetails> executionDetailsSupplier) {
+        try {
+            TaskExecutionDetails executionDetails = executionDetailsSupplier.get();
+            return ExecutionDetailsDto.from(executionDetails);
+        } catch (TaskNotFoundException e) {
+            throw ErrorResponder.builder()
+                .message(String.format("%s can not be found", taskId.getValue()))
+                .statusCode(HttpStatus.NOT_FOUND_404)
+                .type(ErrorResponder.ErrorType.NOT_FOUND)
+                .haltError();
+        }
+    }
+
+    private Object cancel(Request req, Response response) {
+        TaskId taskId = getTaskId(req);
+        taskManager.cancel(taskId);
+        response.status(HttpStatus.NO_CONTENT_204);
+        return Constants.EMPTY_BODY;
+    }
+
+    private TaskId getTaskId(Request req) {
+        try {
+            String id = req.params("id");
+            return new TaskId(UUID.fromString(id));
+        } catch (Exception e) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .cause(e)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .message("Invalid task id")
+                .haltError();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/d9d73f80/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/ErrorResponder.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/ErrorResponder.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/ErrorResponder.java
index c87f0f9..b02883d 100644
--- a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/ErrorResponder.java
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/ErrorResponder.java
@@ -33,6 +33,7 @@ import spark.HaltException;
 public class ErrorResponder {
     public enum ErrorType {
         INVALID_ARGUMENT("InvalidArgument"),
+        NOT_FOUND("notFound"),
         WRONG_STATE("WrongState"),
         SERVER_ERROR("ServerError");
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/d9d73f80/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java
index f4eb420..02ebe50 100644
--- a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonExtractor.java
@@ -22,6 +22,7 @@ package org.apache.james.webadmin.utils;
 import java.io.IOException;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 
 public class JsonExtractor<Request> {
 
@@ -29,14 +30,15 @@ public class JsonExtractor<Request> {
     private final Class<Request> type;
 
     public JsonExtractor(Class<Request> type) {
-        this.objectMapper = new ObjectMapper();
+        this.objectMapper = new ObjectMapper()
+            .registerModule(new Jdk8Module());
         this.type = type;
     }
 
     public Request parse(String text) throws JsonExtractException {
         try {
             return objectMapper.readValue(text, type);
-        } catch (IOException e) {
+        } catch (IOException | IllegalArgumentException e) {
             throw new JsonExtractException(e);
         }
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/d9d73f80/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/routes/TasksRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/routes/TasksRoutesTest.java b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/routes/TasksRoutesTest.java
new file mode 100644
index 0000000..5403349
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/routes/TasksRoutesTest.java
@@ -0,0 +1,277 @@
+/****************************************************************
+ * 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.webadmin.routes;
+
+import static com.jayway.restassured.RestAssured.given;
+import static com.jayway.restassured.RestAssured.when;
+import static com.jayway.restassured.RestAssured.with;
+import static com.jayway.restassured.config.EncoderConfig.encoderConfig;
+import static com.jayway.restassured.config.RestAssuredConfig.newConfig;
+import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.james.metrics.logger.DefaultMetricFactory;
+import org.apache.james.task.MemoryTaskManager;
+import org.apache.james.task.Task;
+import org.apache.james.task.TaskId;
+import org.apache.james.task.TaskManager;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.WebAdminUtils;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Throwables;
+import com.jayway.restassured.RestAssured;
+import com.jayway.restassured.builder.RequestSpecBuilder;
+import com.jayway.restassured.http.ContentType;
+
+public class TasksRoutesTest {
+
+    private MemoryTaskManager taskManager;
+    private WebAdminServer webAdminServer;
+
+    @Before
+    public void setUp() throws Exception {
+        taskManager = new MemoryTaskManager();
+
+        webAdminServer = WebAdminUtils.createWebAdminServer(
+            new DefaultMetricFactory(),
+            new TasksRoutes(taskManager, new JsonTransformer()));
+
+        webAdminServer.configure(NO_CONFIGURATION);
+        webAdminServer.await();
+
+        RestAssured.requestSpecification = new RequestSpecBuilder()
+            .setContentType(ContentType.JSON)
+            .setAccept(ContentType.JSON)
+            .setBasePath(TasksRoutes.BASE)
+            .setPort(webAdminServer.getPort().get().getValue())
+            .setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)))
+            .build();
+    }
+
+    @After
+    public void tearDown() {
+        taskManager.stop();
+        webAdminServer.destroy();
+    }
+
+    @Test
+    public void listShouldReturnEmptyWhenNoTask() {
+        when()
+            .get()
+        .then()
+            .body("", hasSize(0));
+    }
+
+    @Test
+    public void listShouldReturnTaskDetailsWhenTaskInProgress() {
+        TaskId taskId = taskManager.submit(() -> {
+            await();
+            return Task.Result.COMPLETED;
+        });
+
+        when()
+            .get()
+        .then()
+            .statusCode(HttpStatus.OK_200)
+            .body("", hasSize(1))
+            .body("[0].status", is(TaskManager.Status.IN_PROGRESS.getValue()))
+            .body("[0].taskId", is(taskId.getValue().toString()))
+            .body("[0].class", is(not(empty())));
+    }
+
+    private void await() {
+        try {
+            new CountDownLatch(1).await();
+        } catch (InterruptedException e) {
+            Throwables.propagate(e);
+        }
+    }
+
+    @Test
+    public void listShouldListTaskWhenStatusFilter() {
+        TaskId taskId = taskManager.submit(() -> {
+            await();
+            return Task.Result.COMPLETED;
+        });
+
+        given()
+            .param("status", TaskManager.Status.IN_PROGRESS.getValue())
+        .when()
+            .get()
+        .then()
+            .statusCode(HttpStatus.OK_200)
+            .body("", hasSize(1))
+            .body("[0].status", is(TaskManager.Status.IN_PROGRESS.getValue()))
+            .body("[0].taskId", is(taskId.getValue().toString()))
+            .body("[0].type", is(Task.UNKNOWN));
+    }
+
+    @Test
+    public void listShouldReturnEmptyWhenNonMatchingStatusFilter() {
+        taskManager.submit(() -> {
+            await();
+            return Task.Result.COMPLETED;
+        });
+
+        given()
+            .param("status", TaskManager.Status.WAITING.getValue())
+        .when()
+            .get()
+        .then()
+            .statusCode(HttpStatus.OK_200)
+            .body("", hasSize(0));
+    }
+
+    @Test
+    public void getShouldReturnTaskDetails() {
+        TaskId taskId = taskManager.submit(() -> {
+            await();
+            return Task.Result.COMPLETED;
+        });
+
+        when()
+            .get("/" + taskId.getValue())
+        .then()
+            .statusCode(HttpStatus.OK_200)
+            .body("status", is("inProgress"));
+    }
+
+    @Test
+    public void getAwaitShouldAwaitTaskCompletion() {
+        TaskId taskId = taskManager.submit(() -> {
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+                throw Throwables.propagate(e);
+            }
+            return Task.Result.COMPLETED;
+        });
+
+        when()
+            .get("/" + taskId.getValue() + "/await")
+        .then()
+            .statusCode(HttpStatus.OK_200)
+            .body("status", is("completed"));
+    }
+
+    @Test
+    public void deleteShouldReturnOk() {
+        TaskId taskId = taskManager.submit(() -> {
+            await();
+            return Task.Result.COMPLETED;
+        });
+
+        when()
+            .delete("/" + taskId.getValue())
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+    }
+
+    @Test
+    public void deleteShouldCancelMatchingTask() {
+        TaskId taskId = taskManager.submit(() -> {
+            await();
+            return Task.Result.COMPLETED;
+        });
+
+        with()
+            .delete("/" + taskId.getValue());
+
+        when()
+            .get("/" + taskId.getValue())
+        .then()
+            .statusCode(HttpStatus.OK_200)
+            .body("status", is("canceled"));
+    }
+
+    @Test
+    public void getShouldReturnNotFoundWhenIdDoesNotExist() {
+        String taskId = UUID.randomUUID().toString();
+
+        when()
+            .get("/" + taskId)
+        .then()
+            .statusCode(HttpStatus.NOT_FOUND_404)
+            .body("statusCode", is(HttpStatus.NOT_FOUND_404))
+            .body("type", is("notFound"))
+            .body("message", is(String.format("%s can not be found", taskId)));
+    }
+
+    @Test
+    public void getShouldReturnErrorWhenInvalidId() {
+        String taskId = "invalid";
+
+        when()
+            .get("/" + taskId)
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .body("statusCode", is(HttpStatus.BAD_REQUEST_400))
+            .body("type", is("InvalidArgument"))
+            .body("message", is("Invalid task id"));
+    }
+
+    @Test
+    public void deleteShouldReturnOkWhenNonExistingId() {
+        String taskId = UUID.randomUUID().toString();
+
+        when()
+            .delete("/" + taskId)
+        .then()
+            .statusCode(HttpStatus.NO_CONTENT_204);
+    }
+
+    @Test
+    public void deleteShouldReturnAnErrorOnInvalidId() {
+        String taskId = "invalid";
+
+        when()
+            .delete("/" + taskId)
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .body("statusCode", is(HttpStatus.BAD_REQUEST_400))
+            .body("type", is("InvalidArgument"))
+            .body("message", is("Invalid task id"));
+    }
+
+    @Test
+    public void listShouldReturnErrorWhenNonExistingStatus() {
+        given()
+            .param("status", "invalid")
+            .get()
+        .then()
+            .statusCode(HttpStatus.BAD_REQUEST_400)
+            .body("statusCode", is(HttpStatus.BAD_REQUEST_400))
+            .body("type", is("InvalidArgument"))
+            .body("message", is("Invalid status query parameter"));
+    }
+
+}
\ 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


[09/21] james-project git commit: JAMES-2272 JSON transformer should be able to serialize ZonedDateTime

Posted by bt...@apache.org.
JAMES-2272 JSON transformer should be able to serialize ZonedDateTime


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

Branch: refs/heads/master
Commit: 1b7e8d74553fef6bf74df6598ad010a01dbc4b01
Parents: 4eeede9
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 14:29:44 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:03:36 2018 +0700

----------------------------------------------------------------------
 pom.xml                                                      | 2 +-
 server/protocols/webadmin/webadmin-core/pom.xml              | 4 ++++
 .../org/apache/james/webadmin/utils/JsonTransformer.java     | 8 +++++---
 3 files changed, 10 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/1b7e8d74/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index fdd34c0..2676c2e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1426,7 +1426,7 @@
             <dependency>
                 <groupId>com.fasterxml.jackson.datatype</groupId>
                 <artifactId>jackson-datatype-jsr310</artifactId>
-                <version>2.6.3</version>
+                <version>${jackson-databinding.version}</version>
             </dependency>
             <dependency>
                 <groupId>com.github.dpaukov</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/1b7e8d74/server/protocols/webadmin/webadmin-core/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/pom.xml b/server/protocols/webadmin/webadmin-core/pom.xml
index 32f8b5f..56bcda1 100644
--- a/server/protocols/webadmin/webadmin-core/pom.xml
+++ b/server/protocols/webadmin/webadmin-core/pom.xml
@@ -63,6 +63,10 @@
             <artifactId>jackson-datatype-jdk8</artifactId>
         </dependency>
         <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+        </dependency>
+        <dependency>
             <groupId>com.github.fge</groupId>
             <artifactId>throwing-lambdas</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/1b7e8d74/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
index 722f8ec..6fd8f8c 100644
--- a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
@@ -23,6 +23,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 
 import spark.ResponseTransformer;
 
@@ -31,9 +32,10 @@ public class JsonTransformer implements ResponseTransformer {
     private final ObjectMapper objectMapper;
 
     public JsonTransformer() {
-        objectMapper = new ObjectMapper();
-        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
-        objectMapper.registerModule(new Jdk8Module());
+        objectMapper = new ObjectMapper()
+            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
+            .registerModule(new Jdk8Module())
+            .registerModule(new JavaTimeModule());
     }
 
     @Override


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


[16/21] james-project git commit: JAMES-2272 Strong typing for Cassandra SchemaVersion

Posted by bt...@apache.org.
JAMES-2272 Strong typing for Cassandra SchemaVersion


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

Branch: refs/heads/master
Commit: 955afb0f21f9e52330d3c43e576384e9146e2c76
Parents: 7e95d7a
Author: benwa <bt...@linagora.com>
Authored: Wed Jan 3 14:33:13 2018 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:12:47 2018 +0700

----------------------------------------------------------------------
 .../migration/CassandraMigrationService.java    | 43 ++++++-----
 .../cassandra/migration/MigrationTask.java      | 17 +++--
 .../versions/CassandraSchemaVersionDAO.java     |  9 +--
 .../versions/CassandraSchemaVersionManager.java | 30 ++++----
 .../cassandra/versions/SchemaVersion.java       | 76 ++++++++++++++++++++
 .../CassandraMigrationServiceTest.java          | 27 +++----
 .../versions/CassandraSchemaVersionDAOTest.java |  8 +--
 .../CassandraSchemaVersionManagerTest.java      | 66 ++++-------------
 .../modules/mailbox/CassandraSessionModule.java | 12 ++--
 .../james/CassandraVersionCheckingTest.java     | 12 ++--
 .../modules/server/CassandraRoutesModule.java   | 13 ++--
 .../WebAdminServerIntegrationTest.java          |  8 +--
 .../webadmin/dto/CassandraVersionRequest.java   |  8 ++-
 .../webadmin/dto/CassandraVersionResponse.java  |  6 ++
 .../routes/CassandraMigrationRoutes.java        |  4 +-
 .../james/webadmin/dto/VersionRequestTest.java  | 31 ++++----
 .../routes/CassandraMigrationRoutesTest.java    | 19 ++---
 17 files changed, 217 insertions(+), 172 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
index 9c494e1..9ab1177 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
@@ -30,56 +30,55 @@ import javax.inject.Named;
 
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Preconditions;
-
 public class CassandraMigrationService {
     public static final String LATEST_VERSION = "latestVersion";
     private final CassandraSchemaVersionDAO schemaVersionDAO;
-    private final int latestVersion;
-    private final Map<Integer, Migration> allMigrationClazz;
+    private final SchemaVersion latestVersion;
+    private final Map<SchemaVersion, Migration> allMigrationClazz;
     private final Logger LOG = LoggerFactory.getLogger(CassandraMigrationService.class);
 
     @Inject
-    public CassandraMigrationService(CassandraSchemaVersionDAO schemaVersionDAO, Map<Integer, Migration> allMigrationClazz, @Named(LATEST_VERSION) int latestVersion) {
-        Preconditions.checkArgument(latestVersion >= 0, "The latest version must be positive");
+    public CassandraMigrationService(CassandraSchemaVersionDAO schemaVersionDAO, Map<SchemaVersion, Migration> allMigrationClazz, @Named(LATEST_VERSION) SchemaVersion latestVersion) {
         this.schemaVersionDAO = schemaVersionDAO;
         this.latestVersion = latestVersion;
         this.allMigrationClazz = allMigrationClazz;
     }
 
-    public Optional<Integer> getCurrentVersion() {
+    public Optional<SchemaVersion> getCurrentVersion() {
         return schemaVersionDAO.getCurrentSchemaVersion().join();
     }
 
-    public Optional<Integer> getLatestVersion() {
+    public Optional<SchemaVersion> getLatestVersion() {
         return Optional.of(latestVersion);
     }
 
-    public Migration upgradeToVersion(int newVersion) {
-        int currentVersion = getCurrentVersion().orElse(DEFAULT_VERSION);
+    public Migration upgradeToVersion(SchemaVersion newVersion) {
+        SchemaVersion currentVersion = getCurrentVersion().orElse(DEFAULT_VERSION);
         assertMigrationNeeded(newVersion, currentVersion);
 
-        Migration migrationCombination = IntStream.range(currentVersion, newVersion)
+        Migration migrationCombination = IntStream.range(currentVersion.getValue(), newVersion.getValue())
             .boxed()
+            .map(SchemaVersion::new)
             .map(this::validateVersionNumber)
             .map(this::toMigration)
             .reduce(Migration.IDENTITY, Migration::combine);
         return new MigrationTask(migrationCombination, newVersion);
     }
 
-    private void assertMigrationNeeded(int newVersion, int currentVersion) {
-        boolean needMigration = currentVersion < newVersion;
+    private void assertMigrationNeeded(SchemaVersion newVersion, SchemaVersion currentVersion) {
+        boolean needMigration = currentVersion.isBefore(newVersion);
         if (!needMigration) {
             throw new IllegalStateException("Current version is already up to date");
         }
     }
 
-    private Integer validateVersionNumber(Integer versionNumber) {
+    private SchemaVersion validateVersionNumber(SchemaVersion versionNumber) {
         if (!allMigrationClazz.containsKey(versionNumber)) {
-            String message = String.format("Can not migrate to %d. No migration class registered.", versionNumber);
+            String message = String.format("Can not migrate to %d. No migration class registered.", versionNumber.getValue());
             LOG.error(message);
             throw new NotImplementedException(message);
         }
@@ -90,11 +89,11 @@ public class CassandraMigrationService {
         return upgradeToVersion(latestVersion);
     }
 
-    private Migration toMigration(Integer version) {
+    private Migration toMigration(SchemaVersion version) {
         return () -> {
-            int newVersion = version + 1;
-            int currentVersion = getCurrentVersion().orElse(DEFAULT_VERSION);
-            if (currentVersion >= newVersion) {
+            SchemaVersion newVersion = version.next();
+            SchemaVersion currentVersion = getCurrentVersion().orElse(DEFAULT_VERSION);
+            if (currentVersion.isAfterOrEquals(newVersion)) {
                 return Migration.Result.PARTIAL;
             }
 
@@ -107,13 +106,13 @@ public class CassandraMigrationService {
         };
     }
 
-    private void throwMigrationException(int newVersion) {
+    private void throwMigrationException(SchemaVersion newVersion) {
         throw new MigrationException(failureMessage(newVersion));
     }
 
-    private String failureMessage(Integer newVersion) {
+    private String failureMessage(SchemaVersion newVersion) {
         return String.format("Migrating to version %d partially done. " +
-                "Please check logs for cause of failure and re-run this migration.", newVersion);
+                "Please check logs for cause of failure and re-run this migration.", newVersion.getValue());
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationTask.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationTask.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationTask.java
index 518b682..7fd3bdd 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationTask.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationTask.java
@@ -21,25 +21,28 @@ package org.apache.james.backends.cassandra.migration;
 
 import java.util.Optional;
 
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
+import org.apache.james.task.TaskExecutionDetails;
+
 public class MigrationTask implements Migration {
     public static final String CASSANDRA_MIGRATION = "CassandraMigration";
 
-    public static class Details {
-        private final int toVersion;
+    public static class Details implements TaskExecutionDetails.AdditionalInformation {
+        private final SchemaVersion toVersion;
 
-        public Details(int toVersion) {
+        public Details(SchemaVersion toVersion) {
             this.toVersion = toVersion;
         }
 
         public int getToVersion() {
-            return toVersion;
+            return toVersion.getValue();
         }
     }
 
     private final Migration migration;
-    private final int toVersion;
+    private final SchemaVersion toVersion;
 
-    public MigrationTask(Migration migration, int toVersion) {
+    public MigrationTask(Migration migration, SchemaVersion toVersion) {
         this.migration = migration;
         this.toVersion = toVersion;
     }
@@ -55,7 +58,7 @@ public class MigrationTask implements Migration {
     }
 
     @Override
-    public Optional<Object> details() {
+    public Optional<TaskExecutionDetails.AdditionalInformation> details() {
         return Optional.of(new Details(toVersion));
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java
index 83a16ba..23ca069 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAO.java
@@ -66,18 +66,19 @@ public class CassandraSchemaVersionDAO {
                 .value(VALUE, bindMarker(VALUE)));
     }
 
-    public CompletableFuture<Optional<Integer>> getCurrentSchemaVersion() {
+    public CompletableFuture<Optional<SchemaVersion>> getCurrentSchemaVersion() {
         return cassandraAsyncExecutor.execute(readVersionStatement.bind())
             .thenApply(resultSet -> cassandraUtils.convertToStream(resultSet)
                 .map(row -> row.getInt(VALUE))
-                .reduce(Math::max));
+                .reduce(Math::max))
+            .thenApply(i -> i.map(SchemaVersion::new));
     }
 
-    public CompletableFuture<Void> updateVersion(int newVersion) {
+    public CompletableFuture<Void> updateVersion(SchemaVersion newVersion) {
         return cassandraAsyncExecutor.executeVoid(
             writeVersionStatement.bind()
                 .setUUID(KEY, UUIDs.timeBased())
-                .setInt(VALUE, newVersion));
+                .setInt(VALUE, newVersion.getValue()));
     }
 }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java
index 42502e8..40b4a7d 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManager.java
@@ -33,14 +33,14 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 
 public class CassandraSchemaVersionManager {
-    public static final int MIN_VERSION = 2;
-    public static final int MAX_VERSION = 5;
-    public static final int DEFAULT_VERSION = 2;
+    public static final SchemaVersion MIN_VERSION = new SchemaVersion(2);
+    public static final SchemaVersion MAX_VERSION = new SchemaVersion(5);
+    public static final SchemaVersion DEFAULT_VERSION = MIN_VERSION;
 
     private static final Logger LOGGER = LoggerFactory.getLogger(CassandraSchemaVersionManager.class);
 
-    private final int minVersion;
-    private final int maxVersion;
+    private final SchemaVersion minVersion;
+    private final SchemaVersion maxVersion;
     private final CassandraSchemaVersionDAO schemaVersionDAO;
 
     public enum SchemaState {
@@ -56,10 +56,8 @@ public class CassandraSchemaVersionManager {
     }
 
     @VisibleForTesting
-    public CassandraSchemaVersionManager(CassandraSchemaVersionDAO schemaVersionDAO, int minVersion, int maxVersion) {
-        Preconditions.checkArgument(minVersion > 0, "minVersion needs to be strictly positive");
-        Preconditions.checkArgument(maxVersion > 0, "maxVersion needs to be strictly positive");
-        Preconditions.checkArgument(maxVersion >= minVersion,
+    public CassandraSchemaVersionManager(CassandraSchemaVersionDAO schemaVersionDAO, SchemaVersion minVersion, SchemaVersion maxVersion) {
+        Preconditions.checkArgument(maxVersion.isAfterOrEquals(minVersion),
             "maxVersion should not be inferior to minVersion");
 
         this.schemaVersionDAO = schemaVersionDAO;
@@ -67,7 +65,7 @@ public class CassandraSchemaVersionManager {
         this.maxVersion = maxVersion;
     }
 
-    public int computeVersion() {
+    public SchemaVersion computeVersion() {
         return schemaVersionDAO
             .getCurrentSchemaVersion()
             .join()
@@ -78,21 +76,21 @@ public class CassandraSchemaVersionManager {
             });
     }
 
-    public int getMinimumSupportedVersion() {
+    public SchemaVersion getMinimumSupportedVersion() {
         return minVersion;
     }
 
-    public int getMaximumSupportedVersion() {
+    public SchemaVersion getMaximumSupportedVersion() {
         return maxVersion;
     }
 
     public SchemaState computeSchemaState() {
-        int version = computeVersion();
-        if (version < minVersion) {
+        SchemaVersion version = computeVersion();
+        if (version.isBefore(minVersion)) {
             return TOO_OLD;
-        } else if (version < maxVersion) {
+        } else if (version.isBefore(maxVersion)) {
             return UPGRADABLE;
-        } else if (version == maxVersion) {
+        } else if (version.equals(maxVersion)) {
             return UP_TO_DATE;
         } else {
             return TOO_RECENT;

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/SchemaVersion.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/SchemaVersion.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/SchemaVersion.java
new file mode 100644
index 0000000..f1b3d41
--- /dev/null
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/versions/SchemaVersion.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.backends.cassandra.versions;
+
+import java.util.Objects;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+
+public class SchemaVersion {
+    private final int value;
+
+    public SchemaVersion(int value) {
+        Preconditions.checkArgument(value > 0, "version needs to be strictly positive");
+        this.value = value;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public boolean isAfterOrEquals(SchemaVersion other) {
+        return this.value >= other.value;
+    }
+
+    public SchemaVersion next() {
+        return new SchemaVersion(value + 1);
+    }
+
+    public SchemaVersion previous() {
+        return new SchemaVersion(value - 1);
+    }
+
+    public boolean isBefore(SchemaVersion other) {
+        return this.value < other.value;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof SchemaVersion) {
+            SchemaVersion that = (SchemaVersion) o;
+
+            return Objects.equals(this.value, that.value);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(value);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("version", value)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
index 5dea96b..4897800 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
@@ -36,6 +36,7 @@ import java.util.concurrent.Executors;
 
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -46,10 +47,10 @@ import com.datastax.driver.core.Session;
 import com.google.common.collect.ImmutableMap;
 
 public class CassandraMigrationServiceTest {
-    private static final int LATEST_VERSION = 3;
-    private static final int INTERMEDIARY_VERSION = 2;
-    private static final int CURRENT_VERSION = INTERMEDIARY_VERSION;
-    private static final int OLDER_VERSION = 1;
+    private static final SchemaVersion LATEST_VERSION = new SchemaVersion(3);
+    private static final SchemaVersion INTERMEDIARY_VERSION = new SchemaVersion(2);
+    private static final SchemaVersion CURRENT_VERSION = INTERMEDIARY_VERSION;
+    private static final SchemaVersion OLDER_VERSION = new SchemaVersion(1);
     private CassandraMigrationService testee;
     private CassandraSchemaVersionDAO schemaVersionDAO;
     private ExecutorService executorService;
@@ -63,7 +64,7 @@ public class CassandraMigrationServiceTest {
         schemaVersionDAO = mock(CassandraSchemaVersionDAO.class);
         successfulMigration = mock(Migration.class);
         when(successfulMigration.run()).thenReturn(Migration.Result.COMPLETED);
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+        Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder()
             .put(OLDER_VERSION, successfulMigration)
             .put(CURRENT_VERSION, successfulMigration)
             .put(LATEST_VERSION, successfulMigration)
@@ -127,7 +128,7 @@ public class CassandraMigrationServiceTest {
 
     @Test
     public void upgradeToVersionShouldThrowOnMissingVersion() throws Exception {
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+        Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder()
             .put(OLDER_VERSION, successfulMigration)
             .put(LATEST_VERSION, successfulMigration)
             .build();
@@ -142,7 +143,7 @@ public class CassandraMigrationServiceTest {
     @Test
     public void upgradeToVersionShouldUpdateIntermediarySuccessfulMigrationsInCaseOfError() throws Exception {
         try {
-            Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+            Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder()
                 .put(OLDER_VERSION, successfulMigration)
                 .put(INTERMEDIARY_VERSION, () -> Migration.Result.PARTIAL)
                 .put(LATEST_VERSION, successfulMigration)
@@ -164,7 +165,7 @@ public class CassandraMigrationServiceTest {
         when(migration1.run()).thenReturn(Migration.Result.PARTIAL);
         Migration migration2 = successfulMigration;
 
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+        Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder()
             .put(OLDER_VERSION, migration1)
             .put(CURRENT_VERSION, migration2)
             .build();
@@ -182,7 +183,7 @@ public class CassandraMigrationServiceTest {
         Migration migration2 = mock(Migration.class);
         when(migration2.run()).thenReturn(Migration.Result.COMPLETED);
 
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+        Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder()
             .put(OLDER_VERSION, migration1)
             .put(CURRENT_VERSION, migration2)
             .build();
@@ -200,20 +201,20 @@ public class CassandraMigrationServiceTest {
     }
 
     public static class InMemorySchemaDAO extends CassandraSchemaVersionDAO {
-        private int currentVersion;
+        private SchemaVersion currentVersion;
 
-        public InMemorySchemaDAO(int currentVersion) {
+        public InMemorySchemaDAO(SchemaVersion currentVersion) {
             super(mock(Session.class), null);
             this.currentVersion = currentVersion;
         }
 
         @Override
-        public CompletableFuture<Optional<Integer>> getCurrentSchemaVersion() {
+        public CompletableFuture<Optional<SchemaVersion>> getCurrentSchemaVersion() {
             return CompletableFuture.completedFuture(Optional.of(currentVersion));
         }
 
         @Override
-        public CompletableFuture<Void> updateVersion(int newVersion) {
+        public CompletableFuture<Void> updateVersion(SchemaVersion newVersion) {
             currentVersion = newVersion;
             return CompletableFuture.completedFuture(null);
         }

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java
index 5e61068..5bd83b5 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionDAOTest.java
@@ -59,7 +59,7 @@ public class CassandraSchemaVersionDAOTest {
 
     @Test
     public void getCurrentSchemaVersionShouldReturnVersionPresentInTheTable() {
-        int version = 42;
+        SchemaVersion version = new SchemaVersion(42);
 
         testee.updateVersion(version).join();
 
@@ -68,11 +68,11 @@ public class CassandraSchemaVersionDAOTest {
 
     @Test
     public void getCurrentSchemaVersionShouldBeIdempotent() {
-        int version = 42;
+        SchemaVersion version = new SchemaVersion(42);
 
-        testee.updateVersion(version + 1).join();
+        testee.updateVersion(version.next()).join();
         testee.updateVersion(version).join();
 
-        assertThat(testee.getCurrentSchemaVersion().join()).contains(version + 1);
+        assertThat(testee.getCurrentSchemaVersion().join()).contains(version.next());
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManagerTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManagerTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManagerTest.java
index 708c492..dfffddc 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManagerTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/versions/CassandraSchemaVersionManagerTest.java
@@ -19,10 +19,10 @@
 
 package org.apache.james.backends.cassandra.versions;
 
-import static org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.SchemaState.UP_TO_DATE;
-import static org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.SchemaState.UPGRADABLE;
 import static org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.SchemaState.TOO_OLD;
 import static org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.SchemaState.TOO_RECENT;
+import static org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.SchemaState.UPGRADABLE;
+import static org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.SchemaState.UP_TO_DATE;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -38,8 +38,8 @@ import org.junit.rules.ExpectedException;
 
 public class CassandraSchemaVersionManagerTest {
 
-    private final int minVersion = 2;
-    private final int maxVersion = 4;
+    private final SchemaVersion minVersion = new SchemaVersion(2);
+    private final SchemaVersion maxVersion = new SchemaVersion(4);
     private CassandraSchemaVersionDAO schemaVersionDAO;
 
     @Rule
@@ -52,7 +52,7 @@ public class CassandraSchemaVersionManagerTest {
 
     @Test
     public void computeSchemaStateShouldReturnTooOldWhenVersionIsLessThanMinVersion() {
-        int currentVersion = minVersion - 1;
+        SchemaVersion currentVersion = minVersion.previous();
 
         when(schemaVersionDAO.getCurrentSchemaVersion())
             .thenReturn(CompletableFuture.completedFuture(Optional.of(currentVersion)));
@@ -67,7 +67,7 @@ public class CassandraSchemaVersionManagerTest {
 
     @Test
     public void computeSchemaStateShouldReturnTooOldWhenVersionIsMoreThanMaxVersion() {
-        int currentVersion = maxVersion + 1;
+        SchemaVersion currentVersion = maxVersion.next();
 
         when(schemaVersionDAO.getCurrentSchemaVersion())
             .thenReturn(CompletableFuture.completedFuture(Optional.of(currentVersion)));
@@ -82,7 +82,7 @@ public class CassandraSchemaVersionManagerTest {
 
     @Test
     public void computeSchemaStateShouldReturnUpToDateWhenVersionEqualsMaxVersion() {
-        int currentVersion = maxVersion;
+        SchemaVersion currentVersion = maxVersion;
 
         when(schemaVersionDAO.getCurrentSchemaVersion())
             .thenReturn(CompletableFuture.completedFuture(Optional.of(currentVersion)));
@@ -97,7 +97,7 @@ public class CassandraSchemaVersionManagerTest {
 
     @Test
     public void computeSchemaStateShouldReturnUpgradableWhenVersionBetweenMinAnd() {
-        int currentVersion = maxVersion - 1;
+        SchemaVersion currentVersion = minVersion.next();
 
         when(schemaVersionDAO.getCurrentSchemaVersion())
             .thenReturn(CompletableFuture.completedFuture(Optional.of(currentVersion)));
@@ -111,51 +111,11 @@ public class CassandraSchemaVersionManagerTest {
     }
 
     @Test
-    public void constructorShouldThrowOnNegativeMinVersion() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        new CassandraSchemaVersionManager(
-            schemaVersionDAO,
-            -1,
-            maxVersion);
-    }
-
-    @Test
-    public void constructorShouldThrowOnZeroMinVersion() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        new CassandraSchemaVersionManager(
-            schemaVersionDAO,
-            0,
-            maxVersion);
-    }
-
-    @Test
-    public void constructorShouldThrowOnNegativeMaxVersion() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        new CassandraSchemaVersionManager(
-            schemaVersionDAO,
-            minVersion,
-            -1);
-    }
-
-    @Test
-    public void constructorShouldThrowOnZeroMaxVersion() {
-        expectedException.expect(IllegalArgumentException.class);
-
-        new CassandraSchemaVersionManager(
-            schemaVersionDAO,
-            minVersion,
-            0);
-    }
-
-    @Test
     public void constructorShouldThrowMinVersionIsSuperiorToMaxVersion() {
         expectedException.expect(IllegalArgumentException.class);
 
-        int minVersion = 4;
-        int maxVersion = 2;
+        SchemaVersion minVersion = new SchemaVersion(4);
+        SchemaVersion maxVersion = new SchemaVersion(2);
         new CassandraSchemaVersionManager(
             schemaVersionDAO,
             minVersion,
@@ -164,9 +124,9 @@ public class CassandraSchemaVersionManagerTest {
 
     @Test
     public void computeSchemaStateShouldReturnUpToDateWhenMinMaxAndVersionEquals() {
-        int minVersion = 4;
-        int maxVersion = 4;
-        int currentVersion = 4;
+        SchemaVersion minVersion = new SchemaVersion(4);
+        SchemaVersion maxVersion = new SchemaVersion(4);
+        SchemaVersion currentVersion = new SchemaVersion(4);
         when(schemaVersionDAO.getCurrentSchemaVersion())
             .thenReturn(CompletableFuture.completedFuture(Optional.of(currentVersion)));
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
index 31a856b..84a33db 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/CassandraSessionModule.java
@@ -192,13 +192,17 @@ public class CassandraSessionModule extends AbstractModule {
                 case TOO_OLD:
                     throw new IllegalStateException(
                         String.format("Current schema version is %d whereas minimum required version is %d. " +
-                            "Recommended version is %d", versionManager.computeVersion(), versionManager.getMinimumSupportedVersion(),
-                            versionManager.getMaximumSupportedVersion()));
+                            "Recommended version is %d",
+                            versionManager.computeVersion().getValue(),
+                            versionManager.getMinimumSupportedVersion().getValue(),
+                            versionManager.getMaximumSupportedVersion().getValue()));
                 case TOO_RECENT:
                     throw new IllegalStateException(
                         String.format("Current schema version is %d whereas the minimum supported version is %d. " +
-                            "Recommended version is %d.", versionManager.computeVersion(), versionManager.getMinimumSupportedVersion(),
-                            versionManager.getMaximumSupportedVersion()));
+                            "Recommended version is %d.",
+                            versionManager.computeVersion().getValue(),
+                            versionManager.getMinimumSupportedVersion().getValue(),
+                            versionManager.getMaximumSupportedVersion().getValue()));
                 case UP_TO_DATE:
                     LOGGER.info("Schema version is up-to-date");
                     return;

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java
index 9e71aa6..4544587 100644
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/CassandraVersionCheckingTest.java
@@ -32,6 +32,7 @@ import java.util.concurrent.CompletableFuture;
 
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
@@ -43,9 +44,8 @@ public class CassandraVersionCheckingTest {
 
     private static final String LOCAL_HOST = "127.0.0.1";
     private static final int IMAP_PORT = 1143;
-    private static final int MIN_VERSION = 2;
-    private static final int MAX_VERSION = 4;
-
+    private static final SchemaVersion MIN_VERSION = new SchemaVersion(2);
+    private static final SchemaVersion MAX_VERSION = new SchemaVersion(4);
 
     @ClassRule
     public static DockerCassandraRule cassandra = new DockerCassandraRule();
@@ -92,7 +92,7 @@ public class CassandraVersionCheckingTest {
     @Test
     public void serverShouldStartSuccessfullyWhenBetweenMinAndMaxVersion() throws Exception {
         when(versionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(MIN_VERSION + 1)));
+            .thenReturn(CompletableFuture.completedFuture(Optional.of(MIN_VERSION.next())));
 
         jamesServer = cassandraJmapTestRule.jmapServer(
             cassandra.getModule(),
@@ -122,7 +122,7 @@ public class CassandraVersionCheckingTest {
     @Test
     public void serverShouldNotStartWhenUnderMinVersion() throws Exception {
         when(versionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(MIN_VERSION - 1)));
+            .thenReturn(CompletableFuture.completedFuture(Optional.of(MIN_VERSION.previous())));
 
         jamesServer = cassandraJmapTestRule.jmapServer(
             cassandra.getModule(),
@@ -139,7 +139,7 @@ public class CassandraVersionCheckingTest {
     @Test
     public void serverShouldNotStartWhenAboveMaxVersion() throws Exception {
         when(versionDAO.getCurrentSchemaVersion())
-            .thenReturn(CompletableFuture.completedFuture(Optional.of(MAX_VERSION + 1)));
+            .thenReturn(CompletableFuture.completedFuture(Optional.of(MAX_VERSION.next())));
 
         jamesServer = cassandraJmapTestRule.jmapServer(
             cassandra.getModule(),

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java b/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
index 16b821b..1cf1f93 100644
--- a/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
+++ b/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
@@ -22,6 +22,7 @@ package org.apache.james.modules.server;
 import org.apache.james.backends.cassandra.migration.CassandraMigrationService;
 import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.apache.james.mailbox.cassandra.mail.migration.AttachmentMessageIdCreation;
 import org.apache.james.mailbox.cassandra.mail.migration.AttachmentV2Migration;
 import org.apache.james.webadmin.Routes;
@@ -34,9 +35,9 @@ import com.google.inject.multibindings.Multibinder;
 import com.google.inject.name.Names;
 
 public class CassandraRoutesModule extends AbstractModule {
-    private static final int FROM_V2_TO_V3 = 2;
-    private static final int FROM_V3_TO_V4 = 3;
-    private static final int FROM_V4_TO_V5 = 4;
+    private static final SchemaVersion FROM_V2_TO_V3 = new SchemaVersion(2);
+    private static final SchemaVersion FROM_V3_TO_V4 = new SchemaVersion(3);
+    private static final SchemaVersion FROM_V4_TO_V5 = new SchemaVersion(4);
 
     @Override
     protected void configure() {
@@ -46,13 +47,13 @@ public class CassandraRoutesModule extends AbstractModule {
         Multibinder<Routes> routesMultibinder = Multibinder.newSetBinder(binder(), Routes.class);
         routesMultibinder.addBinding().to(CassandraMigrationRoutes.class);
 
-        MapBinder<Integer, Migration> allMigrationClazzBinder = MapBinder.newMapBinder(binder(), Integer.class, Migration.class);
+        MapBinder<SchemaVersion, Migration> allMigrationClazzBinder = MapBinder.newMapBinder(binder(), SchemaVersion.class, Migration.class);
         allMigrationClazzBinder.addBinding(FROM_V2_TO_V3).toInstance(() -> Migration.Result.COMPLETED);
         allMigrationClazzBinder.addBinding(FROM_V3_TO_V4).to(AttachmentV2Migration.class);
         allMigrationClazzBinder.addBinding(FROM_V4_TO_V5).to(AttachmentMessageIdCreation.class);
 
-        bindConstant()
+        bind(SchemaVersion.class)
             .annotatedWith(Names.named(CassandraMigrationService.LATEST_VERSION))
-            .to(CassandraSchemaVersionManager.MAX_VERSION);
+            .toInstance(CassandraSchemaVersionManager.MAX_VERSION);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
index 981fbf5..fee4465 100644
--- a/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
+++ b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
@@ -227,14 +227,14 @@ public class WebAdminServerIntegrationTest {
         .then()
             .statusCode(HttpStatus.OK_200)
             .contentType(JSON_CONTENT_TYPE)
-            .body(is("{\"version\":" + CassandraSchemaVersionManager.MAX_VERSION + "}"));
+            .body(is("{\"version\":" + CassandraSchemaVersionManager.MAX_VERSION.getValue() + "}"));
     }
 
     @Test
     public void postShouldDoMigrationAndUpdateCurrentVersion() throws Exception {
         String taskId = with()
             .port(webAdminGuiceProbe.getWebAdminPort())
-            .body(String.valueOf(CassandraSchemaVersionManager.MAX_VERSION))
+            .body(String.valueOf(CassandraSchemaVersionManager.MAX_VERSION.getValue()))
         .post(UPGRADE_VERSION)
             .jsonPath()
             .get("taskId");
@@ -250,7 +250,7 @@ public class WebAdminServerIntegrationTest {
         .then()
             .statusCode(HttpStatus.OK_200)
             .contentType(JSON_CONTENT_TYPE)
-            .body(is("{\"version\":" + CassandraSchemaVersionManager.MAX_VERSION + "}"));
+            .body(is("{\"version\":" + CassandraSchemaVersionManager.MAX_VERSION.getValue() + "}"));
     }
 
     @Test
@@ -272,7 +272,7 @@ public class WebAdminServerIntegrationTest {
         .then()
             .statusCode(HttpStatus.OK_200)
             .contentType(JSON_CONTENT_TYPE)
-            .body(is("{\"version\":" + CassandraSchemaVersionManager.MAX_VERSION + "}"));
+            .body(is("{\"version\":" + CassandraSchemaVersionManager.MAX_VERSION.getValue() + "}"));
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/dto/CassandraVersionRequest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/dto/CassandraVersionRequest.java b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/dto/CassandraVersionRequest.java
index 5eaef46..73e4ca5 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/dto/CassandraVersionRequest.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/dto/CassandraVersionRequest.java
@@ -19,6 +19,8 @@
 
 package org.apache.james.webadmin.dto;
 
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
+
 import com.google.common.base.Preconditions;
 
 public class CassandraVersionRequest {
@@ -30,11 +32,11 @@ public class CassandraVersionRequest {
     private final int value;
 
     private CassandraVersionRequest(int value) {
-        Preconditions.checkArgument(value >= 0);
+        Preconditions.checkArgument(value > 0);
         this.value = value;
     }
 
-    public int getValue() {
-        return value;
+    public SchemaVersion getValue() {
+        return new SchemaVersion(value);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/dto/CassandraVersionResponse.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/dto/CassandraVersionResponse.java b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/dto/CassandraVersionResponse.java
index 34e98a8..cc07c7c 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/dto/CassandraVersionResponse.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/dto/CassandraVersionResponse.java
@@ -21,8 +21,14 @@ package org.apache.james.webadmin.dto;
 
 import java.util.Optional;
 
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
+
 public class CassandraVersionResponse {
 
+    public static CassandraVersionResponse from(Optional<SchemaVersion> schemaVersion) {
+        return new CassandraVersionResponse(schemaVersion.map(SchemaVersion::getValue));
+    }
+
     private final Optional<Integer> version;
 
     public CassandraVersionResponse(Optional<Integer> version) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
index 4ae87ed..d30b9c5 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
@@ -167,7 +167,7 @@ public class CassandraMigrationRoutes implements Routes {
         @ApiResponse(code = HttpStatus.OK_200, message = "The latest version of the schema", response = CassandraVersionResponse.class)
     })
     public CassandraVersionResponse getCassandraLatestVersion() {
-        return new CassandraVersionResponse(cassandraMigrationService.getLatestVersion());
+        return CassandraVersionResponse.from(cassandraMigrationService.getLatestVersion());
     }
 
     @GET
@@ -176,6 +176,6 @@ public class CassandraMigrationRoutes implements Routes {
         @ApiResponse(code = HttpStatus.OK_200, message = "The current version of the schema", response = CassandraVersionResponse.class)
     })
     public CassandraVersionResponse getCassandraCurrentVersion() {
-        return new CassandraVersionResponse(cassandraMigrationService.getCurrentVersion());
+        return CassandraVersionResponse.from(cassandraMigrationService.getCurrentVersion());
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/dto/VersionRequestTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/dto/VersionRequestTest.java b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/dto/VersionRequestTest.java
index 48ce134..228120b 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/dto/VersionRequestTest.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/dto/VersionRequestTest.java
@@ -20,48 +20,41 @@
 package org.apache.james.webadmin.dto;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import org.junit.Rule;
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 
 public class VersionRequestTest {
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
     @Test
     public void parseShouldThrowWhenNullVersion() throws Exception {
-        expectedException.expect(NullPointerException.class);
-
-        CassandraVersionRequest.parse(null);
+        assertThatThrownBy(() -> CassandraVersionRequest.parse(null))
+            .isInstanceOf(NullPointerException.class);
     }
 
     @Test
     public void parseShouldThrowWhenNonIntegerVersion() throws Exception {
-        expectedException.expect(IllegalArgumentException.class);
-
-        CassandraVersionRequest.parse("NoInt");
+        assertThatThrownBy(() -> CassandraVersionRequest.parse("NoInt"))
+            .isInstanceOf(IllegalArgumentException.class);
     }
 
     @Test
     public void parseShouldThrowWhenNegativeVersion() throws Exception {
-        expectedException.expect(IllegalArgumentException.class);
-
-        CassandraVersionRequest.parse("-1");
+        assertThatThrownBy(() -> CassandraVersionRequest.parse("-1"))
+            .isInstanceOf(IllegalArgumentException.class);
     }
 
     @Test
-    public void parseShouldAcceptZeroVersion() throws Exception {
-        CassandraVersionRequest cassandraVersionRequest = CassandraVersionRequest.parse("0");
-
-        assertThat(cassandraVersionRequest.getValue()).isEqualTo(0);
+    public void parseShouldThrowWhenZeroVersion() throws Exception {
+        assertThatThrownBy(() -> CassandraVersionRequest.parse("0"))
+            .isInstanceOf(IllegalArgumentException.class);
     }
 
     @Test
     public void parseShouldParseTheVersionValue() throws Exception {
         CassandraVersionRequest cassandraVersionRequest = CassandraVersionRequest.parse("1");
 
-        assertThat(cassandraVersionRequest.getValue()).isEqualTo(1);
+        assertThat(cassandraVersionRequest.getValue()).isEqualTo(new SchemaVersion(1));
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/955afb0f/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
index 0cc9d9c..1372c9b 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
@@ -44,6 +44,7 @@ import org.apache.james.backends.cassandra.migration.CassandraMigrationService;
 import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.backends.cassandra.migration.MigrationTask;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
 import org.apache.james.metrics.logger.DefaultMetricFactory;
 import org.apache.james.task.MemoryTaskManager;
 import org.apache.james.webadmin.WebAdminServer;
@@ -61,9 +62,9 @@ import com.jayway.restassured.builder.RequestSpecBuilder;
 import com.jayway.restassured.http.ContentType;
 
 public class CassandraMigrationRoutesTest {
-    private static final Integer LATEST_VERSION = 3;
-    private static final Integer CURRENT_VERSION = 2;
-    private static final Integer OLDER_VERSION = 1;
+    private static final SchemaVersion LATEST_VERSION = new SchemaVersion(3);
+    private static final SchemaVersion CURRENT_VERSION = new SchemaVersion(2);
+    private static final SchemaVersion OLDER_VERSION = new SchemaVersion(1);
     private WebAdminServer webAdminServer;
     private CassandraSchemaVersionDAO schemaVersionDAO;
     private MemoryTaskManager taskManager;
@@ -72,7 +73,7 @@ public class CassandraMigrationRoutesTest {
         Migration successfulMigration = mock(Migration.class);
         when(successfulMigration.run()).thenReturn(Migration.Result.COMPLETED);
 
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+        Map<SchemaVersion, Migration> allMigrationClazz = ImmutableMap.<SchemaVersion, Migration>builder()
             .put(OLDER_VERSION, successfulMigration)
             .put(CURRENT_VERSION, successfulMigration)
             .put(LATEST_VERSION, successfulMigration)
@@ -124,7 +125,7 @@ public class CassandraMigrationRoutesTest {
                 .jsonPath()
                 .getInt("version");
 
-        assertThat(version).isEqualTo(CURRENT_VERSION);
+        assertThat(version).isEqualTo(CURRENT_VERSION.getValue());
     }
 
     @Test
@@ -140,7 +141,7 @@ public class CassandraMigrationRoutesTest {
                 .jsonPath()
                 .getInt("version");
 
-        assertThat(version).isEqualTo(LATEST_VERSION);
+        assertThat(version).isEqualTo(LATEST_VERSION.getValue());
     }
 
     @Ignore
@@ -182,7 +183,7 @@ public class CassandraMigrationRoutesTest {
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
 
         String taskId = with()
-            .body(String.valueOf(CURRENT_VERSION))
+            .body(String.valueOf(CURRENT_VERSION.getValue()))
         .post("/upgrade")
             .jsonPath()
             .get("taskId");
@@ -204,7 +205,7 @@ public class CassandraMigrationRoutesTest {
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
 
         Map<String, Object> errors = given()
-            .body(String.valueOf(OLDER_VERSION))
+            .body(String.valueOf(OLDER_VERSION.getValue()))
         .with()
             .post("/upgrade")
         .then()
@@ -272,7 +273,7 @@ public class CassandraMigrationRoutesTest {
             .body("status", is("completed"))
             .body("taskId", is(notNullValue()))
             .body("type", is(MigrationTask.CASSANDRA_MIGRATION))
-            .body("additionalInformation.toVersion", is(LATEST_VERSION))
+            .body("additionalInformation.toVersion", is(LATEST_VERSION.getValue()))
             .body("startedDate", is(notNullValue()))
             .body("submitDate", is(notNullValue()))
             .body("completedDate", is(notNullValue()));


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


[11/21] james-project git commit: JAMES-2272 Docs: Correct webadmin webpage generation

Posted by bt...@apache.org.
JAMES-2272 Docs: Correct webadmin webpage generation


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

Branch: refs/heads/master
Commit: 45eec2eca065146ab53d43f41a6c4de4268476ec
Parents: b1a7139
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 20 14:11:12 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:12:42 2018 +0700

----------------------------------------------------------------------
 src/site/markdown/server/manage-webadmin.md | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/45eec2ec/src/site/markdown/server/manage-webadmin.md
----------------------------------------------------------------------
diff --git a/src/site/markdown/server/manage-webadmin.md b/src/site/markdown/server/manage-webadmin.md
index 1484d21..e0f59af 100644
--- a/src/site/markdown/server/manage-webadmin.md
+++ b/src/site/markdown/server/manage-webadmin.md
@@ -8,12 +8,15 @@ The web administration supports for now the CRUD operations on the domains,the u
 Please also note **webadmin** is only enabled with **Guice**. You can not use it when using James with **Spring**, as the required injections are not implemented.
 
 In case of any error, the system will return an error message which is json format like this:
+
+```
 {
     statusCode: <error_code>,
     type: <error_type>,
     message: <the_error_message>
     cause: <the_detail_message_from_throwable>
 }
+```
 
 ## Administrating domains
 


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


[02/21] james-project git commit: JAMES-2272 Allow adding details to tasks

Posted by bt...@apache.org.
JAMES-2272 Allow adding details to tasks

A default impelmentation is provided to keep lambda instanciation possible.


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

Branch: refs/heads/master
Commit: 97cf4305ba50e9b549086e157f7fe9e00aeb8da5
Parents: 1f6f9be
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 11:42:10 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:00:43 2018 +0700

----------------------------------------------------------------------
 .../src/main/java/org/apache/james/task/Task.java    | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/97cf4305/server/task/src/main/java/org/apache/james/task/Task.java
----------------------------------------------------------------------
diff --git a/server/task/src/main/java/org/apache/james/task/Task.java b/server/task/src/main/java/org/apache/james/task/Task.java
index fdb6878..fcfc8af 100644
--- a/server/task/src/main/java/org/apache/james/task/Task.java
+++ b/server/task/src/main/java/org/apache/james/task/Task.java
@@ -20,6 +20,7 @@
 package org.apache.james.task;
 
 import java.util.Arrays;
+import java.util.Optional;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -75,4 +76,18 @@ public interface Task {
      */
     Result run();
 
+
+    default String type() {
+        return UNKNOWN;
+    }
+
+    default Optional<Object> details() {
+        return Optional.empty();
+    }
+
+    String TASK_ID = "taskId";
+    String TASK_TYPE = "taskType";
+    String TASK_DETAILS = "taskDetails";
+
+    String UNKNOWN = "unknown";
 }


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


[05/21] james-project git commit: JAMES-2272 Adding a TaskManager API

Posted by bt...@apache.org.
JAMES-2272 Adding a TaskManager API


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

Branch: refs/heads/master
Commit: fbce4b0bfbce1c8b1abc73d1c114744d3b0539ff
Parents: 97cf430
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 11:43:25 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:03:35 2018 +0700

----------------------------------------------------------------------
 .../main/java/org/apache/james/task/Task.java   |   2 +-
 .../apache/james/task/TaskExecutionDetails.java | 164 +++++++++++++++++++
 .../main/java/org/apache/james/task/TaskId.java |  64 ++++++++
 .../java/org/apache/james/task/TaskManager.java |  63 +++++++
 .../james/task/TaskNotFoundException.java       |  23 +++
 .../java/org/apache/james/task/TaskIdTest.java  |  34 ++++
 6 files changed, 349 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/fbce4b0b/server/task/src/main/java/org/apache/james/task/Task.java
----------------------------------------------------------------------
diff --git a/server/task/src/main/java/org/apache/james/task/Task.java b/server/task/src/main/java/org/apache/james/task/Task.java
index fcfc8af..82b7670 100644
--- a/server/task/src/main/java/org/apache/james/task/Task.java
+++ b/server/task/src/main/java/org/apache/james/task/Task.java
@@ -81,7 +81,7 @@ public interface Task {
         return UNKNOWN;
     }
 
-    default Optional<Object> details() {
+    default Optional<TaskExecutionDetails.AdditionalInformation> details() {
         return Optional.empty();
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/fbce4b0b/server/task/src/main/java/org/apache/james/task/TaskExecutionDetails.java
----------------------------------------------------------------------
diff --git a/server/task/src/main/java/org/apache/james/task/TaskExecutionDetails.java b/server/task/src/main/java/org/apache/james/task/TaskExecutionDetails.java
new file mode 100644
index 0000000..0122fa7
--- /dev/null
+++ b/server/task/src/main/java/org/apache/james/task/TaskExecutionDetails.java
@@ -0,0 +1,164 @@
+/****************************************************************
+ * 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.task;
+
+import java.time.ZonedDateTime;
+import java.util.Optional;
+
+import com.google.common.base.Preconditions;
+
+public class TaskExecutionDetails {
+
+    public interface AdditionalInformation {
+
+    }
+
+    public static TaskExecutionDetails from(Task task, TaskId id) {
+        return new TaskExecutionDetails(
+            id,
+            task.type(),
+            TaskManager.Status.WAITING,
+            task.details(),
+            Optional.of(ZonedDateTime.now()),
+            Optional.empty(),
+            Optional.empty(),
+            Optional.empty(),
+            Optional.empty());
+    }
+
+    private final TaskId taskId;
+    private final String type;
+    private final TaskManager.Status status;
+    private final Optional<AdditionalInformation> additionalInformation;
+    private final Optional<ZonedDateTime> submitDate;
+    private final Optional<ZonedDateTime> startedDate;
+    private final Optional<ZonedDateTime> completedDate;
+    private final Optional<ZonedDateTime> canceledDate;
+    private final Optional<ZonedDateTime> failedDate;
+
+    public TaskExecutionDetails(TaskId taskId, String type, TaskManager.Status status,
+                                Optional<AdditionalInformation> additionalInformation,
+                                Optional<ZonedDateTime> submitDate, Optional<ZonedDateTime> startedDate,
+                                Optional<ZonedDateTime> completedDate, Optional<ZonedDateTime> canceledDate,
+                                Optional<ZonedDateTime> failedDate) {
+        this.taskId = taskId;
+        this.type = type;
+        this.status = status;
+        this.additionalInformation = additionalInformation;
+        this.submitDate = submitDate;
+        this.startedDate = startedDate;
+        this.completedDate = completedDate;
+        this.canceledDate = canceledDate;
+        this.failedDate = failedDate;
+    }
+
+    public TaskId getTaskId() {
+        return taskId;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public TaskManager.Status getStatus() {
+        return status;
+    }
+
+    public Optional<AdditionalInformation> getAdditionalInformation() {
+        return additionalInformation;
+    }
+
+    public Optional<ZonedDateTime> getSubmitDate() {
+        return submitDate;
+    }
+
+    public Optional<ZonedDateTime> getStartedDate() {
+        return startedDate;
+    }
+
+    public Optional<ZonedDateTime> getCompletedDate() {
+        return completedDate;
+    }
+
+    public Optional<ZonedDateTime> getCanceledDate() {
+        return canceledDate;
+    }
+
+    public Optional<ZonedDateTime> getFailedDate() {
+        return failedDate;
+    }
+
+    public TaskExecutionDetails start() {
+        Preconditions.checkState(status == TaskManager.Status.WAITING);
+        return new TaskExecutionDetails(
+            taskId,
+            type,
+            TaskManager.Status.IN_PROGRESS,
+            additionalInformation,
+            submitDate,
+            Optional.of(ZonedDateTime.now()),
+            Optional.empty(),
+            Optional.empty(),
+            Optional.empty());
+    }
+
+    public TaskExecutionDetails completed() {
+        Preconditions.checkState(status == TaskManager.Status.IN_PROGRESS);
+        return new TaskExecutionDetails(
+            taskId,
+            type,
+            TaskManager.Status.COMPLETED,
+            additionalInformation,
+            submitDate,
+            startedDate,
+            Optional.of(ZonedDateTime.now()),
+            Optional.empty(),
+            Optional.empty());
+    }
+
+    public TaskExecutionDetails failed() {
+        Preconditions.checkState(status == TaskManager.Status.IN_PROGRESS);
+        return new TaskExecutionDetails(
+            taskId,
+            type,
+            TaskManager.Status.FAILED,
+            additionalInformation,
+            submitDate,
+            startedDate,
+            Optional.empty(),
+            Optional.empty(),
+            Optional.of(ZonedDateTime.now()));
+    }
+
+    public TaskExecutionDetails cancel() {
+        Preconditions.checkState(status == TaskManager.Status.IN_PROGRESS
+            || status == TaskManager.Status.WAITING);
+        return new TaskExecutionDetails(
+            taskId,
+            type,
+            TaskManager.Status.CANCELLED,
+            additionalInformation,
+            submitDate,
+            startedDate,
+            Optional.empty(),
+            Optional.of(ZonedDateTime.now()),
+            Optional.empty());
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/fbce4b0b/server/task/src/main/java/org/apache/james/task/TaskId.java
----------------------------------------------------------------------
diff --git a/server/task/src/main/java/org/apache/james/task/TaskId.java b/server/task/src/main/java/org/apache/james/task/TaskId.java
new file mode 100644
index 0000000..4b66feb
--- /dev/null
+++ b/server/task/src/main/java/org/apache/james/task/TaskId.java
@@ -0,0 +1,64 @@
+/****************************************************************
+ * 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.task;
+
+import java.util.Objects;
+import java.util.UUID;
+
+import com.google.common.base.MoreObjects;
+
+public class TaskId {
+
+    public static TaskId generateTaskId() {
+        return new TaskId(UUID.randomUUID());
+    }
+
+    private final UUID value;
+
+    public TaskId(UUID value) {
+        this.value = value;
+    }
+
+    public UUID getValue() {
+        return value;
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        if (o instanceof TaskId) {
+            TaskId taskId = (TaskId) o;
+
+            return Objects.equals(this.value, taskId.value);
+        }
+        return false;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(value);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("value", value)
+            .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/fbce4b0b/server/task/src/main/java/org/apache/james/task/TaskManager.java
----------------------------------------------------------------------
diff --git a/server/task/src/main/java/org/apache/james/task/TaskManager.java b/server/task/src/main/java/org/apache/james/task/TaskManager.java
new file mode 100644
index 0000000..a3fabc3
--- /dev/null
+++ b/server/task/src/main/java/org/apache/james/task/TaskManager.java
@@ -0,0 +1,63 @@
+/****************************************************************
+ * 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.task;
+
+import java.util.Arrays;
+import java.util.List;
+
+public interface TaskManager {
+    enum Status {
+        WAITING("waiting"),
+        IN_PROGRESS("inProgress"),
+        COMPLETED("completed"),
+        CANCELLED("canceled"),
+        FAILED("failed");
+
+        public static Status fromString(String value) {
+            return Arrays.stream(values())
+                .filter(status -> status.value.equalsIgnoreCase(value))
+                .findFirst()
+                .orElseThrow(() -> new IllegalArgumentException(
+                    String.format("Unknown status value '%s'", value)));
+        }
+
+        private final String value;
+
+        Status(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+
+    TaskId submit(Task task);
+
+    TaskExecutionDetails getExecutionDetails(TaskId id);
+
+    List<TaskExecutionDetails> list();
+
+    List<TaskExecutionDetails> list(Status status);
+
+    void cancel(TaskId id);
+
+    TaskExecutionDetails await(TaskId id);
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/fbce4b0b/server/task/src/main/java/org/apache/james/task/TaskNotFoundException.java
----------------------------------------------------------------------
diff --git a/server/task/src/main/java/org/apache/james/task/TaskNotFoundException.java b/server/task/src/main/java/org/apache/james/task/TaskNotFoundException.java
new file mode 100644
index 0000000..cec026a
--- /dev/null
+++ b/server/task/src/main/java/org/apache/james/task/TaskNotFoundException.java
@@ -0,0 +1,23 @@
+/****************************************************************
+ * 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.task;
+
+public class TaskNotFoundException extends RuntimeException {
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/fbce4b0b/server/task/src/test/java/org/apache/james/task/TaskIdTest.java
----------------------------------------------------------------------
diff --git a/server/task/src/test/java/org/apache/james/task/TaskIdTest.java b/server/task/src/test/java/org/apache/james/task/TaskIdTest.java
new file mode 100644
index 0000000..c1f378a
--- /dev/null
+++ b/server/task/src/test/java/org/apache/james/task/TaskIdTest.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * 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.task;
+
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class TaskIdTest {
+
+    @Test
+    public void taskIdShouldMatchBeanContract() {
+        EqualsVerifier.forClass(TaskId.class)
+            .allFieldsShouldBeUsed()
+            .verify();
+    }
+}
\ 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


[03/21] james-project git commit: JAMES-2272 Add onComplete onFailure Result composer

Posted by bt...@apache.org.
JAMES-2272 Add onComplete onFailure Result composer

This make code more fluent.


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

Branch: refs/heads/master
Commit: 1f6f9be716cba7a9783e6382687c11fe94ac22a4
Parents: b87d49c
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 11:19:03 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:00:43 2018 +0700

----------------------------------------------------------------------
 .../main/java/org/apache/james/task/Task.java   |  36 ++++++-
 .../java/org/apache/james/task/TaskTest.java    | 100 +++++++++++++++++++
 2 files changed, 135 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/1f6f9be7/server/task/src/main/java/org/apache/james/task/Task.java
----------------------------------------------------------------------
diff --git a/server/task/src/main/java/org/apache/james/task/Task.java b/server/task/src/main/java/org/apache/james/task/Task.java
index 87ce233..fdb6878 100644
--- a/server/task/src/main/java/org/apache/james/task/Task.java
+++ b/server/task/src/main/java/org/apache/james/task/Task.java
@@ -19,11 +19,45 @@
 
 package org.apache.james.task;
 
+import java.util.Arrays;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 public interface Task {
+    Logger LOGGER = LoggerFactory.getLogger(Task.class);
+
+    interface Operation {
+        void run();
+    }
 
     enum Result {
         COMPLETED,
-        PARTIAL
+        PARTIAL;
+
+        public Result onComplete(Operation... operation) {
+            try {
+                if (this == COMPLETED) {
+                    run(operation);
+                }
+                return this;
+            } catch (Exception e) {
+                LOGGER.error("Error while executing operation", e);
+                return PARTIAL;
+            }
+        }
+
+        public Result onFailure(Operation... operation) {
+            if (this == PARTIAL) {
+                run(operation);
+            }
+            return this;
+        }
+
+        private void run(Operation... operation) {
+            Arrays.stream(operation)
+                .forEach(Operation::run);
+        }
     }
 
     static Result combine(Result result1, Result result2) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/1f6f9be7/server/task/src/test/java/org/apache/james/task/TaskTest.java
----------------------------------------------------------------------
diff --git a/server/task/src/test/java/org/apache/james/task/TaskTest.java b/server/task/src/test/java/org/apache/james/task/TaskTest.java
index 55ec2f4..0a7a005 100644
--- a/server/task/src/test/java/org/apache/james/task/TaskTest.java
+++ b/server/task/src/test/java/org/apache/james/task/TaskTest.java
@@ -20,6 +20,9 @@
 package org.apache.james.task;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.junit.Test;
 
@@ -49,4 +52,101 @@ public class TaskTest {
             .isEqualTo(Task.Result.PARTIAL);
     }
 
+
+    @Test
+    public void onCompleteShouldExecuteOperationWhenCompleted() {
+        AtomicInteger atomicInteger = new AtomicInteger(0);
+
+        Task.Result.COMPLETED
+            .onComplete(atomicInteger::incrementAndGet);
+
+        assertThat(atomicInteger.get())
+            .isEqualTo(1);
+    }
+
+    @Test
+    public void onFailureShouldNotExecuteOperationWhenCompleted() {
+        AtomicInteger atomicInteger = new AtomicInteger(0);
+
+        Task.Result.COMPLETED
+            .onFailure(atomicInteger::incrementAndGet);
+
+        assertThat(atomicInteger.get())
+            .isEqualTo(0);
+    }
+
+    @Test
+    public void onCompleteShouldNotExecuteOperationWhenPartial() {
+        AtomicInteger atomicInteger = new AtomicInteger(0);
+
+        Task.Result.PARTIAL
+            .onComplete(atomicInteger::incrementAndGet);
+
+        assertThat(atomicInteger.get())
+            .isEqualTo(0);
+    }
+
+    @Test
+    public void onFailureShouldExecuteOperationWhenPartial() {
+        AtomicInteger atomicInteger = new AtomicInteger(0);
+
+        Task.Result.PARTIAL
+            .onFailure(atomicInteger::incrementAndGet);
+
+        assertThat(atomicInteger.get())
+            .isEqualTo(1);
+    }
+
+    @Test
+    public void onCompleteShouldReturnPartialWhenPartial() {
+        assertThat(
+            Task.Result.PARTIAL
+                .onComplete(() -> {}))
+            .isEqualTo(Task.Result.PARTIAL);
+    }
+
+    @Test
+    public void onFailureShouldReturnCompletedWhenCompleted() {
+        assertThat(
+            Task.Result.COMPLETED
+                .onFailure(() -> {}))
+            .isEqualTo(Task.Result.COMPLETED);
+    }
+
+    @Test
+    public void onCompleteShouldReturnCompletedWhenCompleted() {
+        assertThat(
+            Task.Result.COMPLETED
+                .onComplete(() -> {}))
+            .isEqualTo(Task.Result.COMPLETED);
+    }
+
+    @Test
+    public void onFailureShouldReturnPartialWhenPartial() {
+        assertThat(
+            Task.Result.PARTIAL
+                .onFailure(() -> {}))
+            .isEqualTo(Task.Result.PARTIAL);
+    }
+
+    @Test
+    public void onCompleteShouldReturnPartialWhenOperationThrows() {
+        assertThat(
+            Task.Result.COMPLETED
+                .onComplete(() -> {
+                    throw new RuntimeException();
+                }))
+            .isEqualTo(Task.Result.PARTIAL);
+    }
+
+    @Test
+    public void onFailureShouldPreserveExceptions() {
+        assertThatThrownBy(() ->
+            Task.Result.PARTIAL
+                .onFailure(() -> {
+                    throw new RuntimeException();
+                }))
+            .isInstanceOf(RuntimeException.class);
+    }
+
 }
\ 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


[19/21] james-project git commit: JAMES-2276 Documentation site: typos and broken links

Posted by bt...@apache.org.
JAMES-2276 Documentation site: typos and broken links


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

Branch: refs/heads/master
Commit: 7d15ef0e689266e7081cda43730bcfbfc68f02a1
Parents: fe9c625
Author: mors741 <e....@bpcbt.com>
Authored: Sun Dec 31 12:01:13 2017 +0300
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:12:47 2018 +0700

----------------------------------------------------------------------
 src/site/xdoc/contribute.xml              |  4 ++--
 src/site/xdoc/documentation.xml           |  2 +-
 src/site/xdoc/mailet/ai/index.xml         |  2 +-
 src/site/xdoc/mailet/api/index.xml        | 12 ++++++------
 src/site/xdoc/mailet/crypto/index.xml     |  4 ++--
 src/site/xdoc/mailet/index.xml            |  2 +-
 src/site/xdoc/mpt/index.xml               |  4 ++--
 src/site/xdoc/protocols/pop3.xml          |  2 +-
 src/site/xdoc/protocols/smtp.xml          |  2 +-
 src/site/xdoc/server/feature-security.xml |  2 +-
 src/site/xdoc/support.xml                 |  2 +-
 11 files changed, 19 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/contribute.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/contribute.xml b/src/site/xdoc/contribute.xml
index 7783cfc..4a89203 100644
--- a/src/site/xdoc/contribute.xml
+++ b/src/site/xdoc/contribute.xml
@@ -121,12 +121,12 @@
       </p>
 
       <p>
-        The reason for these rules is so that commiters can easily see
+        The reason for these rules is so that committers can easily see
         what you are trying to achieve,
         it is their responsibility to manage the code and review submissions,
         if you make it easy for them to see what you are doing your
         patch is more likely to
-        be commited quickly.
+        be committed quickly.
         <br />
       </p>
     </section>

http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/documentation.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/documentation.xml b/src/site/xdoc/documentation.xml
index fce8c8f..5194dc0 100644
--- a/src/site/xdoc/documentation.xml
+++ b/src/site/xdoc/documentation.xml
@@ -66,7 +66,7 @@
 
             <h4>Internal Projects</h4>
 
-            <p>The <a href='http://james.apache.org/mailets/'>Apache James Mailet project</a> collects products
+            <p>The <a href='http://james.apache.org/mailet/'>Apache James Mailet project</a> collects products
                related to mailets (mail processing components analogous to servlets). These are independent of the
                 <a href='http://james.apache.org/server/'>James server</a> and can be reused in any mailet container.</p>
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/mailet/ai/index.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/mailet/ai/index.xml b/src/site/xdoc/mailet/ai/index.xml
index 8c81dcf..b76d929 100644
--- a/src/site/xdoc/mailet/ai/index.xml
+++ b/src/site/xdoc/mailet/ai/index.xml
@@ -25,7 +25,7 @@
     <body>
         <section name="Artificial Intelligence Mailets">
             <p>Mail processors with artificial intelligence (AI). Their purpose is to use AI algorithms to process
-                emails - things like identify<a href="http://en.wikipedia.org/wiki/Spam_(electronic)">SPAM</a>,
+                emails - things like identify <a href="http://en.wikipedia.org/wiki/Spam_(electronic)">SPAM</a>,
                 <a href="http://en.wikipedia.org/wiki/Phishing">phishing</a>
                 attempts, etc.
             </p>

http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/mailet/api/index.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/mailet/api/index.xml b/src/site/xdoc/mailet/api/index.xml
index ea4ab8b..223390c 100644
--- a/src/site/xdoc/mailet/api/index.xml
+++ b/src/site/xdoc/mailet/api/index.xml
@@ -32,9 +32,9 @@
                 processing functionality.
             </p>
             <p>
-                The Mailet API is a subproject of<a href='http://james.apache.org'>Apache James</a>.
+                The Mailet API is a subproject of <a href='http://james.apache.org'>Apache James</a>.
                 All who are interested in developing the Mailet API and James will be warmly
-                welcomed on the<a href='/mail-lists.html'>mailing lists</a>.
+                welcomed on the <a href='/mail-lists.html'>mailing lists</a>.
             </p>
         </section>
         <section name="Quick Start">
@@ -44,7 +44,7 @@
                     processing component is a useful analogy.
                 </p>
                 <p>
-                    Mailets implement<a href='/apidocs/org/apache/mailet/Mailet.html'>Mailet</a>.
+                    Mailets implement <a href='/mailet/apidocs/org/apache/mailet/Mailet.html'>Mailet</a>.
                     Mailets execute within a mailet container.
                     <a href='http://james.apache.org/server'>James server</a>
                     is a well known mailet container. Assembly and configuration of mailets and mail processors is the
@@ -111,12 +111,12 @@
             </subsection>
             <subsection name='Examples'>
                 <p>
-                    See<a href='http://james.apache.org/mailet/standard'>Standard mailets</a>.
+                    See <a href='http://james.apache.org/mailet/standard'>Standard mailets</a>.
                 </p>
             </subsection>
             <subsection name='Building the Mailet API'>
                 <p>
-                    The build uses<a href='http://ant.apache.org'>Ant</a>.
+                    The build uses <a href='http://ant.apache.org'>Ant</a>.
                     <code>ant -projecthelp</code>
                     describes appropriate targets.
                     <code>ant</code>
@@ -126,7 +126,7 @@
         </section>
 
         <section name="Comments, Questions and Issues">
-            <p>Please direct your feedback to the<a href='mail-lists.html'>mailet-api mailing list</a>.
+            <p>Please direct your feedback to the <a href='mail-lists.html'>mailet-api mailing list</a>.
             </p>
         </section>
     </body>

http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/mailet/crypto/index.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/mailet/crypto/index.xml b/src/site/xdoc/mailet/crypto/index.xml
index a99f041..74d8fa3 100644
--- a/src/site/xdoc/mailet/crypto/index.xml
+++ b/src/site/xdoc/mailet/crypto/index.xml
@@ -41,7 +41,7 @@
             <p>
                 SMIME is standardised by the
                 <acronym title='Internet Engineering Task Force'>
-                    <a href='http://www.imc.org/ietf-smime/index.html'>IEFT</a>
+                    <a href='http://www.ietf.org/mailman/listinfo/smime'>IEFT</a>
                 </acronym>
                 .
             </p>
@@ -93,7 +93,7 @@
             <ul>
                 <li>This library provides high level cryptographic operations
                     based on lower level cryptographic libraries created
-                    by<a href='http://www.bouncycastle.org/'>The Legion of the Bouncy Castle</a>.
+                    by <a href='http://www.bouncycastle.org/'>The Legion of the Bouncy Castle</a>.
                 </li>
             </ul>
             <p>Export classifications and source links can be found

http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/mailet/index.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/mailet/index.xml b/src/site/xdoc/mailet/index.xml
index 1321f2a..5d92ccd 100644
--- a/src/site/xdoc/mailet/index.xml
+++ b/src/site/xdoc/mailet/index.xml
@@ -71,7 +71,7 @@
                 </li>
                 <li>
                     <a href='mailetdocs-maven-plugin/index.html'>Mailetdocs</a>
-                    generates catelogs and documentation for mailets.
+                    generates catalogs and documentation for mailets.
                 </li>
             </ul>
         </section>

http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/mpt/index.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/mpt/index.xml b/src/site/xdoc/mpt/index.xml
index 50d38fe..4e60a2a 100644
--- a/src/site/xdoc/mpt/index.xml
+++ b/src/site/xdoc/mpt/index.xml
@@ -29,7 +29,7 @@
 <section name="What is the Apache James MPT?">
 <p>
 Apache James Mail Protocol Tester (MPT) is  a framework for the 
-scritable functional testing of ASCII based line protocols. 
+scriptable functional testing of ASCII based line protocols.
 Apache James MPT requires Java 1.5 or higher.</p>
 <subsection name='Releases'>
     <subsection name='0.2 (Roadmap)'>
@@ -61,7 +61,7 @@ templates (which may include regex's and so on).
 </p><p>
 The <a href='antlib'>AntLib</a> module extends the standalone framework
 to create functional testing tasks suitable for execution against a 
-indepedently running server.
+independently running server.
 </p>
 <p>
 The <a href='app'>Application</a> module provides an executable interface

http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/protocols/pop3.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/protocols/pop3.xml b/src/site/xdoc/protocols/pop3.xml
index 5ef6148..1ef7487 100644
--- a/src/site/xdoc/protocols/pop3.xml
+++ b/src/site/xdoc/protocols/pop3.xml
@@ -14,7 +14,7 @@
   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 govaerning permissions and limitations
+  specific language governing permissions and limitations
   under the License.    
 -->
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/protocols/smtp.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/protocols/smtp.xml b/src/site/xdoc/protocols/smtp.xml
index b79e039..5858934 100644
--- a/src/site/xdoc/protocols/smtp.xml
+++ b/src/site/xdoc/protocols/smtp.xml
@@ -14,7 +14,7 @@
   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 govaerning permissions and limitations
+  specific language governing permissions and limitations
   under the License.    
 -->
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/server/feature-security.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/server/feature-security.xml b/src/site/xdoc/server/feature-security.xml
index cea28e3..ba06743 100644
--- a/src/site/xdoc/server/feature-security.xml
+++ b/src/site/xdoc/server/feature-security.xml
@@ -41,7 +41,7 @@
   
   <section name="User Credential Security">
 
-    <p>Apache James Server supports different user storage (<a href="config-users.html">read more</a>) - LDAP support is partail (work in progress).</p>
+    <p>Apache James Server supports different user storage (<a href="config-users.html">read more</a>) - LDAP support is partial (work in progress).</p>
 
   </section>
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/7d15ef0e/src/site/xdoc/support.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/support.xml b/src/site/xdoc/support.xml
index 97dd483..f549447 100644
--- a/src/site/xdoc/support.xml
+++ b/src/site/xdoc/support.xml
@@ -34,7 +34,7 @@
       <p>We are an Open Source Software Company.</p>
       <p>Our mission is to bring digital independency to our customers.</p>
       <p>We are focused on large organizations both from private and public sector. We have set ourselves the goal of helping Governments to achieve their digital sovereignty.</p>
-      <p>Linagora employs 4 James commiters and 3 PMC members. We can offer professional services related to James: support, feature development or project integration.</p>
+      <p>Linagora employs 4 James committers and 3 PMC members. We can offer professional services related to James: support, feature development or project integration.</p>
     </subsection>
   </section>
 


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


[10/21] james-project git commit: JAMES-2272 Cassandra migrations should rely on TaskManager

Posted by bt...@apache.org.
JAMES-2272 Cassandra migrations should rely on TaskManager

 - Use MigrationTask to add context to migration tasks
 - This makes migration manageable
 - Concurrency concerns are pushed to the TaskManager (which has sequential task execution) thus related tests can be removed. Note that an integration test demonstrate no WebAdmin behaviour regression was introduced on that point.

In order to achieve this result, CassandraMigrationService has to generate a Migration that is a combination of required migrations.


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

Branch: refs/heads/master
Commit: b1a7139bbb9f720faa12bb00d52c7d71ce7b6e11
Parents: d9d73f8
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 13:41:23 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:03:36 2018 +0700

----------------------------------------------------------------------
 .../migration/CassandraMigrationService.java    | 75 +++++++++++------
 .../backends/cassandra/migration/Migration.java | 10 +++
 .../cassandra/migration/MigrationTask.java      | 61 ++++++++++++++
 .../CassandraMigrationServiceTest.java          | 61 +++-----------
 .../cassandra/migration/MigrationTest.java      | 89 ++++++++++++++++++++
 .../migration/AttachmentMessageIdCreation.java  |  3 +-
 .../mail/migration/AttachmentV2Migration.java   |  3 +-
 .../WebAdminServerIntegrationTest.java          | 66 ++++++++++++---
 .../routes/CassandraMigrationRoutes.java        | 48 +++++------
 .../routes/CassandraMigrationRoutesTest.java    | 80 +++++++++++++++---
 .../apache/james/webadmin/dto/TaskIdDto.java    | 13 +++
 11 files changed, 379 insertions(+), 130 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
index 0eb80aa..9c494e1 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
@@ -19,6 +19,8 @@
 
 package org.apache.james.backends.cassandra.migration;
 
+import static org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager.DEFAULT_VERSION;
+
 import java.util.Map;
 import java.util.Optional;
 import java.util.stream.IntStream;
@@ -28,7 +30,6 @@ import javax.inject.Named;
 
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
-import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -57,40 +58,62 @@ public class CassandraMigrationService {
         return Optional.of(latestVersion);
     }
 
-    public synchronized void upgradeToVersion(int newVersion) {
-        int currentVersion = schemaVersionDAO.getCurrentSchemaVersion().join().orElse(CassandraSchemaVersionManager.DEFAULT_VERSION);
-        if (currentVersion >= newVersion) {
-            throw new IllegalStateException("Current version is already up to date");
-        }
+    public Migration upgradeToVersion(int newVersion) {
+        int currentVersion = getCurrentVersion().orElse(DEFAULT_VERSION);
+        assertMigrationNeeded(newVersion, currentVersion);
 
-        IntStream.range(currentVersion, newVersion)
+        Migration migrationCombination = IntStream.range(currentVersion, newVersion)
             .boxed()
-            .forEach(this::doMigration);
+            .map(this::validateVersionNumber)
+            .map(this::toMigration)
+            .reduce(Migration.IDENTITY, Migration::combine);
+        return new MigrationTask(migrationCombination, newVersion);
     }
 
-    public void upgradeToLastVersion() {
-        upgradeToVersion(latestVersion);
+    private void assertMigrationNeeded(int newVersion, int currentVersion) {
+        boolean needMigration = currentVersion < newVersion;
+        if (!needMigration) {
+            throw new IllegalStateException("Current version is already up to date");
+        }
     }
 
-    private void doMigration(Integer version) {
-        if (allMigrationClazz.containsKey(version)) {
-            LOG.info("Migrating to version {} ", version + 1);
-            Migration.Result migrationResult = allMigrationClazz.get(version).run();
-            if (migrationResult == Migration.Result.COMPLETED) {
-                schemaVersionDAO.updateVersion(version + 1);
-                LOG.info("Migrating to version {} done", version + 1);
-            } else {
-                String message = String.format("Migrating to version %d partially done. " +
-                    "Please check logs for cause of failure and re-run this migration.",
-                    version + 1);
-                LOG.warn(message);
-                throw new MigrationException(message);
-            }
-        } else {
-            String message = String.format("Can not migrate to %d. No migration class registered.", version + 1);
+    private Integer validateVersionNumber(Integer versionNumber) {
+        if (!allMigrationClazz.containsKey(versionNumber)) {
+            String message = String.format("Can not migrate to %d. No migration class registered.", versionNumber);
             LOG.error(message);
             throw new NotImplementedException(message);
         }
+        return versionNumber;
+    }
+
+    public Migration upgradeToLastVersion() {
+        return upgradeToVersion(latestVersion);
+    }
+
+    private Migration toMigration(Integer version) {
+        return () -> {
+            int newVersion = version + 1;
+            int currentVersion = getCurrentVersion().orElse(DEFAULT_VERSION);
+            if (currentVersion >= newVersion) {
+                return Migration.Result.PARTIAL;
+            }
+
+            LOG.info("Migrating to version {} ", newVersion);
+            return allMigrationClazz.get(version).run()
+                .onComplete(() -> schemaVersionDAO.updateVersion(newVersion),
+                    () -> LOG.info("Migrating to version {} done", newVersion))
+                .onFailure(() -> LOG.warn(failureMessage(newVersion)),
+                    () -> throwMigrationException(newVersion));
+        };
+    }
+
+    private void throwMigrationException(int newVersion) {
+        throw new MigrationException(failureMessage(newVersion));
+    }
+
+    private String failureMessage(Integer newVersion) {
+        return String.format("Migrating to version %d partially done. " +
+                "Please check logs for cause of failure and re-run this migration.", newVersion);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/Migration.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/Migration.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/Migration.java
index b4f15f4..18be8dc 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/Migration.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/Migration.java
@@ -22,5 +22,15 @@ package org.apache.james.backends.cassandra.migration;
 import org.apache.james.task.Task;
 
 public interface Migration extends Task {
+    Migration IDENTITY = () -> Result.COMPLETED;
 
+    static Migration combine(Migration migration1, Migration migration2) {
+        return () -> {
+            Result migration1Result = migration1.run();
+            if (migration1Result == Result.COMPLETED) {
+                return migration2.run();
+            }
+            return Result.PARTIAL;
+        };
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationTask.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationTask.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationTask.java
new file mode 100644
index 0000000..518b682
--- /dev/null
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationTask.java
@@ -0,0 +1,61 @@
+/****************************************************************
+ * 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.backends.cassandra.migration;
+
+import java.util.Optional;
+
+public class MigrationTask implements Migration {
+    public static final String CASSANDRA_MIGRATION = "CassandraMigration";
+
+    public static class Details {
+        private final int toVersion;
+
+        public Details(int toVersion) {
+            this.toVersion = toVersion;
+        }
+
+        public int getToVersion() {
+            return toVersion;
+        }
+    }
+
+    private final Migration migration;
+    private final int toVersion;
+
+    public MigrationTask(Migration migration, int toVersion) {
+        this.migration = migration;
+        this.toVersion = toVersion;
+    }
+
+    @Override
+    public Result run() {
+        return migration.run();
+    }
+
+    @Override
+    public String type() {
+        return CASSANDRA_MIGRATION;
+    }
+
+    @Override
+    public Optional<Object> details() {
+        return Optional.of(new Details(toVersion));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
index fa2a29f..5dea96b 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
@@ -21,7 +21,6 @@ package org.apache.james.backends.cassandra.migration;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -34,8 +33,6 @@ import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
@@ -46,12 +43,12 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
 import com.datastax.driver.core.Session;
-import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableMap;
 
 public class CassandraMigrationServiceTest {
     private static final int LATEST_VERSION = 3;
-    private static final int CURRENT_VERSION = 2;
+    private static final int INTERMEDIARY_VERSION = 2;
+    private static final int CURRENT_VERSION = INTERMEDIARY_VERSION;
     private static final int OLDER_VERSION = 1;
     private CassandraMigrationService testee;
     private CassandraSchemaVersionDAO schemaVersionDAO;
@@ -98,14 +95,14 @@ public class CassandraMigrationServiceTest {
 
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
 
-        testee.upgradeToVersion(OLDER_VERSION);
+        testee.upgradeToVersion(OLDER_VERSION).run();
     }
 
     @Test
     public void upgradeToVersionShouldUpdateToVersion() throws Exception {
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
 
-        testee.upgradeToVersion(CURRENT_VERSION);
+        testee.upgradeToVersion(CURRENT_VERSION).run();
 
         verify(schemaVersionDAO, times(1)).updateVersion(eq(CURRENT_VERSION));
     }
@@ -116,14 +113,14 @@ public class CassandraMigrationServiceTest {
 
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(LATEST_VERSION)));
 
-        testee.upgradeToLastVersion();
+        testee.upgradeToLastVersion().run();
     }
 
     @Test
     public void upgradeToLastVersionShouldUpdateToLatestVersion() throws Exception {
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
 
-        testee.upgradeToLastVersion();
+        testee.upgradeToLastVersion().run();
 
         verify(schemaVersionDAO, times(1)).updateVersion(eq(LATEST_VERSION));
     }
@@ -139,7 +136,7 @@ public class CassandraMigrationServiceTest {
 
         expectedException.expect(NotImplementedException.class);
 
-        testee.upgradeToVersion(LATEST_VERSION);
+        testee.upgradeToVersion(LATEST_VERSION).run();
     }
 
     @Test
@@ -147,6 +144,7 @@ public class CassandraMigrationServiceTest {
         try {
             Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
                 .put(OLDER_VERSION, successfulMigration)
+                .put(INTERMEDIARY_VERSION, () -> Migration.Result.PARTIAL)
                 .put(LATEST_VERSION, successfulMigration)
                 .build();
             testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION);
@@ -154,50 +152,13 @@ public class CassandraMigrationServiceTest {
 
             expectedException.expect(RuntimeException.class);
 
-            testee.upgradeToVersion(LATEST_VERSION);
+            testee.upgradeToVersion(LATEST_VERSION).run();
         } finally {
             verify(schemaVersionDAO).updateVersion(CURRENT_VERSION);
         }
     }
 
     @Test
-    public void concurrentMigrationsShouldFail() throws Exception {
-        // Given a stateful migration service
-        Migration wait1SecondMigration = mock(Migration.class);
-        doAnswer(invocation -> {
-            Thread.sleep(1000);
-            return Migration.Result.COMPLETED;
-        }).when(wait1SecondMigration).run();
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
-            .put(OLDER_VERSION, wait1SecondMigration)
-            .put(CURRENT_VERSION, wait1SecondMigration)
-            .put(LATEST_VERSION, wait1SecondMigration)
-            .build();
-        testee = new CassandraMigrationService(new InMemorySchemaDAO(OLDER_VERSION), allMigrationClazz, LATEST_VERSION);
-
-        // When I perform a concurrent migration
-        AtomicInteger encounteredExceptionCount = new AtomicInteger(0);
-        executorService.submit(() -> testee.upgradeToVersion(LATEST_VERSION));
-        executorService.submit(() -> {
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException e) {
-                throw Throwables.propagate(e);
-            }
-
-            try {
-                testee.upgradeToVersion(LATEST_VERSION);
-            } catch (IllegalStateException e) {
-                encounteredExceptionCount.incrementAndGet();
-            }
-        });
-        executorService.awaitTermination(10, TimeUnit.SECONDS);
-
-        // Then the second migration fails
-        assertThat(encounteredExceptionCount.get()).isEqualTo(1);
-    }
-
-    @Test
     public void partialMigrationShouldThrow() throws Exception {
         Migration migration1 = mock(Migration.class);
         when(migration1.run()).thenReturn(Migration.Result.PARTIAL);
@@ -211,7 +172,7 @@ public class CassandraMigrationServiceTest {
 
         expectedException.expect(MigrationException.class);
 
-        testee.upgradeToVersion(LATEST_VERSION);
+        testee.upgradeToVersion(LATEST_VERSION).run();
     }
 
     @Test
@@ -230,7 +191,7 @@ public class CassandraMigrationServiceTest {
         expectedException.expect(MigrationException.class);
 
         try {
-            testee.upgradeToVersion(LATEST_VERSION);
+            testee.upgradeToVersion(LATEST_VERSION).run();
         } finally {
             verify(migration1, times(1)).run();
             verifyNoMoreInteractions(migration1);

http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/MigrationTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/MigrationTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/MigrationTest.java
new file mode 100644
index 0000000..f1a0092
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/MigrationTest.java
@@ -0,0 +1,89 @@
+/****************************************************************
+ * 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.backends.cassandra.migration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Test;
+
+public class MigrationTest {
+    @Test
+    public void combineShouldNotExecuteSecondMigrationExecutionWhenTheFirstOneIsFailing() {
+        AtomicBoolean migration2Done = new AtomicBoolean(false);
+
+        Migration migration1 = () -> Migration.Result.PARTIAL;
+        Migration migration2 = () -> {
+            migration2Done.set(true);
+            return Migration.Result.COMPLETED;
+        };
+
+        Migration.combine(migration1, migration2).run();
+
+        assertThat(migration2Done).isFalse();
+    }
+
+    @Test
+    public void combineShouldTriggerSecondMigrationWhenTheFirstOneSucceed() {
+        AtomicBoolean migration2Done = new AtomicBoolean(false);
+
+        Migration migration1 = () -> Migration.Result.COMPLETED;
+        Migration migration2 = () -> {
+            migration2Done.set(true);
+            return Migration.Result.COMPLETED;
+        };
+
+        Migration.combine(migration1, migration2).run();
+
+        assertThat(migration2Done).isTrue();
+    }
+
+    @Test
+    public void combineShouldExecuteTheFirstMigrationWhenSecondWillFail() {
+        AtomicBoolean migration1Done = new AtomicBoolean(false);
+
+        Migration migration1 = () -> {
+            migration1Done.set(true);
+            return Migration.Result.COMPLETED;
+        };
+        Migration migration2 = () -> Migration.Result.PARTIAL;
+
+
+        Migration.combine(migration1, migration2).run();
+
+        assertThat(migration1Done).isTrue();
+    }
+
+    @Test
+    public void combineShouldExecuteTheFirstMigration() {
+        AtomicBoolean migration1Done = new AtomicBoolean(false);
+
+        Migration migration1 = () -> {
+            migration1Done.set(true);
+            return Migration.Result.COMPLETED;
+        };
+        Migration migration2 = () -> Migration.Result.COMPLETED;
+
+        Migration.combine(migration1, migration2).run();
+
+        assertThat(migration1Done).isTrue();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
index 37e8358..d43c8a6 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentMessageIdCreation.java
@@ -25,6 +25,7 @@ import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO.MessageIdAttachmentIds;
+import org.apache.james.task.Task;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,7 +47,7 @@ public class AttachmentMessageIdCreation implements Migration {
             return cassandraMessageDAO.retrieveAllMessageIdAttachmentIds()
                 .join()
                 .map(this::createIndex)
-                .reduce(Result.COMPLETED, Migration::combine);
+                .reduce(Result.COMPLETED, Task::combine);
         } catch (Exception e) {
             LOGGER.error("Error while creation attachmentId -> messageIds index", e);
             return Result.PARTIAL;

http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
----------------------------------------------------------------------
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
index ca5c116..0d33e36 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/migration/AttachmentV2Migration.java
@@ -26,6 +26,7 @@ import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAO;
 import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
 import org.apache.james.mailbox.cassandra.mail.CassandraBlobsDAO;
 import org.apache.james.mailbox.model.Attachment;
+import org.apache.james.task.Task;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,7 +50,7 @@ public class AttachmentV2Migration implements Migration {
         try {
             return attachmentDAOV1.retrieveAll()
                 .map(this::migrateAttachment)
-                .reduce(Result.COMPLETED, Migration::combine);
+                .reduce(Result.COMPLETED, Task::combine);
         } catch (Exception e) {
             LOGGER.error("Error while performing attachmentDAO V2 migration", e);
             return Result.PARTIAL;

http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
index 575bd30..981fbf5 100644
--- a/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
+++ b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
@@ -20,6 +20,7 @@
 package org.apache.james.webadmin.integration;
 
 import static com.jayway.restassured.RestAssured.given;
+import static com.jayway.restassured.RestAssured.with;
 import static com.jayway.restassured.config.EncoderConfig.encoderConfig;
 import static com.jayway.restassured.config.RestAssuredConfig.newConfig;
 import static org.apache.james.webadmin.Constants.JSON_CONTENT_TYPE;
@@ -30,6 +31,8 @@ import static org.hamcrest.Matchers.is;
 
 import java.nio.charset.StandardCharsets;
 import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.james.CassandraJmapTestRule;
 import org.apache.james.DockerCassandraRule;
@@ -37,6 +40,8 @@ import org.apache.james.GuiceJamesServer;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.modules.MailboxProbeImpl;
 import org.apache.james.probe.DataProbe;
+import org.apache.james.task.TaskManager;
+import org.apache.james.util.concurrency.ConcurrentTestRunner;
 import org.apache.james.utils.DataProbeImpl;
 import org.apache.james.utils.WebAdminGuiceProbe;
 import org.apache.james.webadmin.routes.DomainsRoutes;
@@ -49,6 +54,7 @@ import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
 
 import com.jayway.restassured.RestAssured;
 import com.jayway.restassured.builder.RequestSpecBuilder;
@@ -226,13 +232,16 @@ public class WebAdminServerIntegrationTest {
 
     @Test
     public void postShouldDoMigrationAndUpdateCurrentVersion() throws Exception {
-        given()
+        String taskId = with()
             .port(webAdminGuiceProbe.getWebAdminPort())
             .body(String.valueOf(CassandraSchemaVersionManager.MAX_VERSION))
-        .when()
-            .post(UPGRADE_VERSION)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
+        .post(UPGRADE_VERSION)
+            .jsonPath()
+            .get("taskId");
+
+        with()
+            .port(webAdminGuiceProbe.getWebAdminPort())
+            .get("/task/" + taskId + "/await");
 
         given()
             .port(webAdminGuiceProbe.getWebAdminPort())
@@ -246,12 +255,15 @@ public class WebAdminServerIntegrationTest {
 
     @Test
     public void postShouldDoMigrationAndUpdateToTheLatestVersion() throws Exception {
-        given()
+        String taskId = with()
             .port(webAdminGuiceProbe.getWebAdminPort())
-        .when()
-            .post(UPGRADE_TO_LATEST_VERSION)
-        .then()
-            .statusCode(HttpStatus.OK_200);
+        .post(UPGRADE_TO_LATEST_VERSION)
+            .jsonPath()
+            .get("taskId");
+
+        with()
+            .port(webAdminGuiceProbe.getWebAdminPort())
+            .get("/task/" + taskId + "/await");
 
         given()
             .port(webAdminGuiceProbe.getWebAdminPort())
@@ -264,6 +276,40 @@ public class WebAdminServerIntegrationTest {
     }
 
     @Test
+    public void concurrentMigrationIsNotAllowed() throws Exception {
+        ConcurrentLinkedQueue<String> taskIds = new ConcurrentLinkedQueue<>();
+        int threadCount = 2;
+        int operationCount = 1;
+        new ConcurrentTestRunner(threadCount, operationCount, (a, b) -> {
+            String migrationId = with()
+                .port(webAdminGuiceProbe.getWebAdminPort())
+                .post(UPGRADE_TO_LATEST_VERSION)
+                .jsonPath()
+                .get("taskId");
+            taskIds.add(migrationId);
+        }).run()
+            .awaitTermination(1, TimeUnit.MINUTES);
+
+        String id1 = taskIds.poll();
+        String id2 = taskIds.poll();
+        String status1 = with()
+            .port(webAdminGuiceProbe.getWebAdminPort())
+            .get("/tasks/" + id1 + "/await")
+            .jsonPath()
+            .get("status");
+        String status2 = with()
+            .port(webAdminGuiceProbe.getWebAdminPort())
+            .get("/tasks/" + id2 + "/await")
+            .jsonPath()
+            .get("status");
+
+        assertThat(ImmutableList.of(status1, status2))
+            .containsOnly(
+                TaskManager.Status.COMPLETED.getValue(),
+                TaskManager.Status.FAILED.getValue());
+    }
+
+    @Test
     public void addressGroupsEndpointShouldHandleRequests() throws Exception {
         dataProbe.addAddressMapping("group", "domain.com", "user1@domain.com");
         dataProbe.addAddressMapping("group", "domain.com", "user2@domain.com");

http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
index dce04cf..bff6d1f 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
@@ -22,10 +22,13 @@ package org.apache.james.webadmin.routes;
 import javax.inject.Inject;
 
 import org.apache.james.backends.cassandra.migration.CassandraMigrationService;
-import org.apache.james.backends.cassandra.migration.MigrationException;
-import org.apache.james.webadmin.Constants;
+import org.apache.james.backends.cassandra.migration.Migration;
+import org.apache.james.task.TaskId;
+import org.apache.james.task.TaskManager;
 import org.apache.james.webadmin.Routes;
 import org.apache.james.webadmin.dto.CassandraVersionRequest;
+import org.apache.james.webadmin.dto.CassandraVersionResponse;
+import org.apache.james.webadmin.dto.TaskIdDto;
 import org.apache.james.webadmin.utils.ErrorResponder;
 import org.apache.james.webadmin.utils.ErrorResponder.ErrorType;
 import org.apache.james.webadmin.utils.JsonTransformer;
@@ -45,6 +48,7 @@ public class CassandraMigrationRoutes implements Routes {
     private static final String VERSION_UPGRADE_TO_LATEST_BASE = VERSION_UPGRADE_BASE + "/latest";
 
     private final CassandraMigrationService cassandraMigrationService;
+    private final TaskManager taskManager;
     private final JsonTransformer jsonTransformer;
 
     public static String INVALID_VERSION_UPGRADE_REQUEST = "Invalid request for version upgrade";
@@ -52,27 +56,30 @@ public class CassandraMigrationRoutes implements Routes {
     public static String PARTIAL_MIGRATION_PROCESS = "An error lead to partial migration process";
 
     @Inject
-    public CassandraMigrationRoutes(CassandraMigrationService cassandraMigrationService, JsonTransformer jsonTransformer) {
+    public CassandraMigrationRoutes(CassandraMigrationService cassandraMigrationService,
+                                    TaskManager taskManager, JsonTransformer jsonTransformer) {
         this.cassandraMigrationService = cassandraMigrationService;
+        this.taskManager = taskManager;
         this.jsonTransformer = jsonTransformer;
     }
 
     @Override
     public void define(Service service) {
         service.get(VERSION_BASE,
-            (request, response) -> cassandraMigrationService.getCurrentVersion(),
+            (request, response) -> new CassandraVersionResponse(cassandraMigrationService.getCurrentVersion()),
             jsonTransformer);
 
         service.get(VERSION_BASE_LATEST,
-            (request, response) -> cassandraMigrationService.getLatestVersion(),
+            (request, response) -> new CassandraVersionResponse(cassandraMigrationService.getLatestVersion()),
             jsonTransformer);
 
         service.post(VERSION_UPGRADE_BASE, (request, response) -> {
             LOGGER.debug("Cassandra upgrade launched");
             try {
                 CassandraVersionRequest cassandraVersionRequest = CassandraVersionRequest.parse(request.body());
-                cassandraMigrationService.upgradeToVersion(cassandraVersionRequest.getValue());
-                response.status(HttpStatus.NO_CONTENT_204);
+                Migration migration = cassandraMigrationService.upgradeToVersion(cassandraVersionRequest.getValue());
+                TaskId taskId = taskManager.submit(migration);
+                return TaskIdDto.respond(response, taskId);
             } catch (NullPointerException | IllegalArgumentException e) {
                 LOGGER.info(INVALID_VERSION_UPGRADE_REQUEST);
                 throw ErrorResponder.builder()
@@ -89,21 +96,14 @@ public class CassandraMigrationRoutes implements Routes {
                     .message(MIGRATION_REQUEST_CAN_NOT_BE_DONE)
                     .cause(e)
                     .haltError();
-            } catch (MigrationException e) {
-                LOGGER.error(PARTIAL_MIGRATION_PROCESS, e);
-                throw ErrorResponder.builder()
-                    .statusCode(HttpStatus.INTERNAL_SERVER_ERROR_500)
-                    .type(ErrorType.SERVER_ERROR)
-                    .message(PARTIAL_MIGRATION_PROCESS)
-                    .cause(e)
-                    .haltError();
             }
-            return Constants.EMPTY_BODY;
-        });
+        }, jsonTransformer);
 
         service.post(VERSION_UPGRADE_TO_LATEST_BASE, (request, response) -> {
             try {
-                cassandraMigrationService.upgradeToLastVersion();
+                Migration migration = cassandraMigrationService.upgradeToLastVersion();
+                TaskId taskId = taskManager.submit(migration);
+                return TaskIdDto.respond(response, taskId);
             } catch (IllegalStateException e) {
                 LOGGER.info(MIGRATION_REQUEST_CAN_NOT_BE_DONE, e);
                 throw ErrorResponder.builder()
@@ -112,17 +112,7 @@ public class CassandraMigrationRoutes implements Routes {
                     .message(MIGRATION_REQUEST_CAN_NOT_BE_DONE)
                     .cause(e)
                     .haltError();
-            } catch (MigrationException e) {
-                LOGGER.error(PARTIAL_MIGRATION_PROCESS, e);
-                throw ErrorResponder.builder()
-                    .statusCode(HttpStatus.INTERNAL_SERVER_ERROR_500)
-                    .type(ErrorType.SERVER_ERROR)
-                    .message(PARTIAL_MIGRATION_PROCESS)
-                    .cause(e)
-                    .haltError();
             }
-
-            return Constants.EMPTY_BODY;
-        });
+        }, jsonTransformer);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
index f3fc05a..0cc9d9c 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
@@ -21,10 +21,13 @@ package org.apache.james.webadmin.routes;
 
 import static com.jayway.restassured.RestAssured.given;
 import static com.jayway.restassured.RestAssured.when;
+import static com.jayway.restassured.RestAssured.with;
 import static com.jayway.restassured.config.EncoderConfig.encoderConfig;
 import static com.jayway.restassured.config.RestAssuredConfig.newConfig;
 import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -38,9 +41,11 @@ import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 
 import org.apache.james.backends.cassandra.migration.CassandraMigrationService;
+import org.apache.james.backends.cassandra.migration.Migration;
+import org.apache.james.backends.cassandra.migration.MigrationTask;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
-import org.apache.james.mailbox.cassandra.mail.migration.Migration;
 import org.apache.james.metrics.logger.DefaultMetricFactory;
+import org.apache.james.task.MemoryTaskManager;
 import org.apache.james.webadmin.WebAdminServer;
 import org.apache.james.webadmin.WebAdminUtils;
 import org.apache.james.webadmin.utils.JsonTransformer;
@@ -56,16 +61,16 @@ import com.jayway.restassured.builder.RequestSpecBuilder;
 import com.jayway.restassured.http.ContentType;
 
 public class CassandraMigrationRoutesTest {
-
     private static final Integer LATEST_VERSION = 3;
     private static final Integer CURRENT_VERSION = 2;
     private static final Integer OLDER_VERSION = 1;
     private WebAdminServer webAdminServer;
     private CassandraSchemaVersionDAO schemaVersionDAO;
+    private MemoryTaskManager taskManager;
 
     private void createServer() throws Exception {
         Migration successfulMigration = mock(Migration.class);
-        when(successfulMigration.run()).thenReturn(Migration.MigrationResult.COMPLETED);
+        when(successfulMigration.run()).thenReturn(Migration.Result.COMPLETED);
 
         Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
             .put(OLDER_VERSION, successfulMigration)
@@ -74,9 +79,13 @@ public class CassandraMigrationRoutesTest {
             .build();
         schemaVersionDAO = mock(CassandraSchemaVersionDAO.class);
 
+        taskManager = new MemoryTaskManager();
+        JsonTransformer jsonTransformer = new JsonTransformer();
         webAdminServer = WebAdminUtils.createWebAdminServer(
             new DefaultMetricFactory(),
-            new CassandraMigrationRoutes(new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION), new JsonTransformer()));
+            new CassandraMigrationRoutes(new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION),
+                taskManager, jsonTransformer),
+            new TasksRoutes(taskManager, jsonTransformer));
 
         webAdminServer.configure(NO_CONFIGURATION);
         webAdminServer.await();
@@ -98,6 +107,7 @@ public class CassandraMigrationRoutesTest {
     @After
     public void tearDown() {
         webAdminServer.destroy();
+        taskManager.stop();
     }
 
     @Test
@@ -171,14 +181,20 @@ public class CassandraMigrationRoutesTest {
     public void postShouldDoMigrationToNewVersion() throws Exception {
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
 
-        given()
+        String taskId = with()
             .body(String.valueOf(CURRENT_VERSION))
-        .with()
-            .post("/upgrade")
+        .post("/upgrade")
+            .jsonPath()
+            .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
         .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
+            .body("status", is("completed"));
 
-        verify(schemaVersionDAO, times(1)).getCurrentSchemaVersion();
+        verify(schemaVersionDAO, times(2)).getCurrentSchemaVersion();
         verify(schemaVersionDAO, times(1)).updateVersion(eq(CURRENT_VERSION));
         verifyNoMoreInteractions(schemaVersionDAO);
     }
@@ -213,18 +229,56 @@ public class CassandraMigrationRoutesTest {
     public void postShouldDoMigrationToLatestVersion() throws Exception {
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
 
-        when()
+        String taskId = with()
             .post("/upgrade/latest")
-        .then()
-            .statusCode(HttpStatus.OK_200);
+            .jsonPath()
+            .get("taskId");
 
-        verify(schemaVersionDAO, times(1)).getCurrentSchemaVersion();
+        with()
+            .basePath(TasksRoutes.BASE)
+            .get(taskId + "/await");
+
+        verify(schemaVersionDAO, times(3)).getCurrentSchemaVersion();
         verify(schemaVersionDAO, times(1)).updateVersion(eq(CURRENT_VERSION));
         verify(schemaVersionDAO, times(1)).updateVersion(eq(LATEST_VERSION));
         verifyNoMoreInteractions(schemaVersionDAO);
     }
 
     @Test
+    public void postShouldReturnTaskIdAndLocation() throws Exception {
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+
+        when()
+            .post("/upgrade/latest")
+        .then()
+            .header("Location", is(notNullValue()))
+            .body("taskId", is(notNullValue()));
+    }
+
+    @Test
+    public void createdTaskShouldHaveDetails() throws Exception {
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+
+        String taskId = with()
+            .post("/upgrade/latest")
+            .jsonPath()
+            .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(notNullValue()))
+            .body("type", is(MigrationTask.CASSANDRA_MIGRATION))
+            .body("additionalInformation.toVersion", is(LATEST_VERSION))
+            .body("startedDate", is(notNullValue()))
+            .body("submitDate", is(notNullValue()))
+            .body("completedDate", is(notNullValue()));
+    }
+
+    @Test
     public void postShouldNotDoMigrationToLatestVersionWhenItIsUpToDate() throws Exception {
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(LATEST_VERSION)));
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/b1a7139b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/TaskIdDto.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/TaskIdDto.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/TaskIdDto.java
index 231d051..64c4321 100644
--- a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/TaskIdDto.java
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/dto/TaskIdDto.java
@@ -19,11 +19,24 @@
 
 package org.apache.james.webadmin.dto;
 
+import static org.eclipse.jetty.http.HttpHeader.LOCATION;
+
 import java.util.UUID;
 
 import org.apache.james.task.TaskId;
+import org.apache.james.webadmin.routes.TasksRoutes;
+import org.eclipse.jetty.http.HttpStatus;
+
+import spark.Response;
 
 public class TaskIdDto {
+
+    public static TaskIdDto respond(Response response, TaskId taskId) {
+        response.status(HttpStatus.CREATED_201);
+        response.header(LOCATION.asString(), TasksRoutes.BASE + "/" + taskId.toString());
+        return TaskIdDto.from(taskId);
+    }
+
     public static TaskIdDto from(TaskId id) {
         return new TaskIdDto(id.getValue());
     }


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


[15/21] james-project git commit: JAMES-2272 Migration should succeed when already applied

Posted by bt...@apache.org.
JAMES-2272 Migration should succeed when already applied

concurrentMigrationIsNotAllowed test can not be return anymore as it was relying on the non indepotent behaviour to ensure tasks was run sequentially. However, using the taskManager, we ensure task, and thus migrations can run sequentially.


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

Branch: refs/heads/master
Commit: e4af1a8b4e71b76685980257eca304bf7faf7d78
Parents: 955afb0
Author: benwa <bt...@linagora.com>
Authored: Wed Jan 3 16:40:28 2018 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:12:47 2018 +0700

----------------------------------------------------------------------
 .../migration/CassandraMigrationService.java    | 10 +--
 .../CassandraMigrationServiceTest.java          | 14 ++--
 .../WebAdminServerIntegrationTest.java          | 39 -----------
 .../routes/CassandraMigrationRoutesTest.java    | 70 +++++++++++++-------
 4 files changed, 54 insertions(+), 79 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/e4af1a8b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
index 9ab1177..7ff0775 100644
--- a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
@@ -58,7 +58,6 @@ public class CassandraMigrationService {
 
     public Migration upgradeToVersion(SchemaVersion newVersion) {
         SchemaVersion currentVersion = getCurrentVersion().orElse(DEFAULT_VERSION);
-        assertMigrationNeeded(newVersion, currentVersion);
 
         Migration migrationCombination = IntStream.range(currentVersion.getValue(), newVersion.getValue())
             .boxed()
@@ -69,13 +68,6 @@ public class CassandraMigrationService {
         return new MigrationTask(migrationCombination, newVersion);
     }
 
-    private void assertMigrationNeeded(SchemaVersion newVersion, SchemaVersion currentVersion) {
-        boolean needMigration = currentVersion.isBefore(newVersion);
-        if (!needMigration) {
-            throw new IllegalStateException("Current version is already up to date");
-        }
-    }
-
     private SchemaVersion validateVersionNumber(SchemaVersion versionNumber) {
         if (!allMigrationClazz.containsKey(versionNumber)) {
             String message = String.format("Can not migrate to %d. No migration class registered.", versionNumber.getValue());
@@ -94,7 +86,7 @@ public class CassandraMigrationService {
             SchemaVersion newVersion = version.next();
             SchemaVersion currentVersion = getCurrentVersion().orElse(DEFAULT_VERSION);
             if (currentVersion.isAfterOrEquals(newVersion)) {
-                return Migration.Result.PARTIAL;
+                return Migration.Result.COMPLETED;
             }
 
             LOG.info("Migrating to version {} ", newVersion);

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4af1a8b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
index 4897800..ac1fc82 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
@@ -37,6 +37,7 @@ import java.util.concurrent.Executors;
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.SchemaVersion;
+import org.apache.james.task.Task;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -91,12 +92,11 @@ public class CassandraMigrationServiceTest {
     }
 
     @Test
-    public void upgradeToVersionShouldThrowWhenCurrentVersionIsUpToDate() throws Exception {
-        expectedException.expect(IllegalStateException.class);
-
+    public void upgradeToVersionShouldNotThrowWhenCurrentVersionIsUpToDate() throws Exception {
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
 
-        testee.upgradeToVersion(OLDER_VERSION).run();
+        assertThat(testee.upgradeToVersion(OLDER_VERSION).run())
+            .isEqualTo(Task.Result.COMPLETED);
     }
 
     @Test
@@ -109,12 +109,12 @@ public class CassandraMigrationServiceTest {
     }
 
     @Test
-    public void upgradeToLastVersionShouldThrowWhenVersionIsUpToDate() throws Exception {
-        expectedException.expect(IllegalStateException.class);
+    public void upgradeToLastVersionShouldNotThrowWhenVersionIsUpToDate() throws Exception {
 
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(LATEST_VERSION)));
 
-        testee.upgradeToLastVersion().run();
+        assertThat(testee.upgradeToLastVersion().run())
+            .isEqualTo(Task.Result.COMPLETED);
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4af1a8b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
index fee4465..3f403bc 100644
--- a/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
+++ b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
@@ -31,8 +31,6 @@ import static org.hamcrest.Matchers.is;
 
 import java.nio.charset.StandardCharsets;
 import java.util.List;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.TimeUnit;
 
 import org.apache.james.CassandraJmapTestRule;
 import org.apache.james.DockerCassandraRule;
@@ -40,8 +38,6 @@ import org.apache.james.GuiceJamesServer;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.modules.MailboxProbeImpl;
 import org.apache.james.probe.DataProbe;
-import org.apache.james.task.TaskManager;
-import org.apache.james.util.concurrency.ConcurrentTestRunner;
 import org.apache.james.utils.DataProbeImpl;
 import org.apache.james.utils.WebAdminGuiceProbe;
 import org.apache.james.webadmin.routes.DomainsRoutes;
@@ -54,7 +50,6 @@ import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
-import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
 
 import com.jayway.restassured.RestAssured;
 import com.jayway.restassured.builder.RequestSpecBuilder;
@@ -276,40 +271,6 @@ public class WebAdminServerIntegrationTest {
     }
 
     @Test
-    public void concurrentMigrationIsNotAllowed() throws Exception {
-        ConcurrentLinkedQueue<String> taskIds = new ConcurrentLinkedQueue<>();
-        int threadCount = 2;
-        int operationCount = 1;
-        new ConcurrentTestRunner(threadCount, operationCount, (a, b) -> {
-            String migrationId = with()
-                .port(webAdminGuiceProbe.getWebAdminPort())
-                .post(UPGRADE_TO_LATEST_VERSION)
-                .jsonPath()
-                .get("taskId");
-            taskIds.add(migrationId);
-        }).run()
-            .awaitTermination(1, TimeUnit.MINUTES);
-
-        String id1 = taskIds.poll();
-        String id2 = taskIds.poll();
-        String status1 = with()
-            .port(webAdminGuiceProbe.getWebAdminPort())
-            .get("/tasks/" + id1 + "/await")
-            .jsonPath()
-            .get("status");
-        String status2 = with()
-            .port(webAdminGuiceProbe.getWebAdminPort())
-            .get("/tasks/" + id2 + "/await")
-            .jsonPath()
-            .get("status");
-
-        assertThat(ImmutableList.of(status1, status2))
-            .containsOnly(
-                TaskManager.Status.COMPLETED.getValue(),
-                TaskManager.Status.FAILED.getValue());
-    }
-
-    @Test
     public void addressGroupsEndpointShouldHandleRequests() throws Exception {
         dataProbe.addAddressMapping("group", "domain.com", "user1@domain.com");
         dataProbe.addAddressMapping("group", "domain.com", "user2@domain.com");

http://git-wip-us.apache.org/repos/asf/james-project/blob/e4af1a8b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
index 1372c9b..d3b3046 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
@@ -201,26 +201,38 @@ public class CassandraMigrationRoutesTest {
     }
 
     @Test
-    public void postShouldNotDoMigrationWhenCurrentVersionIsNewerThan() throws Exception {
+    public void postShouldCreateTaskWhenCurrentVersionIsNewerThan() throws Exception {
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
 
-        Map<String, Object> errors = given()
+        String taskId =  given()
             .body(String.valueOf(OLDER_VERSION.getValue()))
         .with()
             .post("/upgrade")
+            .jsonPath()
+            .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
         .then()
-            .statusCode(HttpStatus.CONFLICT_409)
-            .contentType(ContentType.JSON)
-            .extract()
-            .body()
+            .body("status", is("completed"));
+    }
+
+    @Test
+    public void postShouldNotUpdateVersionWhenCurrentVersionIsNewerThan() throws Exception {
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
+
+        String taskId =  given()
+            .body(String.valueOf(OLDER_VERSION.getValue()))
+        .with()
+            .post("/upgrade")
             .jsonPath()
-            .getMap(".");
+            .get("taskId");
 
-        assertThat(errors)
-            .containsEntry("statusCode", HttpStatus.CONFLICT_409)
-            .containsEntry("type", "WrongState")
-            .containsEntry("message", "The migration requested can not be performed")
-            .containsEntry("cause", "Current version is already up to date");
+        with()
+            .basePath(TasksRoutes.BASE)
+            .get(taskId + "/await");
 
         verify(schemaVersionDAO, times(1)).getCurrentSchemaVersion();
         verifyNoMoreInteractions(schemaVersionDAO);
@@ -280,24 +292,34 @@ public class CassandraMigrationRoutesTest {
     }
 
     @Test
-    public void postShouldNotDoMigrationToLatestVersionWhenItIsUpToDate() throws Exception {
+    public void postShouldCreateTaskWhenItIsUpToDate() throws Exception {
         when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(LATEST_VERSION)));
 
-        Map<String, Object> errors = when()
+        String taskId = with()
             .post("/upgrade/latest")
+            .jsonPath()
+            .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
         .then()
-            .statusCode(HttpStatus.CONFLICT_409)
-            .contentType(ContentType.JSON)
-            .extract()
-            .body()
+            .body("status", is("completed"));
+    }
+
+    @Test
+    public void postShouldNotUpdateVersionWhenItIsUpToDate() throws Exception {
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(LATEST_VERSION)));
+
+        String taskId = with()
+            .post("/upgrade/latest")
             .jsonPath()
-            .getMap(".");
+            .get("taskId");
 
-        assertThat(errors)
-            .containsEntry("statusCode", HttpStatus.CONFLICT_409)
-            .containsEntry("type", "WrongState")
-            .containsEntry("message", "The migration requested can not be performed")
-            .containsEntry("cause", "Current version is already up to date");
+        with()
+            .basePath(TasksRoutes.BASE)
+            .get(taskId + "/await");
 
         verify(schemaVersionDAO, times(1)).getCurrentSchemaVersion();
         verifyNoMoreInteractions(schemaVersionDAO);


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


[17/21] james-project git commit: JAMES-2274 Allow to build package from specific docker image

Posted by bt...@apache.org.
JAMES-2274 Allow to build package from specific docker image


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

Branch: refs/heads/master
Commit: 0e6e17d5ab99bc5a373505252234607227eba976
Parents: 64d2d19
Author: benwa <bt...@linagora.com>
Authored: Thu Dec 28 13:18:03 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:12:47 2018 +0700

----------------------------------------------------------------------
 README.adoc                                      | 10 ++++++----
 dockerfiles/packaging/guice/cassandra/Dockerfile |  3 ++-
 2 files changed, 8 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/0e6e17d5/README.adoc
----------------------------------------------------------------------
diff --git a/README.adoc b/README.adoc
index 3df60ec..7e3acc9 100644
--- a/README.adoc
+++ b/README.adoc
@@ -357,11 +357,16 @@ You can generate a deb package and an RPM package for James by using the followi
 
 First step, you have to build the Docker image used to generate the package
 
-    $ docker build -t build-james-packages --build-arg RELEASE=3.0-beta6 --build-arg ITERATION=1 dockerfiles/packaging/guice/cassandra
+    $ docker build -t build-james-packages \
+        --build-arg RELEASE=3.0-beta6 \
+        --build-arg ITERATION=1 \
+        --build-arg BASE=linagora/james-project
+        dockerfiles/packaging/guice/cassandra
 
 Where:
 
 - ITERATION is the release number used after the last hyphen (e.g. 3.0-beta6-1, 3.0-beta6-2, 3.0-beta6-3...)
+- BASE is the image jar and executable are copied from. Defaults to linagora/james-project:latest
 
 Then, you have to run the container:
 
@@ -370,6 +375,3 @@ Then, you have to run the container:
 Where:
 
 - $PWD/result is the folder where the deb and the RPM packages will be copied
-
-This process will use the last generated docker image of James. You can change this behaviour by editing the first line of
-dockerfiles/packaging/Dockerfile and choose the source image you want to use.

http://git-wip-us.apache.org/repos/asf/james-project/blob/0e6e17d5/dockerfiles/packaging/guice/cassandra/Dockerfile
----------------------------------------------------------------------
diff --git a/dockerfiles/packaging/guice/cassandra/Dockerfile b/dockerfiles/packaging/guice/cassandra/Dockerfile
index eed4b0f..21b99c6 100644
--- a/dockerfiles/packaging/guice/cassandra/Dockerfile
+++ b/dockerfiles/packaging/guice/cassandra/Dockerfile
@@ -1,4 +1,5 @@
-FROM linagora/james-project:latest as source
+ARG BASE=linagora/james-project:latest
+FROM ${BASE} as source
 
 FROM debian:8.1
 


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


[18/21] james-project git commit: JAMES-2272 Docs: Add swagger documentation to TaskRoutes

Posted by bt...@apache.org.
JAMES-2272 Docs: Add swagger documentation to TaskRoutes


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

Branch: refs/heads/master
Commit: 54b790562692ced5a0fbfb420108caabc75035bd
Parents: 1561b6a
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 16:04:20 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:12:47 2018 +0700

----------------------------------------------------------------------
 .../routes/CassandraMigrationRoutes.java        | 161 +++++++++++++------
 .../james/webadmin/routes/TasksRoutes.java      |  62 ++++++-
 2 files changed, 170 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/54b79056/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
index bff6d1f..4ae87ed 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
@@ -20,6 +20,10 @@
 package org.apache.james.webadmin.routes;
 
 import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
 
 import org.apache.james.backends.cassandra.migration.CassandraMigrationService;
 import org.apache.james.backends.cassandra.migration.Migration;
@@ -36,8 +40,20 @@ import org.eclipse.jetty.http.HttpStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.ResponseHeader;
+import spark.Request;
+import spark.Response;
 import spark.Service;
 
+@Api(tags = "Cassandra migration")
+@Path(":cassandra/version")
+@Produces("application/json")
 public class CassandraMigrationRoutes implements Routes {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(CassandraMigrationRoutes.class);
@@ -65,54 +81,101 @@ public class CassandraMigrationRoutes implements Routes {
 
     @Override
     public void define(Service service) {
-        service.get(VERSION_BASE,
-            (request, response) -> new CassandraVersionResponse(cassandraMigrationService.getCurrentVersion()),
-            jsonTransformer);
-
-        service.get(VERSION_BASE_LATEST,
-            (request, response) -> new CassandraVersionResponse(cassandraMigrationService.getLatestVersion()),
-            jsonTransformer);
-
-        service.post(VERSION_UPGRADE_BASE, (request, response) -> {
-            LOGGER.debug("Cassandra upgrade launched");
-            try {
-                CassandraVersionRequest cassandraVersionRequest = CassandraVersionRequest.parse(request.body());
-                Migration migration = cassandraMigrationService.upgradeToVersion(cassandraVersionRequest.getValue());
-                TaskId taskId = taskManager.submit(migration);
-                return TaskIdDto.respond(response, taskId);
-            } catch (NullPointerException | IllegalArgumentException e) {
-                LOGGER.info(INVALID_VERSION_UPGRADE_REQUEST);
-                throw ErrorResponder.builder()
-                    .statusCode(HttpStatus.BAD_REQUEST_400)
-                    .type(ErrorType.INVALID_ARGUMENT)
-                    .message(INVALID_VERSION_UPGRADE_REQUEST)
-                    .cause(e)
-                    .haltError();
-            } catch (IllegalStateException e) {
-                LOGGER.info(MIGRATION_REQUEST_CAN_NOT_BE_DONE, e);
-                throw ErrorResponder.builder()
-                    .statusCode(HttpStatus.CONFLICT_409)
-                    .type(ErrorType.WRONG_STATE)
-                    .message(MIGRATION_REQUEST_CAN_NOT_BE_DONE)
-                    .cause(e)
-                    .haltError();
-            }
-        }, jsonTransformer);
-
-        service.post(VERSION_UPGRADE_TO_LATEST_BASE, (request, response) -> {
-            try {
-                Migration migration = cassandraMigrationService.upgradeToLastVersion();
-                TaskId taskId = taskManager.submit(migration);
-                return TaskIdDto.respond(response, taskId);
-            } catch (IllegalStateException e) {
-                LOGGER.info(MIGRATION_REQUEST_CAN_NOT_BE_DONE, e);
-                throw ErrorResponder.builder()
-                    .statusCode(HttpStatus.CONFLICT_409)
-                    .type(ErrorType.WRONG_STATE)
-                    .message(MIGRATION_REQUEST_CAN_NOT_BE_DONE)
-                    .cause(e)
-                    .haltError();
-            }
-        }, jsonTransformer);
+        service.get(VERSION_BASE, (request, response) -> getCassandraCurrentVersion(), jsonTransformer);
+
+        service.get(VERSION_BASE_LATEST, (request, response) -> getCassandraLatestVersion(), jsonTransformer);
+
+        service.post(VERSION_UPGRADE_BASE, this::upgradeToVersion, jsonTransformer);
+
+        service.post(VERSION_UPGRADE_TO_LATEST_BASE, (request, response) -> upgradeToLatest(response), jsonTransformer);
+    }
+
+    @POST
+    @Path("upgrade/latest")
+    @ApiOperation("Triggers a migration of Cassandra schema to the latest available")
+    @ApiResponses({
+        @ApiResponse(code = HttpStatus.CREATED_201, message = "The taskId of the given scheduled task", response = TaskIdDto.class,
+            responseHeaders = {
+                @ResponseHeader(name = "Location", description = "URL of the resource associated with the scheduled task")
+            }),
+        @ApiResponse(code = HttpStatus.CONFLICT_409, message = "Migration can not be done")
+    })
+    public Object upgradeToLatest(Response response) {
+        try {
+            Migration migration = cassandraMigrationService.upgradeToLastVersion();
+            TaskId taskId = taskManager.submit(migration);
+            return TaskIdDto.respond(response, taskId);
+        } catch (IllegalStateException e) {
+            LOGGER.info(MIGRATION_REQUEST_CAN_NOT_BE_DONE, e);
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.CONFLICT_409)
+                .type(ErrorType.WRONG_STATE)
+                .message(MIGRATION_REQUEST_CAN_NOT_BE_DONE)
+                .cause(e)
+                .haltError();
+        }
+    }
+
+    @POST
+    @Path("upgrade")
+    @ApiOperation("Triggers a migration of Cassandra schema to a specific version")
+    @ApiImplicitParams({
+        @ApiImplicitParam(
+            required = true,
+            paramType = "body",
+            dataType = "Integer",
+            example = "3",
+            value = "The schema version to upgrade to.")
+    })
+    @ApiResponses({
+        @ApiResponse(code = HttpStatus.CREATED_201, message = "The taskId of the given scheduled task", response = TaskIdDto.class,
+            responseHeaders = {
+            @ResponseHeader(name = "Location", description = "URL of the resource associated with the scheduled task")
+        }),
+        @ApiResponse(code = HttpStatus.CONFLICT_409, message = "Migration can not be done")
+    })
+    public Object upgradeToVersion(Request request, Response response) {
+        LOGGER.debug("Cassandra upgrade launched");
+        try {
+            CassandraVersionRequest cassandraVersionRequest = CassandraVersionRequest.parse(request.body());
+            Migration migration = cassandraMigrationService.upgradeToVersion(cassandraVersionRequest.getValue());
+            TaskId taskId = taskManager.submit(migration);
+            return TaskIdDto.from(taskId);
+        } catch (NullPointerException | IllegalArgumentException e) {
+            LOGGER.info(INVALID_VERSION_UPGRADE_REQUEST);
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorType.INVALID_ARGUMENT)
+                .message(INVALID_VERSION_UPGRADE_REQUEST)
+                .cause(e)
+                .haltError();
+        } catch (IllegalStateException e) {
+            LOGGER.info(MIGRATION_REQUEST_CAN_NOT_BE_DONE, e);
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.CONFLICT_409)
+                .type(ErrorType.WRONG_STATE)
+                .message(MIGRATION_REQUEST_CAN_NOT_BE_DONE)
+                .cause(e)
+                .haltError();
+        }
+    }
+
+    @GET
+    @Path("latest")
+    @ApiOperation(value = "Getting the latest version available for Cassandra schema")
+    @ApiResponses(value = {
+        @ApiResponse(code = HttpStatus.OK_200, message = "The latest version of the schema", response = CassandraVersionResponse.class)
+    })
+    public CassandraVersionResponse getCassandraLatestVersion() {
+        return new CassandraVersionResponse(cassandraMigrationService.getLatestVersion());
+    }
+
+    @GET
+    @ApiOperation(value = "Getting the current version used by Cassandra schema")
+    @ApiResponses(value = {
+        @ApiResponse(code = HttpStatus.OK_200, message = "The current version of the schema", response = CassandraVersionResponse.class)
+    })
+    public CassandraVersionResponse getCassandraCurrentVersion() {
+        return new CassandraVersionResponse(cassandraMigrationService.getCurrentVersion());
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/54b79056/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
index 99bd2df..9116b51 100644
--- a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/routes/TasksRoutes.java
@@ -19,11 +19,16 @@
 
 package org.apache.james.webadmin.routes;
 
+import java.util.List;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.function.Supplier;
 
 import javax.inject.Inject;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
 
 import org.apache.james.task.TaskExecutionDetails;
 import org.apache.james.task.TaskId;
@@ -36,10 +41,19 @@ import org.apache.james.webadmin.utils.ErrorResponder;
 import org.apache.james.webadmin.utils.JsonTransformer;
 import org.eclipse.jetty.http.HttpStatus;
 
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
 import spark.Request;
 import spark.Response;
 import spark.Service;
 
+@Api(tags = "Tasks")
+@Path(":task")
+@Produces("application/json")
 public class TasksRoutes implements Routes {
     public static final String BASE = "/tasks";
     private final TaskManager taskManager;
@@ -62,7 +76,24 @@ public class TasksRoutes implements Routes {
         service.get(BASE, this::list, jsonTransformer);
     }
 
-    private Object list(Request req, Response response) {
+    @GET
+    @ApiOperation(value = "Listing tasks")
+    @ApiImplicitParams({
+        @ApiImplicitParam(
+            required = false,
+            paramType = "query parameter",
+            dataType = "String",
+            defaultValue = "None",
+            example = "?status=inProgress",
+            value = "If present, allow to filter the tasks and keep only the one with a given status. " +
+                "The status are one of [waiting, inProgress, failed, canceled, completed]")
+    })
+    @ApiResponses(value = {
+        @ApiResponse(code = HttpStatus.OK_200, message = "A specific class execution details", response = List.class),
+        @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "The provided payload is invalid (JSON error or invalid status)"),
+        @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The taskId is not found")
+    })
+    public Object list(Request req, Response response) {
         try {
             return ExecutionDetailsDto.from(
                 Optional.ofNullable(req.queryParams("status"))
@@ -79,13 +110,29 @@ public class TasksRoutes implements Routes {
         }
     }
 
-    private Object getStatus(Request req, Response response) {
+    @GET
+    @Path("/{taskId}")
+    @ApiOperation(value = "Getting a task execution details")
+    @ApiResponses(value = {
+        @ApiResponse(code = HttpStatus.OK_200, message = "A specific class execution details", response = ExecutionDetailsDto.class),
+        @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "The taskId is invalid"),
+        @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The taskId is not found")
+    })
+    public Object getStatus(Request req, Response response) {
         TaskId taskId = getTaskId(req);
         return respondStatus(taskId,
             () -> taskManager.getExecutionDetails(getTaskId(req)));
     }
 
-    private Object await(Request req, Response response) {
+    @GET
+    @Path("/{taskId}/await")
+    @ApiOperation(value = "Await, then get a task execution details")
+    @ApiResponses(value = {
+        @ApiResponse(code = HttpStatus.OK_200, message = "A specific class execution details", response = ExecutionDetailsDto.class),
+        @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "The taskId is invalid"),
+        @ApiResponse(code = HttpStatus.NOT_FOUND_404, message = "The taskId is not found")
+    })
+    public Object await(Request req, Response response) {
         TaskId taskId = getTaskId(req);
         return respondStatus(taskId,
             () -> taskManager.await(getTaskId(req)));
@@ -104,7 +151,14 @@ public class TasksRoutes implements Routes {
         }
     }
 
-    private Object cancel(Request req, Response response) {
+    @DELETE
+    @Path("/{taskId}")
+    @ApiOperation(value = "Cancel a given task")
+    @ApiResponses(value = {
+        @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "Task is cancelled"),
+        @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "The taskId is invalid")
+    })
+    public Object cancel(Request req, Response response) {
         TaskId taskId = getTaskId(req);
         taskManager.cancel(taskId);
         response.status(HttpStatus.NO_CONTENT_204);


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


[07/21] james-project git commit: JAMES-2272 Guice injections for MemoryTaskManager

Posted by bt...@apache.org.
JAMES-2272 Guice injections for MemoryTaskManager


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

Branch: refs/heads/master
Commit: 4eeede95c0d82d66509d8b5ff2a669c19b21dd99
Parents: 8c1a067
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 12:15:24 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:03:36 2018 +0700

----------------------------------------------------------------------
 server/container/guice/guice-common/pom.xml     |  4 +++
 .../james/modules/CommonServicesModule.java     |  6 ++--
 .../james/modules/server/TaskManagerModule.java | 34 ++++++++++++++++++++
 3 files changed, 42 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/4eeede95/server/container/guice/guice-common/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/guice-common/pom.xml b/server/container/guice/guice-common/pom.xml
index 25a67c7..45f6696 100644
--- a/server/container/guice/guice-common/pom.xml
+++ b/server/container/guice/guice-common/pom.xml
@@ -129,6 +129,10 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>james-server-task</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>metrics-api</artifactId>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/4eeede95/server/container/guice/guice-common/src/main/java/org/apache/james/modules/CommonServicesModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/modules/CommonServicesModule.java b/server/container/guice/guice-common/src/main/java/org/apache/james/modules/CommonServicesModule.java
index 30d123e..f6f72ba 100644
--- a/server/container/guice/guice-common/src/main/java/org/apache/james/modules/CommonServicesModule.java
+++ b/server/container/guice/guice-common/src/main/java/org/apache/james/modules/CommonServicesModule.java
@@ -24,15 +24,16 @@ import java.util.Optional;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.apache.james.server.core.JamesServerResourceLoader;
-import org.apache.james.server.core.filesystem.FileSystemImpl;
 import org.apache.james.filesystem.api.FileSystem;
 import org.apache.james.filesystem.api.JamesDirectoriesProvider;
 import org.apache.james.modules.server.AsyncTasksExecutorModule;
 import org.apache.james.modules.server.ConfigurationProviderModule;
 import org.apache.james.modules.server.DNSServiceModule;
 import org.apache.james.modules.server.DropWizardMetricsModule;
+import org.apache.james.modules.server.TaskManagerModule;
 import org.apache.james.onami.lifecycle.PreDestroyModule;
+import org.apache.james.server.core.JamesServerResourceLoader;
+import org.apache.james.server.core.filesystem.FileSystemImpl;
 import org.apache.james.utils.DataProbeImpl;
 import org.apache.james.utils.GuiceProbe;
 
@@ -56,6 +57,7 @@ public class CommonServicesModule extends AbstractModule {
         install(new DNSServiceModule());
         install(new AsyncTasksExecutorModule());
         install(new DropWizardMetricsModule());
+        install(new TaskManagerModule());
 
         bind(FileSystemImpl.class).in(Scopes.SINGLETON);
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/4eeede95/server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/TaskManagerModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/TaskManagerModule.java b/server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/TaskManagerModule.java
new file mode 100644
index 0000000..b3d1e4f
--- /dev/null
+++ b/server/container/guice/guice-common/src/main/java/org/apache/james/modules/server/TaskManagerModule.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * 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.modules.server;
+
+import org.apache.james.task.MemoryTaskManager;
+import org.apache.james.task.TaskManager;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Scopes;
+
+public class TaskManagerModule extends AbstractModule {
+    @Override
+    protected void configure() {
+        bind(MemoryTaskManager.class).in(Scopes.SINGLETON);
+        bind(TaskManager.class).to(MemoryTaskManager.class);
+    }
+}


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


[08/21] james-project git commit: JAMES-2272 Memory implementation for TaskManager

Posted by bt...@apache.org.
JAMES-2272 Memory implementation for TaskManager


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

Branch: refs/heads/master
Commit: 8c1a06717a4fc694648a496e1cb0e2981a339ced
Parents: fbce4b0
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 11:47:04 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:03:36 2018 +0700

----------------------------------------------------------------------
 .../apache/james/task/MemoryTaskManager.java    | 156 +++++++
 .../apache/james/task/TaskExecutionDetails.java |  28 +-
 .../james/task/MemoryTaskManagerTest.java       | 434 +++++++++++++++++++
 3 files changed, 600 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/8c1a0671/server/task/src/main/java/org/apache/james/task/MemoryTaskManager.java
----------------------------------------------------------------------
diff --git a/server/task/src/main/java/org/apache/james/task/MemoryTaskManager.java b/server/task/src/main/java/org/apache/james/task/MemoryTaskManager.java
new file mode 100644
index 0000000..ddd37bb
--- /dev/null
+++ b/server/task/src/main/java/org/apache/james/task/MemoryTaskManager.java
@@ -0,0 +1,156 @@
+/****************************************************************
+ * 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.task;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.function.Consumer;
+
+import javax.annotation.PreDestroy;
+
+import org.apache.james.util.MDCBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+
+public class MemoryTaskManager implements TaskManager {
+    private static final boolean INTERRUPT_IF_RUNNING = true;
+    private static final Logger LOGGER = LoggerFactory.getLogger(MemoryTaskManager.class);
+
+    private final ConcurrentHashMap<TaskId, TaskExecutionDetails> idToExecutionDetails;
+    private final ConcurrentHashMap<TaskId, Future> idToFuture;
+    private final ExecutorService executor;
+
+    public MemoryTaskManager() {
+        idToExecutionDetails = new ConcurrentHashMap<>();
+        idToFuture = new ConcurrentHashMap<>();
+        executor = Executors.newSingleThreadExecutor();
+    }
+
+    @Override
+    public TaskId submit(Task task) {
+        return submit(task, id -> {});
+    }
+
+    @VisibleForTesting
+    TaskId submit(Task task, Consumer<TaskId> callback) {
+        TaskId taskId = TaskId.generateTaskId();
+        TaskExecutionDetails executionDetails = TaskExecutionDetails.from(task, taskId);
+
+        idToExecutionDetails.put(taskId, executionDetails);
+        idToFuture.put(taskId,
+            executor.submit(() -> runWithMdc(executionDetails, task, callback)));
+        return taskId;
+    }
+
+    private void runWithMdc(TaskExecutionDetails executionDetails, Task task, Consumer<TaskId> callback) {
+        MDCBuilder.withMdc(
+            MDCBuilder.create()
+                .addContext(Task.TASK_ID, executionDetails.getTaskId())
+                .addContext(Task.TASK_TYPE, executionDetails.getType())
+                .addContext(Task.TASK_DETAILS, executionDetails.getAdditionalInformation()),
+            () -> run(executionDetails, task, callback));
+    }
+
+    private void run(TaskExecutionDetails executionDetails, Task task, Consumer<TaskId> callback) {
+        TaskExecutionDetails started = executionDetails.start();
+        idToExecutionDetails.put(started.getTaskId(), started);
+        try {
+            task.run()
+                .onComplete(() -> success(started))
+                .onFailure(() -> failed(started,
+                    logger -> logger.info("Task was partially performed. Check logs for more details")));
+        } catch (Exception e) {
+            failed(started,
+                logger -> logger.error("Error while running task", executionDetails, e));
+        } finally {
+            idToFuture.remove(executionDetails.getTaskId());
+            callback.accept(executionDetails.getTaskId());
+        }
+    }
+
+    private void success(TaskExecutionDetails started) {
+        if (!wasCancelled(started.getTaskId())) {
+            idToExecutionDetails.put(started.getTaskId(), started.completed());
+            LOGGER.info("Task success");
+        }
+    }
+
+    private void failed(TaskExecutionDetails started, Consumer<Logger> logOperation) {
+        if (!wasCancelled(started.getTaskId())) {
+            idToExecutionDetails.put(started.getTaskId(), started.failed());
+            logOperation.accept(LOGGER);
+        }
+    }
+
+    private boolean wasCancelled(TaskId taskId) {
+        return idToExecutionDetails.get(taskId).getStatus() == Status.CANCELLED;
+    }
+
+    @Override
+    public TaskExecutionDetails getExecutionDetails(TaskId id) {
+        return Optional.ofNullable(idToExecutionDetails.get(id))
+            .orElseThrow(TaskNotFoundException::new);
+    }
+
+    @Override
+    public List<TaskExecutionDetails> list() {
+        return ImmutableList.copyOf(idToExecutionDetails.values());
+    }
+
+    @Override
+    public List<TaskExecutionDetails> list(Status status) {
+        return idToExecutionDetails.values()
+            .stream()
+            .filter(details -> details.getStatus().equals(status))
+            .collect(Guavate.toImmutableList());
+    }
+
+    @Override
+    public void cancel(TaskId id) {
+        Optional.ofNullable(idToFuture.get(id))
+            .ifPresent(future -> {
+                TaskExecutionDetails executionDetails = idToExecutionDetails.get(id);
+                idToExecutionDetails.put(id, executionDetails.cancel());
+                future.cancel(INTERRUPT_IF_RUNNING);
+                idToFuture.remove(id);
+            });
+    }
+
+    @Override
+    public TaskExecutionDetails await(TaskId id) {
+        Optional.ofNullable(idToFuture.get(id))
+            .ifPresent(Throwing.consumer(Future::get));
+        return getExecutionDetails(id);
+    }
+
+    @PreDestroy
+    public void stop() {
+        executor.shutdownNow();
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/8c1a0671/server/task/src/main/java/org/apache/james/task/TaskExecutionDetails.java
----------------------------------------------------------------------
diff --git a/server/task/src/main/java/org/apache/james/task/TaskExecutionDetails.java b/server/task/src/main/java/org/apache/james/task/TaskExecutionDetails.java
index 0122fa7..a95627c 100644
--- a/server/task/src/main/java/org/apache/james/task/TaskExecutionDetails.java
+++ b/server/task/src/main/java/org/apache/james/task/TaskExecutionDetails.java
@@ -33,9 +33,8 @@ public class TaskExecutionDetails {
     public static TaskExecutionDetails from(Task task, TaskId id) {
         return new TaskExecutionDetails(
             id,
-            task.type(),
+            task,
             TaskManager.Status.WAITING,
-            task.details(),
             Optional.of(ZonedDateTime.now()),
             Optional.empty(),
             Optional.empty(),
@@ -44,24 +43,21 @@ public class TaskExecutionDetails {
     }
 
     private final TaskId taskId;
-    private final String type;
+    private final Task task;
     private final TaskManager.Status status;
-    private final Optional<AdditionalInformation> additionalInformation;
     private final Optional<ZonedDateTime> submitDate;
     private final Optional<ZonedDateTime> startedDate;
     private final Optional<ZonedDateTime> completedDate;
     private final Optional<ZonedDateTime> canceledDate;
     private final Optional<ZonedDateTime> failedDate;
 
-    public TaskExecutionDetails(TaskId taskId, String type, TaskManager.Status status,
-                                Optional<AdditionalInformation> additionalInformation,
+    public TaskExecutionDetails(TaskId taskId, Task task, TaskManager.Status status,
                                 Optional<ZonedDateTime> submitDate, Optional<ZonedDateTime> startedDate,
                                 Optional<ZonedDateTime> completedDate, Optional<ZonedDateTime> canceledDate,
                                 Optional<ZonedDateTime> failedDate) {
         this.taskId = taskId;
-        this.type = type;
+        this.task = task;
         this.status = status;
-        this.additionalInformation = additionalInformation;
         this.submitDate = submitDate;
         this.startedDate = startedDate;
         this.completedDate = completedDate;
@@ -74,7 +70,7 @@ public class TaskExecutionDetails {
     }
 
     public String getType() {
-        return type;
+        return task.type();
     }
 
     public TaskManager.Status getStatus() {
@@ -82,7 +78,7 @@ public class TaskExecutionDetails {
     }
 
     public Optional<AdditionalInformation> getAdditionalInformation() {
-        return additionalInformation;
+        return task.details();
     }
 
     public Optional<ZonedDateTime> getSubmitDate() {
@@ -109,9 +105,8 @@ public class TaskExecutionDetails {
         Preconditions.checkState(status == TaskManager.Status.WAITING);
         return new TaskExecutionDetails(
             taskId,
-            type,
+            task,
             TaskManager.Status.IN_PROGRESS,
-            additionalInformation,
             submitDate,
             Optional.of(ZonedDateTime.now()),
             Optional.empty(),
@@ -123,9 +118,8 @@ public class TaskExecutionDetails {
         Preconditions.checkState(status == TaskManager.Status.IN_PROGRESS);
         return new TaskExecutionDetails(
             taskId,
-            type,
+            task,
             TaskManager.Status.COMPLETED,
-            additionalInformation,
             submitDate,
             startedDate,
             Optional.of(ZonedDateTime.now()),
@@ -137,9 +131,8 @@ public class TaskExecutionDetails {
         Preconditions.checkState(status == TaskManager.Status.IN_PROGRESS);
         return new TaskExecutionDetails(
             taskId,
-            type,
+            task,
             TaskManager.Status.FAILED,
-            additionalInformation,
             submitDate,
             startedDate,
             Optional.empty(),
@@ -152,9 +145,8 @@ public class TaskExecutionDetails {
             || status == TaskManager.Status.WAITING);
         return new TaskExecutionDetails(
             taskId,
-            type,
+            task,
             TaskManager.Status.CANCELLED,
-            additionalInformation,
             submitDate,
             startedDate,
             Optional.empty(),

http://git-wip-us.apache.org/repos/asf/james-project/blob/8c1a0671/server/task/src/test/java/org/apache/james/task/MemoryTaskManagerTest.java
----------------------------------------------------------------------
diff --git a/server/task/src/test/java/org/apache/james/task/MemoryTaskManagerTest.java b/server/task/src/test/java/org/apache/james/task/MemoryTaskManagerTest.java
new file mode 100644
index 0000000..0b7005a
--- /dev/null
+++ b/server/task/src/test/java/org/apache/james/task/MemoryTaskManagerTest.java
@@ -0,0 +1,434 @@
+/****************************************************************
+ * 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.task;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.assertj.core.api.JUnitSoftAssertions;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.github.fge.lambdas.Throwing;
+import com.github.fge.lambdas.consumers.ConsumerChainer;
+import com.google.common.base.Throwables;
+
+public class MemoryTaskManagerTest {
+
+    private MemoryTaskManager memoryTaskManager;
+
+    @Rule
+    public JUnitSoftAssertions softly = new JUnitSoftAssertions();
+
+    @Before
+    public void setUp() {
+        memoryTaskManager = new MemoryTaskManager();
+    }
+
+    @After
+    public void tearDown() {
+        memoryTaskManager.stop();
+    }
+
+    @Test
+    public void getStatusShouldReturnUnknownWhenUnknownId() {
+        TaskId unknownId = TaskId.generateTaskId();
+        assertThatThrownBy(() -> memoryTaskManager.getExecutionDetails(unknownId))
+            .isInstanceOf(TaskNotFoundException.class);
+    }
+
+    @Test
+    public void getStatusShouldReturnWaitingWhenNotYetProcessed() {
+        CountDownLatch task1Latch = new CountDownLatch(1);
+
+        memoryTaskManager.submit(() -> {
+            await(task1Latch);
+            return Task.Result.COMPLETED;
+        });
+
+        TaskId taskId = memoryTaskManager.submit(() -> Task.Result.COMPLETED);
+
+        assertThat(memoryTaskManager.getExecutionDetails(taskId).getStatus())
+            .isEqualTo(TaskManager.Status.WAITING);
+    }
+
+    @Test
+    public void taskCodeAfterCancelIsNotRun() {
+        CountDownLatch task1Latch = new CountDownLatch(1);
+        AtomicInteger count = new AtomicInteger(0);
+
+        TaskId id = memoryTaskManager.submit(() -> {
+            await(task1Latch);
+            count.incrementAndGet();
+            return Task.Result.COMPLETED;
+        });
+
+        memoryTaskManager.cancel(id);
+        task1Latch.countDown();
+
+        assertThat(count.get()).isEqualTo(0);
+    }
+
+    @Test
+    public void getStatusShouldReturnCancelledWhenCancelled() throws Exception {
+        CountDownLatch task1Latch = new CountDownLatch(1);
+        CountDownLatch ensureStartedLatch = new CountDownLatch(1);
+        CountDownLatch ensureFinishedLatch = new CountDownLatch(1);
+
+        TaskId id = memoryTaskManager.submit(() -> {
+            ensureStartedLatch.countDown();
+            await(task1Latch);
+            return Task.Result.COMPLETED;
+        },
+            any -> ensureFinishedLatch.countDown());
+
+        ensureStartedLatch.await();
+        memoryTaskManager.cancel(id);
+        ensureFinishedLatch.await();
+
+        assertThat(memoryTaskManager.getExecutionDetails(id).getStatus())
+            .isEqualTo(TaskManager.Status.CANCELLED);
+    }
+
+    @Test
+    public void cancelShouldBeIdempotent() {
+        CountDownLatch task1Latch = new CountDownLatch(1);
+
+        TaskId id = memoryTaskManager.submit(() -> {
+            await(task1Latch);
+            return Task.Result.COMPLETED;
+        });
+
+        memoryTaskManager.cancel(id);
+        assertThatCode(() -> memoryTaskManager.cancel(id))
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    public void getStatusShouldReturnInProgressWhenProcessingIsInProgress() throws Exception {
+        CountDownLatch latch1 = new CountDownLatch(1);
+        CountDownLatch latch2 = new CountDownLatch(1);
+
+        TaskId taskId = memoryTaskManager.submit(() -> {
+            latch2.countDown();
+            await(latch1);
+            return Task.Result.COMPLETED;
+        });
+        latch2.await();
+
+        assertThat(memoryTaskManager.getExecutionDetails(taskId).getStatus())
+            .isEqualTo(TaskManager.Status.IN_PROGRESS);
+    }
+
+    @Test
+    public void getStatusShouldReturnCompletedWhenRunSuccessfully() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+
+        TaskId taskId = memoryTaskManager.submit(
+            () -> Task.Result.COMPLETED,
+            countDownCallback(latch));
+
+        latch.await();
+
+        assertThat(memoryTaskManager.getExecutionDetails(taskId).getStatus())
+            .isEqualTo(TaskManager.Status.COMPLETED);
+    }
+
+    @Test
+    public void getStatusShouldReturnFailedWhenRunPartially() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+
+        TaskId taskId = memoryTaskManager.submit(
+            () -> Task.Result.PARTIAL,
+            countDownCallback(latch));
+
+        latch.await();
+
+        assertThat(memoryTaskManager.getExecutionDetails(taskId).getStatus())
+            .isEqualTo(TaskManager.Status.FAILED);
+    }
+
+    private ConsumerChainer<TaskId> countDownCallback(CountDownLatch latch) {
+        return Throwing.consumer(id -> latch.countDown());
+    }
+
+    @Test
+    public void listShouldReturnTaskSatus() throws Exception {
+        CountDownLatch latch1 = new CountDownLatch(1);
+        CountDownLatch latch2 = new CountDownLatch(1);
+        CountDownLatch latch3 = new CountDownLatch(1);
+
+        TaskId failedId = memoryTaskManager.submit(
+            () -> Task.Result.PARTIAL);
+        TaskId successfulId = memoryTaskManager.submit(
+            () -> Task.Result.COMPLETED);
+        TaskId inProgressId = memoryTaskManager.submit(
+            () -> {
+                await(latch1);
+                latch2.countDown();
+                await(latch3);
+                return Task.Result.COMPLETED;
+            });
+        TaskId waitingId = memoryTaskManager.submit(
+            () -> {
+                await(latch3);
+                latch2.countDown();
+                return Task.Result.COMPLETED;
+            });
+
+        latch1.countDown();
+        latch2.await();
+
+        List<TaskExecutionDetails> list = memoryTaskManager.list();
+        softly.assertThat(list).hasSize(4);
+        softly.assertThat(entryWithId(list, failedId))
+            .isEqualTo(TaskManager.Status.FAILED);
+        softly.assertThat(entryWithId(list, waitingId))
+            .isEqualTo(TaskManager.Status.WAITING);
+        softly.assertThat(entryWithId(list, successfulId))
+            .isEqualTo(TaskManager.Status.COMPLETED);
+        softly.assertThat(entryWithId(list, inProgressId))
+            .isEqualTo(TaskManager.Status.IN_PROGRESS);
+    }
+
+    private TaskManager.Status entryWithId(List<TaskExecutionDetails> list, TaskId taskId) {
+        return list.stream()
+            .filter(e -> e.getTaskId().equals(taskId))
+            .findFirst().get()
+            .getStatus();
+    }
+
+    @Test
+    public void listShouldAllowToSeeWaitingTasks() throws Exception {
+        CountDownLatch latch1 = new CountDownLatch(1);
+        CountDownLatch latch2 = new CountDownLatch(1);
+        CountDownLatch latch3 = new CountDownLatch(1);
+
+        memoryTaskManager.submit(
+            () -> Task.Result.PARTIAL);
+        memoryTaskManager.submit(
+            () -> Task.Result.COMPLETED);
+        memoryTaskManager.submit(
+            () -> {
+                await(latch1);
+                latch2.countDown();
+                await(latch3);
+                return Task.Result.COMPLETED;
+            });
+        TaskId waitingId = memoryTaskManager.submit(
+            () -> {
+                await(latch3);
+                latch2.countDown();
+                return Task.Result.COMPLETED;
+            });
+
+        latch1.countDown();
+        latch2.await();
+
+        assertThat(memoryTaskManager.list(TaskManager.Status.WAITING))
+            .extracting(TaskExecutionDetails::getTaskId)
+            .containsOnly(waitingId);
+    }
+
+    @Test
+    public void listShouldAllowToSeeInProgressTasks() throws Exception {
+        CountDownLatch latch1 = new CountDownLatch(1);
+        CountDownLatch latch2 = new CountDownLatch(1);
+        CountDownLatch latch3 = new CountDownLatch(1);
+
+        memoryTaskManager.submit(
+            () -> Task.Result.PARTIAL);
+        TaskId successfulId = memoryTaskManager.submit(
+            () -> Task.Result.COMPLETED);
+        memoryTaskManager.submit(
+            () -> {
+                await(latch1);
+                latch2.countDown();
+                await(latch3);
+                return Task.Result.COMPLETED;
+            });
+        memoryTaskManager.submit(
+            () -> {
+                await(latch3);
+                latch2.countDown();
+                return Task.Result.COMPLETED;
+            });
+
+        latch1.countDown();
+        latch2.await();
+
+        assertThat(memoryTaskManager.list(TaskManager.Status.COMPLETED))
+            .extracting(TaskExecutionDetails::getTaskId)
+            .containsOnly(successfulId);
+    }
+
+    @Test
+    public void listShouldAllowToSeeFailedTasks() throws Exception {
+        CountDownLatch latch1 = new CountDownLatch(1);
+        CountDownLatch latch2 = new CountDownLatch(1);
+        CountDownLatch latch3 = new CountDownLatch(1);
+
+        TaskId failedId = memoryTaskManager.submit(
+            () -> Task.Result.PARTIAL);
+        memoryTaskManager.submit(
+            () -> Task.Result.COMPLETED);
+        memoryTaskManager.submit(
+            () -> {
+                await(latch1);
+                latch2.countDown();
+                await(latch3);
+                return Task.Result.COMPLETED;
+            });
+        memoryTaskManager.submit(
+            () -> {
+                await(latch3);
+                latch2.countDown();
+                return Task.Result.COMPLETED;
+            });
+
+        latch1.countDown();
+        latch2.await();
+
+        assertThat(memoryTaskManager.list(TaskManager.Status.FAILED))
+            .extracting(TaskExecutionDetails::getTaskId)
+            .containsOnly(failedId);
+    }
+
+    @Test
+    public void listShouldAllowToSeeSuccessfulTasks() throws Exception {
+        CountDownLatch latch1 = new CountDownLatch(1);
+        CountDownLatch latch2 = new CountDownLatch(1);
+        CountDownLatch latch3 = new CountDownLatch(1);
+
+        memoryTaskManager.submit(
+            () -> Task.Result.PARTIAL);
+        memoryTaskManager.submit(
+            () -> Task.Result.COMPLETED);
+        TaskId inProgressId = memoryTaskManager.submit(
+            () -> {
+                await(latch1);
+                latch2.countDown();
+                await(latch3);
+                return Task.Result.COMPLETED;
+            });
+        memoryTaskManager.submit(
+            () -> {
+                await(latch3);
+                latch2.countDown();
+                return Task.Result.COMPLETED;
+            });
+
+        latch1.countDown();
+        latch2.await();
+
+        assertThat(memoryTaskManager.list(TaskManager.Status.IN_PROGRESS))
+            .extracting(TaskExecutionDetails::getTaskId)
+            .containsOnly(inProgressId);
+    }
+
+    @Test
+    public void listShouldBeEmptyWhenNoTasks() throws Exception {
+        assertThat(memoryTaskManager.list()).isEmpty();
+    }
+
+    @Test
+    public void listCancelledShouldBeEmptyWhenNoTasks() throws Exception {
+        assertThat(memoryTaskManager.list(TaskManager.Status.CANCELLED)).isEmpty();
+    }
+
+    @Test
+    public void awaitShouldNotThrowWhenCompletedTask() throws Exception {
+        TaskId taskId = memoryTaskManager.submit(
+            () -> Task.Result.COMPLETED);
+        memoryTaskManager.await(taskId);
+        memoryTaskManager.await(taskId);
+    }
+
+    @Test
+    public void submittedTaskShouldExecuteSequentially() {
+        ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();
+
+        TaskId id1 = memoryTaskManager.submit(() -> {
+            queue.add(1);
+            sleep(500);
+            queue.add(2);
+            return Task.Result.COMPLETED;
+        });
+        TaskId id2 = memoryTaskManager.submit(() -> {
+            queue.add(3);
+            sleep(500);
+            queue.add(4);
+            return Task.Result.COMPLETED;
+        });
+        memoryTaskManager.await(id1);
+        memoryTaskManager.await(id2);
+
+        assertThat(queue)
+            .containsExactly(1, 2, 3, 4);
+    }
+
+    @Test
+    public void awaitShouldReturnFailedWhenExceptionThrown() {
+        TaskId taskId = memoryTaskManager.submit(() -> {
+            throw new RuntimeException();
+        });
+
+        TaskExecutionDetails executionDetails = memoryTaskManager.await(taskId);
+
+        assertThat(executionDetails.getStatus())
+            .isEqualTo(TaskManager.Status.FAILED);
+    }
+
+    @Test
+    public void getStatusShouldReturnFailedWhenExceptionThrown() {
+        TaskId taskId = memoryTaskManager.submit(() -> {
+            throw new RuntimeException();
+        });
+
+        memoryTaskManager.await(taskId);
+
+        assertThat(memoryTaskManager.getExecutionDetails(taskId).getStatus())
+            .isEqualTo(TaskManager.Status.FAILED);
+    }
+
+    public void sleep(int durationInMs) {
+        try {
+            Thread.sleep(durationInMs);
+        } catch (InterruptedException e) {
+            Throwables.propagate(e);
+        }
+    }
+
+    public void await(CountDownLatch countDownLatch) {
+        try {
+            countDownLatch.await();
+        } catch (InterruptedException e) {
+            Throwables.propagate(e);
+        }
+    }
+}
\ 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


[21/21] james-project git commit: JAMES-2272 Docs: Document Task API and Cassandra migration API changes on the website

Posted by bt...@apache.org.
JAMES-2272 Docs: Document Task API and Cassandra migration API changes on the website


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

Branch: refs/heads/master
Commit: 1561b6afca5a65b813c23410e749f943460e8d97
Parents: 45eec2e
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 15:43:26 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:12:47 2018 +0700

----------------------------------------------------------------------
 src/site/markdown/server/manage-webadmin.md | 147 +++++++++++++++++++++--
 1 file changed, 138 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/1561b6af/src/site/markdown/server/manage-webadmin.md
----------------------------------------------------------------------
diff --git a/src/site/markdown/server/manage-webadmin.md b/src/site/markdown/server/manage-webadmin.md
index e0f59af..10347ea 100644
--- a/src/site/markdown/server/manage-webadmin.md
+++ b/src/site/markdown/server/manage-webadmin.md
@@ -405,37 +405,67 @@ Response codes:
 curl -XPOST http://ip:port/cassandra/version/upgrade -d '3'
 ```
 
-Will run the migrations you need to reach schema version 3.
+
+Will schedule the run of the migrations you need to reach schema version 3. The `taskId` will allow you to monitor and manage this process.
+
+```
+{"taskId":"3294a976-ce63-491e-bd52-1b6f465ed7a2"}
+```
 
 Response codes:
 
- - 204: Success
+ - 200: Success. The scheduled task taskId is returned.
  - 400: The version is invalid. The version should be a strictly positive number.
- - 410: Error running the migration. This resource is gone away. Reason is mentionned in the body.
- - 500: Internal error. This can result from a partial migration, in which case the reason is contained in the body.
+ - 410: Error while planning this migration. This resource is gone away. Reason is mentionned in the body.
+ - 500: Internal error while creating the migration task.
 
 Note that several calls to this endpoint will be run in a sequential pattern.
 
 If the server restarts during the migration, the migration is silently aborted.
 
+
+The scheduled task will have the following type `CassandraMigration` and the following `additionalInformation`:
+
+```
+{"toVersion":3}
+```
+
 ### Upgrading to the latest version
 
 ```
 curl -XPOST http://ip:port/cassandra/version/upgrade/latest
 ```
 
-Will run the migrations you need to reach the latest schema version.
+Will schedule the run of the migrations you need to reach the latest schema version. The `taskId` will allow you to monitor and manage this process.
+
+```
+{"taskId":"3294a976-ce63-491e-bd52-1b6f465ed7a2"}
+```
+
+Positionned headers:
+
+ - Location header indicates the location of the resource associated with the scheduled task. Example:
+
+```
+Location: /tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2
+```
 
 Response codes:
 
- - 204: Success
- - 410: Error running the migration. This resource is gone away. Reason is mentionned in the body.
- - 500: Internal error. This can result from a partial migration, in which case the reason is contained in the body.
+ - 200: Success. The scheduled task taskId is returned.
+ - 410: Error while planning this migration. This resource is gone away. Reason is mentionned in the body.
+ - 500: Internal error while creating the migration task.
 
 Note that several calls to this endpoint will be run in a sequential pattern.
 
 If the server restarts during the migration, the migration is silently aborted.
 
+The scheduled task will have the following type `CassandraMigration` and the following `additionalInformation`:
+
+```
+{"toVersion":2}
+```
+
 ## Creating address group
 
 You can use **webadmin** to define address groups.
@@ -512,4 +542,103 @@ Response codes:
 
  - 200: Success
  - 400: Group structure or member is not valid
- - 500: Internal error
\ No newline at end of file
+ - 500: Internal error
+
+## Task management
+
+Some webadmin features schedules tasks. The task management API allow to monitor and manage the execution of the following tasks.
+
+Note that the `taskId` used in the following APIs is returned by other WebAdmin APIs scheduling tasks.
+
+### Getting a task details
+
+```
+curl -XGET http://ip:port/tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2
+```
+
+An Execution Report will be returned:
+
+```
+{
+    "submitDate": "2017-12-27T15:15:24.805+0700",
+    "startedDate": "2017-12-27T15:15:24.809+0700",
+    "completedDate": "2017-12-27T15:15:24.815+0700",
+    "cancelledDate": null,
+    "failedDate": null,
+    "taskId": "3294a976-ce63-491e-bd52-1b6f465ed7a2",
+    "additionalInformation": {},
+    "status": "completed",
+    "type": "typeOfTheTask"
+}
+```
+
+Note that:
+
+ - `status` can have the value:
+    - `waiting`: The task is schedule but its execution did not start yet
+    - `inProgress`: The task is currently executed
+    - `cancelled`: The task had been cancelled
+    - `completed`: The task execution is finished, and this execution is a success
+    - `failed`: The task execution is finished, and this execution is a failure
+
+ - `additionalInformation` is a task specific object giving additional informationa and context about that task. The structure
+   of this `additionalInformation` field is provided along the specific task submission endpoint.
+
+Response codes:
+
+ - 200: The specific task was found and the execution report exposed above is returned
+ - 400: Invalid task ID
+ - 404: Task ID was not found
+
+### Awaiting a task
+
+One can await the end of a task, then receive it's final execution report.
+
+That feature is especially usefull for testing purpose but still can serve real-life scenari.
+
+```
+curl -XGET http://ip:port/tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2/await
+```
+
+An Execution Report will be returned.
+
+Response codes:
+
+ - 200: The specific task was found and the execution report exposed above is returned
+ - 400: Invalid task ID
+ - 404: Task ID was not found
+
+### Cancelling a task
+
+You can cancel a task by calling:
+
+```
+curl -XDELETE http://ip:port/tasks/3294a976-ce63-491e-bd52-1b6f465ed7a2
+```
+
+Response codes:
+ - 204: Task had been cancelled
+ - 400: Invalid task ID
+
+### Listing tasks
+
+A list of all tasks can be retrieved:
+
+```
+curl -XGET /tasks
+```
+
+Will return a list of Execution reports
+
+One can filter the above results by status. For example:
+
+```
+curl -XGET /tasks?status=inProgress
+```
+
+Will return a list of Execution reports that are currently in progress.
+
+Response codes:
+
+ - 200: A list of corresponding tasks is returned
+ - 400: Invalid status value
\ 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


[12/21] james-project git commit: JAMES-2272 Docs: Swagger doc for Cassandra migrations

Posted by bt...@apache.org.
JAMES-2272 Docs: Swagger doc for Cassandra migrations


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

Branch: refs/heads/master
Commit: 7e95d7a5aae326fa7852db87902c423122322321
Parents: 54b7905
Author: benwa <bt...@linagora.com>
Authored: Wed Jan 3 14:39:52 2018 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:12:47 2018 +0700

----------------------------------------------------------------------
 src/site/markdown/server/manage-webadmin.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/7e95d7a5/src/site/markdown/server/manage-webadmin.md
----------------------------------------------------------------------
diff --git a/src/site/markdown/server/manage-webadmin.md b/src/site/markdown/server/manage-webadmin.md
index 10347ea..d73651f 100644
--- a/src/site/markdown/server/manage-webadmin.md
+++ b/src/site/markdown/server/manage-webadmin.md
@@ -575,13 +575,13 @@ An Execution Report will be returned:
 Note that:
 
  - `status` can have the value:
-    - `waiting`: The task is schedule but its execution did not start yet
+    - `waiting`: The task is scheduled but its execution did not start yet
     - `inProgress`: The task is currently executed
     - `cancelled`: The task had been cancelled
     - `completed`: The task execution is finished, and this execution is a success
     - `failed`: The task execution is finished, and this execution is a failure
 
- - `additionalInformation` is a task specific object giving additional informationa and context about that task. The structure
+ - `additionalInformation` is a task specific object giving additional information and context about that task. The structure
    of this `additionalInformation` field is provided along the specific task submission endpoint.
 
 Response codes:


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


[04/21] james-project git commit: JAMES-2272 Cassandra migration service should be located in Cassandra back-end

Posted by bt...@apache.org.
JAMES-2272 Cassandra migration service should be located in Cassandra back-end

That will makes running Cassandra migration more generic and would be a good move toward CLI 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/b87d49c7
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/b87d49c7
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/b87d49c7

Branch: refs/heads/master
Commit: b87d49c79df4961d9975469babb94f51958dac03
Parents: 3f26590
Author: benwa <bt...@linagora.com>
Authored: Wed Dec 27 11:36:45 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Thu Jan 4 15:00:43 2018 +0700

----------------------------------------------------------------------
 .../migration/CassandraMigrationService.java    |  96 +++++++
 .../cassandra/migration/MigrationException.java |  26 ++
 .../CassandraMigrationServiceTest.java          | 260 ++++++++++++++++++
 .../modules/server/CassandraRoutesModule.java   |   2 +-
 .../routes/CassandraMigrationRoutes.java        |   4 +-
 .../service/CassandraMigrationService.java      |  98 -------
 .../webadmin/service/MigrationException.java    |  26 --
 .../routes/CassandraMigrationRoutesTest.java    |   2 +-
 .../service/CassandraMigrationServiceTest.java  | 261 -------------------
 9 files changed, 386 insertions(+), 389 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/b87d49c7/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
new file mode 100644
index 0000000..0eb80aa
--- /dev/null
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/CassandraMigrationService.java
@@ -0,0 +1,96 @@
+/****************************************************************
+ * 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.backends.cassandra.migration;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.IntStream;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class CassandraMigrationService {
+    public static final String LATEST_VERSION = "latestVersion";
+    private final CassandraSchemaVersionDAO schemaVersionDAO;
+    private final int latestVersion;
+    private final Map<Integer, Migration> allMigrationClazz;
+    private final Logger LOG = LoggerFactory.getLogger(CassandraMigrationService.class);
+
+    @Inject
+    public CassandraMigrationService(CassandraSchemaVersionDAO schemaVersionDAO, Map<Integer, Migration> allMigrationClazz, @Named(LATEST_VERSION) int latestVersion) {
+        Preconditions.checkArgument(latestVersion >= 0, "The latest version must be positive");
+        this.schemaVersionDAO = schemaVersionDAO;
+        this.latestVersion = latestVersion;
+        this.allMigrationClazz = allMigrationClazz;
+    }
+
+    public Optional<Integer> getCurrentVersion() {
+        return schemaVersionDAO.getCurrentSchemaVersion().join();
+    }
+
+    public Optional<Integer> getLatestVersion() {
+        return Optional.of(latestVersion);
+    }
+
+    public synchronized void upgradeToVersion(int newVersion) {
+        int currentVersion = schemaVersionDAO.getCurrentSchemaVersion().join().orElse(CassandraSchemaVersionManager.DEFAULT_VERSION);
+        if (currentVersion >= newVersion) {
+            throw new IllegalStateException("Current version is already up to date");
+        }
+
+        IntStream.range(currentVersion, newVersion)
+            .boxed()
+            .forEach(this::doMigration);
+    }
+
+    public void upgradeToLastVersion() {
+        upgradeToVersion(latestVersion);
+    }
+
+    private void doMigration(Integer version) {
+        if (allMigrationClazz.containsKey(version)) {
+            LOG.info("Migrating to version {} ", version + 1);
+            Migration.Result migrationResult = allMigrationClazz.get(version).run();
+            if (migrationResult == Migration.Result.COMPLETED) {
+                schemaVersionDAO.updateVersion(version + 1);
+                LOG.info("Migrating to version {} done", version + 1);
+            } else {
+                String message = String.format("Migrating to version %d partially done. " +
+                    "Please check logs for cause of failure and re-run this migration.",
+                    version + 1);
+                LOG.warn(message);
+                throw new MigrationException(message);
+            }
+        } else {
+            String message = String.format("Can not migrate to %d. No migration class registered.", version + 1);
+            LOG.error(message);
+            throw new NotImplementedException(message);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/b87d49c7/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationException.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationException.java b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationException.java
new file mode 100644
index 0000000..41aa423
--- /dev/null
+++ b/backends-common/cassandra/src/main/java/org/apache/james/backends/cassandra/migration/MigrationException.java
@@ -0,0 +1,26 @@
+/****************************************************************
+ * 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.backends.cassandra.migration;
+
+public class MigrationException extends RuntimeException {
+    public MigrationException(String message) {
+        super(message);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/b87d49c7/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
----------------------------------------------------------------------
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
new file mode 100644
index 0000000..fa2a29f
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/migration/CassandraMigrationServiceTest.java
@@ -0,0 +1,260 @@
+/****************************************************************
+ * 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.backends.cassandra.migration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.datastax.driver.core.Session;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
+
+public class CassandraMigrationServiceTest {
+    private static final int LATEST_VERSION = 3;
+    private static final int CURRENT_VERSION = 2;
+    private static final int OLDER_VERSION = 1;
+    private CassandraMigrationService testee;
+    private CassandraSchemaVersionDAO schemaVersionDAO;
+    private ExecutorService executorService;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+    private Migration successfulMigration;
+
+    @Before
+    public void setUp() throws Exception {
+        schemaVersionDAO = mock(CassandraSchemaVersionDAO.class);
+        successfulMigration = mock(Migration.class);
+        when(successfulMigration.run()).thenReturn(Migration.Result.COMPLETED);
+        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+            .put(OLDER_VERSION, successfulMigration)
+            .put(CURRENT_VERSION, successfulMigration)
+            .put(LATEST_VERSION, successfulMigration)
+            .build();
+        testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION);
+        executorService = Executors.newFixedThreadPool(2);
+    }
+
+    @After
+    public void tearDown() {
+        executorService.shutdownNow();
+    }
+
+    @Test
+    public void getCurrentVersionShouldReturnCurrentVersion() throws Exception {
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
+
+        assertThat(testee.getCurrentVersion().get()).isEqualTo(CURRENT_VERSION);
+    }
+
+    @Test
+    public void getLatestVersionShouldReturnTheLatestVersion() throws Exception {
+        assertThat(testee.getLatestVersion().get()).isEqualTo(LATEST_VERSION);
+    }
+
+    @Test
+    public void upgradeToVersionShouldThrowWhenCurrentVersionIsUpToDate() throws Exception {
+        expectedException.expect(IllegalStateException.class);
+
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
+
+        testee.upgradeToVersion(OLDER_VERSION);
+    }
+
+    @Test
+    public void upgradeToVersionShouldUpdateToVersion() throws Exception {
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+
+        testee.upgradeToVersion(CURRENT_VERSION);
+
+        verify(schemaVersionDAO, times(1)).updateVersion(eq(CURRENT_VERSION));
+    }
+
+    @Test
+    public void upgradeToLastVersionShouldThrowWhenVersionIsUpToDate() throws Exception {
+        expectedException.expect(IllegalStateException.class);
+
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(LATEST_VERSION)));
+
+        testee.upgradeToLastVersion();
+    }
+
+    @Test
+    public void upgradeToLastVersionShouldUpdateToLatestVersion() throws Exception {
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+
+        testee.upgradeToLastVersion();
+
+        verify(schemaVersionDAO, times(1)).updateVersion(eq(LATEST_VERSION));
+    }
+
+    @Test
+    public void upgradeToVersionShouldThrowOnMissingVersion() throws Exception {
+        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+            .put(OLDER_VERSION, successfulMigration)
+            .put(LATEST_VERSION, successfulMigration)
+            .build();
+        testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION);
+        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+
+        expectedException.expect(NotImplementedException.class);
+
+        testee.upgradeToVersion(LATEST_VERSION);
+    }
+
+    @Test
+    public void upgradeToVersionShouldUpdateIntermediarySuccessfulMigrationsInCaseOfError() throws Exception {
+        try {
+            Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+                .put(OLDER_VERSION, successfulMigration)
+                .put(LATEST_VERSION, successfulMigration)
+                .build();
+            testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION);
+            when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
+
+            expectedException.expect(RuntimeException.class);
+
+            testee.upgradeToVersion(LATEST_VERSION);
+        } finally {
+            verify(schemaVersionDAO).updateVersion(CURRENT_VERSION);
+        }
+    }
+
+    @Test
+    public void concurrentMigrationsShouldFail() throws Exception {
+        // Given a stateful migration service
+        Migration wait1SecondMigration = mock(Migration.class);
+        doAnswer(invocation -> {
+            Thread.sleep(1000);
+            return Migration.Result.COMPLETED;
+        }).when(wait1SecondMigration).run();
+        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+            .put(OLDER_VERSION, wait1SecondMigration)
+            .put(CURRENT_VERSION, wait1SecondMigration)
+            .put(LATEST_VERSION, wait1SecondMigration)
+            .build();
+        testee = new CassandraMigrationService(new InMemorySchemaDAO(OLDER_VERSION), allMigrationClazz, LATEST_VERSION);
+
+        // When I perform a concurrent migration
+        AtomicInteger encounteredExceptionCount = new AtomicInteger(0);
+        executorService.submit(() -> testee.upgradeToVersion(LATEST_VERSION));
+        executorService.submit(() -> {
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException e) {
+                throw Throwables.propagate(e);
+            }
+
+            try {
+                testee.upgradeToVersion(LATEST_VERSION);
+            } catch (IllegalStateException e) {
+                encounteredExceptionCount.incrementAndGet();
+            }
+        });
+        executorService.awaitTermination(10, TimeUnit.SECONDS);
+
+        // Then the second migration fails
+        assertThat(encounteredExceptionCount.get()).isEqualTo(1);
+    }
+
+    @Test
+    public void partialMigrationShouldThrow() throws Exception {
+        Migration migration1 = mock(Migration.class);
+        when(migration1.run()).thenReturn(Migration.Result.PARTIAL);
+        Migration migration2 = successfulMigration;
+
+        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+            .put(OLDER_VERSION, migration1)
+            .put(CURRENT_VERSION, migration2)
+            .build();
+        testee = new CassandraMigrationService(new InMemorySchemaDAO(OLDER_VERSION), allMigrationClazz, LATEST_VERSION);
+
+        expectedException.expect(MigrationException.class);
+
+        testee.upgradeToVersion(LATEST_VERSION);
+    }
+
+    @Test
+    public void partialMigrationShouldAbortMigrations() throws Exception {
+        Migration migration1 = mock(Migration.class);
+        when(migration1.run()).thenReturn(Migration.Result.PARTIAL);
+        Migration migration2 = mock(Migration.class);
+        when(migration2.run()).thenReturn(Migration.Result.COMPLETED);
+
+        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
+            .put(OLDER_VERSION, migration1)
+            .put(CURRENT_VERSION, migration2)
+            .build();
+        testee = new CassandraMigrationService(new InMemorySchemaDAO(OLDER_VERSION), allMigrationClazz, LATEST_VERSION);
+
+        expectedException.expect(MigrationException.class);
+
+        try {
+            testee.upgradeToVersion(LATEST_VERSION);
+        } finally {
+            verify(migration1, times(1)).run();
+            verifyNoMoreInteractions(migration1);
+            verifyZeroInteractions(migration2);
+        }
+    }
+
+    public static class InMemorySchemaDAO extends CassandraSchemaVersionDAO {
+        private int currentVersion;
+
+        public InMemorySchemaDAO(int currentVersion) {
+            super(mock(Session.class), null);
+            this.currentVersion = currentVersion;
+        }
+
+        @Override
+        public CompletableFuture<Optional<Integer>> getCurrentSchemaVersion() {
+            return CompletableFuture.completedFuture(Optional.of(currentVersion));
+        }
+
+        @Override
+        public CompletableFuture<Void> updateVersion(int newVersion) {
+            currentVersion = newVersion;
+            return CompletableFuture.completedFuture(null);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/b87d49c7/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java b/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
index 6fe2792..16b821b 100644
--- a/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
+++ b/server/container/guice/protocols/webadmin-cassandra/src/main/java/org/apache/james/modules/server/CassandraRoutesModule.java
@@ -19,13 +19,13 @@
 
 package org.apache.james.modules.server;
 
+import org.apache.james.backends.cassandra.migration.CassandraMigrationService;
 import org.apache.james.backends.cassandra.migration.Migration;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
 import org.apache.james.mailbox.cassandra.mail.migration.AttachmentMessageIdCreation;
 import org.apache.james.mailbox.cassandra.mail.migration.AttachmentV2Migration;
 import org.apache.james.webadmin.Routes;
 import org.apache.james.webadmin.routes.CassandraMigrationRoutes;
-import org.apache.james.webadmin.service.CassandraMigrationService;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Scopes;

http://git-wip-us.apache.org/repos/asf/james-project/blob/b87d49c7/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
index 3a42657..dce04cf 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/CassandraMigrationRoutes.java
@@ -21,11 +21,11 @@ package org.apache.james.webadmin.routes;
 
 import javax.inject.Inject;
 
+import org.apache.james.backends.cassandra.migration.CassandraMigrationService;
+import org.apache.james.backends.cassandra.migration.MigrationException;
 import org.apache.james.webadmin.Constants;
 import org.apache.james.webadmin.Routes;
 import org.apache.james.webadmin.dto.CassandraVersionRequest;
-import org.apache.james.webadmin.service.CassandraMigrationService;
-import org.apache.james.webadmin.service.MigrationException;
 import org.apache.james.webadmin.utils.ErrorResponder;
 import org.apache.james.webadmin.utils.ErrorResponder.ErrorType;
 import org.apache.james.webadmin.utils.JsonTransformer;

http://git-wip-us.apache.org/repos/asf/james-project/blob/b87d49c7/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/service/CassandraMigrationService.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/service/CassandraMigrationService.java b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/service/CassandraMigrationService.java
deleted file mode 100644
index 004cd60..0000000
--- a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/service/CassandraMigrationService.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.webadmin.service;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.IntStream;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.apache.commons.lang.NotImplementedException;
-import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
-import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
-import org.apache.james.mailbox.cassandra.mail.migration.Migration;
-import org.apache.james.webadmin.dto.CassandraVersionResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-
-public class CassandraMigrationService {
-    public static final String LATEST_VERSION = "latestVersion";
-    private final CassandraSchemaVersionDAO schemaVersionDAO;
-    private final int latestVersion;
-    private final Map<Integer, Migration> allMigrationClazz;
-    private final Logger LOG = LoggerFactory.getLogger(CassandraMigrationService.class);
-
-    @Inject
-    public CassandraMigrationService(CassandraSchemaVersionDAO schemaVersionDAO, Map<Integer, Migration> allMigrationClazz, @Named(LATEST_VERSION) int latestVersion) {
-        Preconditions.checkArgument(latestVersion >= 0, "The latest version must be positive");
-        this.schemaVersionDAO = schemaVersionDAO;
-        this.latestVersion = latestVersion;
-        this.allMigrationClazz = allMigrationClazz;
-    }
-
-    public CassandraVersionResponse getCurrentVersion() {
-        return new CassandraVersionResponse(schemaVersionDAO.getCurrentSchemaVersion().join());
-    }
-
-    public CassandraVersionResponse getLatestVersion() {
-        return new CassandraVersionResponse(Optional.of(latestVersion));
-    }
-
-    public synchronized void upgradeToVersion(int newVersion) {
-        int currentVersion = schemaVersionDAO.getCurrentSchemaVersion().join().orElse(CassandraSchemaVersionManager.DEFAULT_VERSION);
-        if (currentVersion >= newVersion) {
-            throw new IllegalStateException("Current version is already up to date");
-        }
-
-        IntStream.range(currentVersion, newVersion)
-            .boxed()
-            .forEach(this::doMigration);
-    }
-
-    public void upgradeToLastVersion() {
-        upgradeToVersion(latestVersion);
-    }
-
-    private void doMigration(Integer version) {
-        if (allMigrationClazz.containsKey(version)) {
-            LOG.info("Migrating to version {} ", version + 1);
-            Migration.MigrationResult migrationResult = allMigrationClazz.get(version).run();
-            if (migrationResult == Migration.MigrationResult.COMPLETED) {
-                schemaVersionDAO.updateVersion(version + 1);
-                LOG.info("Migrating to version {} done", version + 1);
-            } else {
-                String message = String.format("Migrating to version %d partially done. " +
-                    "Please check logs for cause of failure and re-run this migration.",
-                    version + 1);
-                LOG.warn(message);
-                throw new MigrationException(message);
-            }
-        } else {
-            String message = String.format("Can not migrate to %d. No migration class registered.", version + 1);
-            LOG.error(message);
-            throw new NotImplementedException(message);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/b87d49c7/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/service/MigrationException.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/service/MigrationException.java b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/service/MigrationException.java
deleted file mode 100644
index 7b9d74f..0000000
--- a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/service/MigrationException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.webadmin.service;
-
-public class MigrationException extends RuntimeException {
-    public MigrationException(String message) {
-        super(message);
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/b87d49c7/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
index 1115e87..f3fc05a 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/routes/CassandraMigrationRoutesTest.java
@@ -37,12 +37,12 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 
+import org.apache.james.backends.cassandra.migration.CassandraMigrationService;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.mailbox.cassandra.mail.migration.Migration;
 import org.apache.james.metrics.logger.DefaultMetricFactory;
 import org.apache.james.webadmin.WebAdminServer;
 import org.apache.james.webadmin.WebAdminUtils;
-import org.apache.james.webadmin.service.CassandraMigrationService;
 import org.apache.james.webadmin.utils.JsonTransformer;
 import org.eclipse.jetty.http.HttpStatus;
 import org.junit.After;

http://git-wip-us.apache.org/repos/asf/james-project/blob/b87d49c7/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/service/CassandraMigrationServiceTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/service/CassandraMigrationServiceTest.java b/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/service/CassandraMigrationServiceTest.java
deleted file mode 100644
index 0e7496f..0000000
--- a/server/protocols/webadmin/webadmin-cassandra/src/test/java/org/apache/james/webadmin/service/CassandraMigrationServiceTest.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.webadmin.service;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.commons.lang.NotImplementedException;
-import org.apache.james.backends.cassandra.migration.Migration;
-import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-import com.datastax.driver.core.Session;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableMap;
-
-public class CassandraMigrationServiceTest {
-    private static final int LATEST_VERSION = 3;
-    private static final int CURRENT_VERSION = 2;
-    private static final int OLDER_VERSION = 1;
-    private CassandraMigrationService testee;
-    private CassandraSchemaVersionDAO schemaVersionDAO;
-    private ExecutorService executorService;
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-    private Migration successfulMigration;
-
-    @Before
-    public void setUp() throws Exception {
-        schemaVersionDAO = mock(CassandraSchemaVersionDAO.class);
-        successfulMigration = mock(Migration.class);
-        when(successfulMigration.run()).thenReturn(Migration.Result.COMPLETED);
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
-            .put(OLDER_VERSION, successfulMigration)
-            .put(CURRENT_VERSION, successfulMigration)
-            .put(LATEST_VERSION, successfulMigration)
-            .build();
-        testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION);
-        executorService = Executors.newFixedThreadPool(2);
-    }
-
-    @After
-    public void tearDown() {
-        executorService.shutdownNow();
-    }
-
-    @Test
-    public void getCurrentVersionShouldReturnCurrentVersion() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
-
-        assertThat(testee.getCurrentVersion().getversion().get()).isEqualTo(CURRENT_VERSION);
-    }
-
-    @Test
-    public void getLatestVersionShouldReturnTheLatestVersion() throws Exception {
-        assertThat(testee.getLatestVersion().getversion().get()).isEqualTo(LATEST_VERSION);
-    }
-
-    @Test
-    public void upgradeToVersionShouldThrowWhenCurrentVersionIsUpToDate() throws Exception {
-        expectedException.expect(IllegalStateException.class);
-
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(CURRENT_VERSION)));
-
-        testee.upgradeToVersion(OLDER_VERSION);
-    }
-
-    @Test
-    public void upgradeToVersionShouldUpdateToVersion() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
-
-        testee.upgradeToVersion(CURRENT_VERSION);
-
-        verify(schemaVersionDAO, times(1)).updateVersion(eq(CURRENT_VERSION));
-    }
-
-    @Test
-    public void upgradeToLastVersionShouldThrowWhenVersionIsUpToDate() throws Exception {
-        expectedException.expect(IllegalStateException.class);
-
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(LATEST_VERSION)));
-
-        testee.upgradeToLastVersion();
-    }
-
-    @Test
-    public void upgradeToLastVersionShouldUpdateToLatestVersion() throws Exception {
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
-
-        testee.upgradeToLastVersion();
-
-        verify(schemaVersionDAO, times(1)).updateVersion(eq(LATEST_VERSION));
-    }
-
-    @Test
-    public void upgradeToVersionShouldThrowOnMissingVersion() throws Exception {
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
-            .put(OLDER_VERSION, successfulMigration)
-            .put(LATEST_VERSION, successfulMigration)
-            .build();
-        testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION);
-        when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
-
-        expectedException.expect(NotImplementedException.class);
-
-        testee.upgradeToVersion(LATEST_VERSION);
-    }
-
-    @Test
-    public void upgradeToVersionShouldUpdateIntermediarySuccessfulMigrationsInCaseOfError() throws Exception {
-        try {
-            Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
-                .put(OLDER_VERSION, successfulMigration)
-                .put(LATEST_VERSION, successfulMigration)
-                .build();
-            testee = new CassandraMigrationService(schemaVersionDAO, allMigrationClazz, LATEST_VERSION);
-            when(schemaVersionDAO.getCurrentSchemaVersion()).thenReturn(CompletableFuture.completedFuture(Optional.of(OLDER_VERSION)));
-
-            expectedException.expect(RuntimeException.class);
-
-            testee.upgradeToVersion(LATEST_VERSION);
-        } finally {
-            verify(schemaVersionDAO).updateVersion(CURRENT_VERSION);
-        }
-    }
-
-    @Test
-    public void concurrentMigrationsShouldFail() throws Exception {
-        // Given a stateful migration service
-        Migration wait1SecondMigration = mock(Migration.class);
-        doAnswer(invocation -> {
-            Thread.sleep(1000);
-            return Migration.Result.COMPLETED;
-        }).when(wait1SecondMigration).run();
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
-            .put(OLDER_VERSION, wait1SecondMigration)
-            .put(CURRENT_VERSION, wait1SecondMigration)
-            .put(LATEST_VERSION, wait1SecondMigration)
-            .build();
-        testee = new CassandraMigrationService(new InMemorySchemaDAO(OLDER_VERSION), allMigrationClazz, LATEST_VERSION);
-
-        // When I perform a concurrent migration
-        AtomicInteger encounteredExceptionCount = new AtomicInteger(0);
-        executorService.submit(() -> testee.upgradeToVersion(LATEST_VERSION));
-        executorService.submit(() -> {
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException e) {
-                throw Throwables.propagate(e);
-            }
-
-            try {
-                testee.upgradeToVersion(LATEST_VERSION);
-            } catch (IllegalStateException e) {
-                encounteredExceptionCount.incrementAndGet();
-            }
-        });
-        executorService.awaitTermination(10, TimeUnit.SECONDS);
-
-        // Then the second migration fails
-        assertThat(encounteredExceptionCount.get()).isEqualTo(1);
-    }
-
-    @Test
-    public void partialMigrationShouldThrow() throws Exception {
-        Migration migration1 = mock(Migration.class);
-        when(migration1.run()).thenReturn(Migration.Result.PARTIAL);
-        Migration migration2 = successfulMigration;
-
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
-            .put(OLDER_VERSION, migration1)
-            .put(CURRENT_VERSION, migration2)
-            .build();
-        testee = new CassandraMigrationService(new InMemorySchemaDAO(OLDER_VERSION), allMigrationClazz, LATEST_VERSION);
-
-        expectedException.expect(MigrationException.class);
-
-        testee.upgradeToVersion(LATEST_VERSION);
-    }
-
-    @Test
-    public void partialMigrationShouldAbortMigrations() throws Exception {
-        Migration migration1 = mock(Migration.class);
-        when(migration1.run()).thenReturn(Migration.Result.PARTIAL);
-        Migration migration2 = mock(Migration.class);
-        when(migration2.run()).thenReturn(Migration.Result.COMPLETED);
-
-        Map<Integer, Migration> allMigrationClazz = ImmutableMap.<Integer, Migration>builder()
-            .put(OLDER_VERSION, migration1)
-            .put(CURRENT_VERSION, migration2)
-            .build();
-        testee = new CassandraMigrationService(new InMemorySchemaDAO(OLDER_VERSION), allMigrationClazz, LATEST_VERSION);
-
-        expectedException.expect(MigrationException.class);
-
-        try {
-            testee.upgradeToVersion(LATEST_VERSION);
-        } finally {
-            verify(migration1, times(1)).run();
-            verifyNoMoreInteractions(migration1);
-            verifyZeroInteractions(migration2);
-        }
-    }
-
-    public static class InMemorySchemaDAO extends CassandraSchemaVersionDAO {
-        private int currentVersion;
-
-        public InMemorySchemaDAO(int currentVersion) {
-            super(mock(Session.class), null);
-            this.currentVersion = currentVersion;
-        }
-
-        @Override
-        public CompletableFuture<Optional<Integer>> getCurrentSchemaVersion() {
-            return CompletableFuture.completedFuture(Optional.of(currentVersion));
-        }
-
-        @Override
-        public CompletableFuture<Void> updateVersion(int newVersion) {
-            currentVersion = newVersion;
-            return CompletableFuture.completedFuture(null);
-        }
-    }
-}
\ 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