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 2019/12/20 08:34:27 UTC

[james-project] 07/08: JAMES-2993 Expose projecting fixing endpoint over memory

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit c1d00d110362c3991d3c5655f8dd31e612f4b6f8
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Dec 18 10:05:32 2019 +0700

    JAMES-2993 Expose projecting fixing endpoint over memory
---
 .../org/apache/james/CassandraJamesServerMain.java |   2 -
 .../java/org/apache/james/JPAJamesServerMain.java  |   2 -
 .../org/apache/james/MemoryJamesServerMain.java    |   2 +-
 .../james/modules/server/MailboxRoutesModule.java  |   8 +
 .../james/modules/server/ReIndexingModule.java     |  16 +
 .../RabbitMQWebAdminServerIntegrationTest.java     |   1 -
 .../integration/WebAdminServerIntegrationTest.java |   3 +-
 .../james/webadmin/routes/MailboxesRoutes.java     | 422 +++++++++++----------
 .../routes/MailboxesRoutesNoTasksTest.java         | 102 +++++
 .../james/webadmin/routes/MailboxesRoutesTest.java |  18 +-
 10 files changed, 369 insertions(+), 207 deletions(-)

diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/CassandraJamesServerMain.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/CassandraJamesServerMain.java
index f62e1bd..05e07ea 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/CassandraJamesServerMain.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/CassandraJamesServerMain.java
@@ -63,7 +63,6 @@ import org.apache.james.modules.server.JmapTasksModule;
 import org.apache.james.modules.server.MailQueueRoutesModule;
 import org.apache.james.modules.server.MailRepositoriesRoutesModule;
 import org.apache.james.modules.server.MailboxRoutesModule;
-import org.apache.james.modules.server.MailboxesRoutesModule;
 import org.apache.james.modules.server.MessagesRoutesModule;
 import org.apache.james.modules.server.ReIndexingModule;
 import org.apache.james.modules.server.SieveRoutesModule;
@@ -89,7 +88,6 @@ public class CassandraJamesServerMain {
         new DeletedMessageVaultRoutesModule(),
         new DLPRoutesModule(),
         new JmapTasksModule(),
-        new MailboxesRoutesModule(),
         new MailboxRoutesModule(),
         new MailQueueRoutesModule(),
         new MailRepositoriesRoutesModule(),
diff --git a/server/container/guice/jpa-guice/src/main/java/org/apache/james/JPAJamesServerMain.java b/server/container/guice/jpa-guice/src/main/java/org/apache/james/JPAJamesServerMain.java
index b4f2b64..d03f0cf 100644
--- a/server/container/guice/jpa-guice/src/main/java/org/apache/james/JPAJamesServerMain.java
+++ b/server/container/guice/jpa-guice/src/main/java/org/apache/james/JPAJamesServerMain.java
@@ -41,7 +41,6 @@ import org.apache.james.modules.server.JMXServerModule;
 import org.apache.james.modules.server.MailQueueRoutesModule;
 import org.apache.james.modules.server.MailRepositoriesRoutesModule;
 import org.apache.james.modules.server.MailboxRoutesModule;
-import org.apache.james.modules.server.MailboxesRoutesModule;
 import org.apache.james.modules.server.NoJwtModule;
 import org.apache.james.modules.server.RawPostDequeueDecoratorModule;
 import org.apache.james.modules.server.ReIndexingModule;
@@ -61,7 +60,6 @@ public class JPAJamesServerMain {
         new WebAdminServerModule(),
         new DataRoutesModules(),
         new MailboxRoutesModule(),
-        new MailboxesRoutesModule(),
         new MailQueueRoutesModule(),
         new MailRepositoriesRoutesModule(),
         new ReIndexingModule(),
diff --git a/server/container/guice/memory-guice/src/main/java/org/apache/james/MemoryJamesServerMain.java b/server/container/guice/memory-guice/src/main/java/org/apache/james/MemoryJamesServerMain.java
index 489b055..21f65f3 100644
--- a/server/container/guice/memory-guice/src/main/java/org/apache/james/MemoryJamesServerMain.java
+++ b/server/container/guice/memory-guice/src/main/java/org/apache/james/MemoryJamesServerMain.java
@@ -70,7 +70,6 @@ public class MemoryJamesServerMain {
         new DataRoutesModules(),
         new DeletedMessageVaultRoutesModule(),
         new DLPRoutesModule(),
-        new JmapTasksModule(),
         new MailboxRoutesModule(),
         new MailQueueRoutesModule(),
         new MailRepositoriesRoutesModule(),
@@ -97,6 +96,7 @@ public class MemoryJamesServerMain {
         new SpamAssassinListenerModule());
 
     public static final Module JMAP = Modules.combine(
+        new JmapTasksModule(),
         new MemoryDataJmapModule(),
         new JMAPDraftServerModule());
 
diff --git a/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/MailboxRoutesModule.java b/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/MailboxRoutesModule.java
index 9b05566..42a7c88 100644
--- a/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/MailboxRoutesModule.java
+++ b/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/MailboxRoutesModule.java
@@ -19,6 +19,9 @@
 
 package org.apache.james.modules.server;
 
+import static org.apache.james.webadmin.routes.MailboxesRoutes.ALL_MAILBOXES_TASKS;
+import static org.apache.james.webadmin.routes.MailboxesRoutes.ONE_MAILBOX_TASKS;
+import static org.apache.james.webadmin.routes.MailboxesRoutes.ONE_MAIL_TASKS;
 import static org.apache.james.webadmin.routes.UserMailboxesRoutes.USER_MAILBOXES_OPERATIONS_INJECTION_KEY;
 
 import org.apache.james.webadmin.Routes;
@@ -26,6 +29,7 @@ import org.apache.james.webadmin.jackson.QuotaModule;
 import org.apache.james.webadmin.routes.DomainQuotaRoutes;
 import org.apache.james.webadmin.routes.EventDeadLettersRoutes;
 import org.apache.james.webadmin.routes.GlobalQuotaRoutes;
+import org.apache.james.webadmin.routes.MailboxesRoutes;
 import org.apache.james.webadmin.routes.UserMailboxesRoutes;
 import org.apache.james.webadmin.routes.UserQuotaRoutes;
 import org.apache.james.webadmin.tasks.TaskFromRequestRegistry.TaskRegistration;
@@ -45,10 +49,14 @@ public class MailboxRoutesModule extends AbstractModule {
         routesMultibinder.addBinding().to(GlobalQuotaRoutes.class);
         routesMultibinder.addBinding().to(UserQuotaRoutes.class);
         routesMultibinder.addBinding().to(UserMailboxesRoutes.class);
+        routesMultibinder.addBinding().to(MailboxesRoutes.class);
 
         Multibinder<JsonTransformerModule> jsonTransformerModuleMultibinder = Multibinder.newSetBinder(binder(), JsonTransformerModule.class);
         jsonTransformerModuleMultibinder.addBinding().to(QuotaModule.class);
 
         Multibinder.newSetBinder(binder(), TaskRegistration.class, Names.named(USER_MAILBOXES_OPERATIONS_INJECTION_KEY));
+        Multibinder.newSetBinder(binder(), TaskRegistration.class, Names.named(ALL_MAILBOXES_TASKS));
+        Multibinder.newSetBinder(binder(), TaskRegistration.class, Names.named(ONE_MAILBOX_TASKS));
+        Multibinder.newSetBinder(binder(), TaskRegistration.class, Names.named(ONE_MAIL_TASKS));
     }
 }
diff --git a/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/ReIndexingModule.java b/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/ReIndexingModule.java
index 8825cf6..c6de10e 100644
--- a/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/ReIndexingModule.java
+++ b/server/container/guice/protocols/webadmin-mailbox/src/main/java/org/apache/james/modules/server/ReIndexingModule.java
@@ -19,8 +19,12 @@
 
 package org.apache.james.modules.server;
 
+import static org.apache.james.webadmin.routes.MailboxesRoutes.ALL_MAILBOXES_TASKS;
+import static org.apache.james.webadmin.routes.MailboxesRoutes.ONE_MAILBOX_TASKS;
+import static org.apache.james.webadmin.routes.MailboxesRoutes.ONE_MAIL_TASKS;
 import static org.apache.james.webadmin.routes.UserMailboxesRoutes.USER_MAILBOXES_OPERATIONS_INJECTION_KEY;
 
+import org.apache.james.webadmin.routes.MailboxesRoutes;
 import org.apache.james.webadmin.routes.UserMailboxesRoutes.UserReIndexingTaskRegistration;
 import org.apache.james.webadmin.tasks.TaskFromRequestRegistry.TaskRegistration;
 
@@ -34,5 +38,17 @@ public class ReIndexingModule extends AbstractModule {
         Multibinder.newSetBinder(binder(), TaskRegistration.class, Names.named(USER_MAILBOXES_OPERATIONS_INJECTION_KEY))
             .addBinding()
             .to(UserReIndexingTaskRegistration.class);
+
+        Multibinder.newSetBinder(binder(), TaskRegistration.class, Names.named(ALL_MAILBOXES_TASKS))
+            .addBinding()
+            .to(MailboxesRoutes.ReIndexAllMailboxesTaskRegistration.class);
+
+        Multibinder.newSetBinder(binder(), TaskRegistration.class, Names.named(ONE_MAILBOX_TASKS))
+            .addBinding()
+            .to(MailboxesRoutes.ReIndexOneMailboxTaskRegistration.class);
+
+        Multibinder.newSetBinder(binder(), TaskRegistration.class, Names.named(ONE_MAIL_TASKS))
+            .addBinding()
+            .to(MailboxesRoutes.ReIndexOneMailTaskRegistration.class);
     }
 }
diff --git a/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/RabbitMQWebAdminServerIntegrationTest.java b/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/RabbitMQWebAdminServerIntegrationTest.java
index 05228e1..65c1423 100644
--- a/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/RabbitMQWebAdminServerIntegrationTest.java
+++ b/server/protocols/webadmin-integration-test/distributed-webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/rabbitmq/RabbitMQWebAdminServerIntegrationTest.java
@@ -165,7 +165,6 @@ public class RabbitMQWebAdminServerIntegrationTest extends WebAdminServerIntegra
             .then()
             .statusCode(HttpStatus.OK_200)
             .body(containsString("\"tags\":[\"Cassandra Mappings Operations\"]"))
-            .body(containsString("{\"name\":\"ReIndexing (mailboxes)\"}"))
             .body(containsString("{\"name\":\"MessageIdReIndexing\"}"));
     }
 }
\ No newline at end of file
diff --git a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
index 7ab11e8..4e83ebe 100644
--- a/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
+++ b/server/protocols/webadmin-integration-test/webadmin-integration-test-common/src/main/java/org/apache/james/webadmin/integration/WebAdminServerIntegrationTest.java
@@ -298,7 +298,8 @@ public abstract class WebAdminServerIntegrationTest {
             .body(containsString("\"tags\":[\"MailQueues\"]"))
             .body(containsString("\"tags\":[\"Address Forwards\"]"))
             .body(containsString("\"tags\":[\"Address Aliases\"]"))
-            .body(containsString("\"tags\":[\"Address Groups\"]"));
+            .body(containsString("\"tags\":[\"Address Groups\"]"))
+            .body(containsString("{\"name\":\"Mailboxes\"}"));
     }
 
     @Test
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/MailboxesRoutes.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/MailboxesRoutes.java
index f48f090..a26450e 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/MailboxesRoutes.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/MailboxesRoutes.java
@@ -19,6 +19,7 @@
 
 package org.apache.james.webadmin.routes;
 
+import java.util.Optional;
 import java.util.Set;
 
 import javax.inject.Inject;
@@ -60,204 +61,185 @@ import spark.Request;
 import spark.Route;
 import spark.Service;
 
-@Api(tags = "ReIndexing (mailboxes)")
+@Api(tags = "Mailboxes")
 @Path("/mailboxes")
 @Produces("application/json")
 public class MailboxesRoutes implements Routes {
-    private static final String BASE_PATH = "/mailboxes";
-    private static final String RE_INDEX_FAILED_MESSAGES_QUERY_PARAM = "reIndexFailedMessagesOf";
-    private static final String MAILBOX_PARAM = ":mailbox";
-    private static final String UID_PARAM = ":uid";
-    private static final String MAILBOX_PATH = BASE_PATH + "/" + MAILBOX_PARAM;
-    private static final String MESSAGE_PATH = MAILBOX_PATH + "/mails/" + UID_PARAM;
-    static final TaskRegistrationKey RE_INDEX = TaskRegistrationKey.of("reIndex");
-    static final String TASK_PARAMETER = "task";
-    public static final String ALL_MAILBOXES_TASKS = "allMailboxesTasks";
-
-    private final TaskManager taskManager;
-    private final PreviousReIndexingService previousReIndexingService;
-    private final MailboxId.Factory mailboxIdFactory;
-    private final ReIndexer reIndexer;
-    private final JsonTransformer jsonTransformer;
-    private final Set<TaskRegistration> allMailboxesTaskRegistration;
-
-    @Inject
-    MailboxesRoutes(TaskManager taskManager, PreviousReIndexingService previousReIndexingService,
-                    MailboxId.Factory mailboxIdFactory, ReIndexer reIndexer, JsonTransformer jsonTransformer,
-                    @Named(ALL_MAILBOXES_TASKS) Set<TaskRegistration> allMailboxesTaskRegistration) {
-        this.taskManager = taskManager;
-        this.previousReIndexingService = previousReIndexingService;
-        this.mailboxIdFactory = mailboxIdFactory;
-        this.reIndexer = reIndexer;
-        this.jsonTransformer = jsonTransformer;
-        this.allMailboxesTaskRegistration = allMailboxesTaskRegistration;
-    }
+    public static class ReIndexAllMailboxesTaskRegistration extends TaskRegistration {
+        @Inject
+        public ReIndexAllMailboxesTaskRegistration(ReIndexer reIndexer, PreviousReIndexingService previousReIndexingService, MailboxId.Factory mailboxIdFactory) {
+            super(RE_INDEX, wrap(request -> reIndexAll(previousReIndexingService, reIndexer, request)));
+        }
 
-    @Override
-    public String getBasePath() {
-        return BASE_PATH;
-    }
+        @POST
+        @Path("/")
+        @ApiOperation(value = "Re-indexes all the mails on this server")
+        @ApiImplicitParams({
+            @ApiImplicitParam(
+                required = true,
+                name = "task",
+                paramType = "query parameter",
+                dataType = "String",
+                defaultValue = "none",
+                example = "?task=reIndex",
+                value = "Compulsory. Only supported value is `reIndex`"),
+            @ApiImplicitParam(
+                name = "reIndexFailedMessagesOf",
+                paramType = "query parameter",
+                dataType = "String",
+                defaultValue = "none",
+                example = "?reIndexFailedMessagesOf=3294a976-ce63-491e-bd52-1b6f465ed7a2",
+                value = "optional. References a previously run reIndexing task. if present, the messages that this previous " +
+                    "task failed to index will be reIndexed.")
+        })
+        @ApiResponses(value = {
+            @ApiResponse(code = HttpStatus.CREATED_201, message = "Task is created", response = TaskIdDto.class),
+            @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side."),
+            @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "Bad request - details in the returned error message")
+        })
+        private static Task reIndexAll(PreviousReIndexingService previousReIndexingService, ReIndexer reIndexer, Request request) throws MailboxException {
+            boolean indexingCorrection = !Strings.isNullOrEmpty(request.queryParams(RE_INDEX_FAILED_MESSAGES_QUERY_PARAM));
+            if (indexingCorrection) {
+                IndexingDetailInformation indexingDetailInformation = retrieveIndexingExecutionDetails(previousReIndexingService, request);
+                return reIndexer.reIndex(indexingDetailInformation.failures());
+            }
+            return reIndexer.reIndex();
+        }
 
-    @Override
-    public void define(Service service) {
-        service.post(BASE_PATH, reIndexAll(), jsonTransformer);
-        service.post(MAILBOX_PATH, reIndexMailbox(), jsonTransformer);
-        service.post(MESSAGE_PATH, reIndexMessage(), jsonTransformer);
-    }
+        private static IndexingDetailInformation retrieveIndexingExecutionDetails(PreviousReIndexingService previousReIndexingService, Request request) {
+            TaskId taskId = getTaskId(request);
+            try {
+                return previousReIndexingService.retrieveIndexingExecutionDetails(taskId);
+            } catch (PreviousReIndexingService.NotAnIndexingRetriableTask | PreviousReIndexingService.TaskNotYetFinishedException e) {
+                throw ErrorResponder.builder()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                    .message("Invalid task id")
+                    .cause(e)
+                    .haltError();
+            } catch (TaskNotFoundException e) {
+                throw ErrorResponder.builder()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                    .message("TaskId " + taskId.asString() + " does not exist")
+                    .cause(e)
+                    .haltError();
+            }
+        }
 
-    @POST
-    @Path("/")
-    @ApiOperation(value = "Re-indexes all the mails on this server")
-    @ApiImplicitParams({
-        @ApiImplicitParam(
-            required = true,
-            name = "task",
-            paramType = "query parameter",
-            dataType = "String",
-            defaultValue = "none",
-            example = "?task=reIndex",
-            value = "Compulsory. Only supported value is `reIndex`"),
-        @ApiImplicitParam(
-            name = "reIndexFailedMessagesOf",
-            paramType = "query parameter",
-            dataType = "String",
-            defaultValue = "none",
-            example = "?reIndexFailedMessagesOf=3294a976-ce63-491e-bd52-1b6f465ed7a2",
-            value = "optional. References a previously run reIndexing task. if present, the messages that this previous " +
-                "task failed to index will be reIndexed.")
-    })
-    @ApiResponses(value = {
-        @ApiResponse(code = HttpStatus.CREATED_201, message = "Task is created", response = TaskIdDto.class),
-        @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side."),
-        @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "Bad request - details in the returned error message")
-    })
-    private Route reIndexAll() {
-        return TaskFromRequestRegistry.builder()
-            .parameterName(TASK_PARAMETER)
-            .registrations(allMailboxesTaskRegistration)
-            .register(RE_INDEX, wrap(this::reIndexAll))
-            .buildAsRoute(taskManager);
+        private static TaskId getTaskId(Request request) {
+            try {
+                String id = request.queryParams(RE_INDEX_FAILED_MESSAGES_QUERY_PARAM);
+                return TaskId.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();
+            }
+        }
     }
 
-    private Task reIndexAll(Request request) throws MailboxException {
-        boolean indexingCorrection = !Strings.isNullOrEmpty(request.queryParams(RE_INDEX_FAILED_MESSAGES_QUERY_PARAM));
-        if (indexingCorrection) {
-            IndexingDetailInformation indexingDetailInformation = retrieveIndexingExecutionDetails(request);
-            return reIndexer.reIndex(indexingDetailInformation.failures());
+    public static class ReIndexOneMailboxTaskRegistration extends TaskRegistration {
+        @Inject
+        public ReIndexOneMailboxTaskRegistration(ReIndexer reIndexer, MailboxId.Factory mailboxIdFactory) {
+            super(RE_INDEX, toTask(reIndexer, mailboxIdFactory));
         }
-        return reIndexer.reIndex();
-    }
 
-    private IndexingDetailInformation retrieveIndexingExecutionDetails(Request request) {
-        TaskId taskId = getTaskId(request);
-        try {
-            return previousReIndexingService.retrieveIndexingExecutionDetails(taskId);
-        } catch (PreviousReIndexingService.NotAnIndexingRetriableTask | PreviousReIndexingService.TaskNotYetFinishedException e) {
-            throw ErrorResponder.builder()
-                .statusCode(HttpStatus.BAD_REQUEST_400)
-                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
-                .message("Invalid task id")
-                .cause(e)
-                .haltError();
-        } catch (TaskNotFoundException e) {
-            throw ErrorResponder.builder()
-                .statusCode(HttpStatus.BAD_REQUEST_400)
-                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
-                .message("TaskId " + taskId.asString() + " does not exist")
-                .cause(e)
-                .haltError();
+        @POST
+        @Path("/{mailboxId}")
+        @ApiOperation(value = "Re-indexes all the mails in a mailbox")
+        @ApiImplicitParams({
+            @ApiImplicitParam(
+                required = true,
+                name = "task",
+                paramType = "query parameter",
+                dataType = "String",
+                defaultValue = "none",
+                example = "?task=reIndex",
+                value = "Compulsory. Only supported value is `reIndex`"),
+            @ApiImplicitParam(
+                required = true,
+                name = "mailboxId",
+                paramType = "path parameter",
+                dataType = "String",
+                defaultValue = "none",
+                value = "Compulsory. Needs to be a valid mailbox ID")
+        })
+        @ApiResponses(value = {
+            @ApiResponse(code = HttpStatus.CREATED_201, message = "Task is created", response = TaskIdDto.class),
+            @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side."),
+            @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "Bad request - details in the returned error message")
+        })
+        private static TaskFromRequest toTask(ReIndexer reIndexer, MailboxId.Factory mailboxIdFactory) {
+            return wrap(request -> reIndexer.reIndex(extractMailboxId(mailboxIdFactory, request)));
         }
     }
 
-    private TaskId getTaskId(Request request) {
-        try {
-            String id = request.queryParams(RE_INDEX_FAILED_MESSAGES_QUERY_PARAM);
-            return TaskId.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();
+    public static class ReIndexOneMailTaskRegistration extends TaskRegistration {
+        @Inject
+        public ReIndexOneMailTaskRegistration(ReIndexer reIndexer, MailboxId.Factory mailboxIdFactory) {
+            super(RE_INDEX, toTask(reIndexer, mailboxIdFactory));
         }
-    }
 
-    @POST
-    @Path("/{mailboxId}")
-    @ApiOperation(value = "Re-indexes all the mails in a mailbox")
-    @ApiImplicitParams({
-        @ApiImplicitParam(
-            required = true,
-            name = "task",
-            paramType = "query parameter",
-            dataType = "String",
-            defaultValue = "none",
-            example = "?task=reIndex",
-            value = "Compulsory. Only supported value is `reIndex`"),
-        @ApiImplicitParam(
-            required = true,
-            name = "mailboxId",
-            paramType = "path parameter",
-            dataType = "String",
-            defaultValue = "none",
-            value = "Compulsory. Needs to be a valid mailbox ID")
-    })
-    @ApiResponses(value = {
-        @ApiResponse(code = HttpStatus.CREATED_201, message = "Task is created", response = TaskIdDto.class),
-        @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side."),
-        @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "Bad request - details in the returned error message")
-    })
-    private Route reIndexMailbox() {
-        return TaskFromRequestRegistry.builder()
-            .parameterName(TASK_PARAMETER)
-            .register(RE_INDEX, wrap(request -> reIndexer.reIndex(extractMailboxId(request))))
-            .buildAsRoute(taskManager);
-    }
+        @POST
+        @Path("/{mailboxId}/mails/{uid}")
+        @ApiOperation(value = "Re-indexes a single email")
+        @ApiImplicitParams({
+            @ApiImplicitParam(
+                required = true,
+                name = "task",
+                paramType = "query parameter",
+                dataType = "String",
+                defaultValue = "none",
+                example = "?task=reIndex",
+                value = "Compulsory. Only supported value is `reIndex`"),
+            @ApiImplicitParam(
+                required = true,
+                name = "user",
+                paramType = "path parameter",
+                dataType = "String",
+                defaultValue = "none",
+                example = "benoit@apache.org",
+                value = "Compulsory. Needs to be a valid username"),
+            @ApiImplicitParam(
+                required = true,
+                name = "mailboxId",
+                paramType = "path parameter",
+                dataType = "String",
+                defaultValue = "none",
+                value = "Compulsory. Needs to be a valid mailbox ID"),
+            @ApiImplicitParam(
+                required = true,
+                name = "uid",
+                paramType = "path parameter",
+                dataType = "Integer",
+                defaultValue = "none",
+                value = "Compulsory. Needs to be a valid UID")
+        })
+        public static TaskFromRequest toTask(ReIndexer reIndexer, MailboxId.Factory mailboxIdFactory) {
+            return wrap(request -> reIndexer.reIndex(
+                extractMailboxId(mailboxIdFactory, request),
+                extractUid(request)));
+        }
 
-    @POST
-    @Path("/{mailboxId}/mails/{uid}")
-    @ApiOperation(value = "Re-indexes a single email")
-    @ApiImplicitParams({
-        @ApiImplicitParam(
-            required = true,
-            name = "task",
-            paramType = "query parameter",
-            dataType = "String",
-            defaultValue = "none",
-            example = "?task=reIndex",
-            value = "Compulsory. Only supported value is `reIndex`"),
-        @ApiImplicitParam(
-            required = true,
-            name = "user",
-            paramType = "path parameter",
-            dataType = "String",
-            defaultValue = "none",
-            example = "benoit@apache.org",
-            value = "Compulsory. Needs to be a valid username"),
-        @ApiImplicitParam(
-            required = true,
-            name = "mailboxId",
-            paramType = "path parameter",
-            dataType = "String",
-            defaultValue = "none",
-            value = "Compulsory. Needs to be a valid mailbox ID"),
-        @ApiImplicitParam(
-            required = true,
-            name = "uid",
-            paramType = "path parameter",
-            dataType = "Integer",
-            defaultValue = "none",
-            value = "Compulsory. Needs to be a valid UID")
-    })
-    private Route reIndexMessage() {
-        return TaskFromRequestRegistry.builder()
-            .parameterName(TASK_PARAMETER)
-            .register(RE_INDEX, wrap(request -> reIndexer.reIndex(extractMailboxId(request), extractUid(request))))
-            .buildAsRoute(taskManager);
+        private static MessageUid extractUid(Request request) {
+            try {
+                return MessageUid.of(Long.parseLong(request.params(UID_PARAM)));
+            } catch (NumberFormatException e) {
+                throw ErrorResponder.builder()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                    .message("'uid' needs to be a parsable long")
+                    .cause(e)
+                    .haltError();
+            }
+        }
     }
 
-    private TaskFromRequest wrap(TaskFromRequest toBeWrapped) {
+    private static TaskFromRequest wrap(TaskFromRequest toBeWrapped) {
         return request -> {
             try {
                 return toBeWrapped.fromRequest(request);
@@ -272,7 +254,7 @@ public class MailboxesRoutes implements Routes {
         };
     }
 
-    private MailboxId extractMailboxId(Request request) {
+    private static MailboxId extractMailboxId(MailboxId.Factory mailboxIdFactory, Request request) {
         try {
             return mailboxIdFactory.fromString(request.params(MAILBOX_PARAM));
         } catch (Exception e) {
@@ -285,16 +267,72 @@ public class MailboxesRoutes implements Routes {
         }
     }
 
-    private MessageUid extractUid(Request request) {
-        try {
-            return MessageUid.of(Long.parseLong(request.params(UID_PARAM)));
-        } catch (NumberFormatException e) {
-            throw ErrorResponder.builder()
-                .statusCode(HttpStatus.BAD_REQUEST_400)
-                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
-                .message("'uid' needs to be a parsable long")
-                .cause(e)
-                .haltError();
-        }
+    private static final String BASE_PATH = "/mailboxes";
+    private static final String RE_INDEX_FAILED_MESSAGES_QUERY_PARAM = "reIndexFailedMessagesOf";
+    private static final String MAILBOX_PARAM = ":mailbox";
+    private static final String UID_PARAM = ":uid";
+    private static final String MAILBOX_PATH = BASE_PATH + "/" + MAILBOX_PARAM;
+    private static final String MESSAGE_PATH = MAILBOX_PATH + "/mails/" + UID_PARAM;
+    static final TaskRegistrationKey RE_INDEX = TaskRegistrationKey.of("reIndex");
+    static final String TASK_PARAMETER = "task";
+    public static final String ALL_MAILBOXES_TASKS = "allMailboxesTasks";
+    public static final String ONE_MAILBOX_TASKS = "oneMailboxTasks";
+    public static final String ONE_MAIL_TASKS = "oneMailTasks";
+
+    private final TaskManager taskManager;
+    private final JsonTransformer jsonTransformer;
+    private final Set<TaskRegistration> allMailboxesTaskRegistration;
+    private final Set<TaskRegistration> oneMailboxTaskRegistration;
+    private final Set<TaskRegistration> oneMailTaskRegistration;
+
+    @Inject
+    MailboxesRoutes(TaskManager taskManager,
+                    JsonTransformer jsonTransformer,
+                    @Named(ALL_MAILBOXES_TASKS) Set<TaskRegistration> allMailboxesTaskRegistration,
+                    @Named(ONE_MAILBOX_TASKS) Set<TaskRegistration> oneMailboxTaskRegistration,
+                    @Named(ONE_MAIL_TASKS) Set<TaskRegistration> oneMailTaskRegistration) {
+        this.taskManager = taskManager;
+        this.jsonTransformer = jsonTransformer;
+        this.allMailboxesTaskRegistration = allMailboxesTaskRegistration;
+        this.oneMailboxTaskRegistration = oneMailboxTaskRegistration;
+        this.oneMailTaskRegistration = oneMailTaskRegistration;
+    }
+
+    @Override
+    public String getBasePath() {
+        return BASE_PATH;
+    }
+
+    @Override
+    public void define(Service service) {
+        allMailboxesOperations()
+            .ifPresent(route -> service.post(BASE_PATH, route, jsonTransformer));
+
+        oneMailboxOperations()
+            .ifPresent(route -> service.post(MAILBOX_PATH, route, jsonTransformer));
+
+        oneMail()
+            .ifPresent(route -> service.post(MESSAGE_PATH, route, jsonTransformer));
+    }
+
+    private Optional<Route> allMailboxesOperations() {
+        return TaskFromRequestRegistry.builder()
+            .parameterName(TASK_PARAMETER)
+            .registrations(allMailboxesTaskRegistration)
+            .buildAsRouteOptional(taskManager);
+    }
+
+    private Optional<Route> oneMailboxOperations() {
+        return TaskFromRequestRegistry.builder()
+            .parameterName(TASK_PARAMETER)
+            .registrations(oneMailboxTaskRegistration)
+            .buildAsRouteOptional(taskManager);
+    }
+
+    private Optional<Route> oneMail() {
+        return TaskFromRequestRegistry.builder()
+            .parameterName(TASK_PARAMETER)
+            .registrations(oneMailTaskRegistration)
+            .buildAsRouteOptional(taskManager);
     }
 }
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesNoTasksTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesNoTasksTest.java
new file mode 100644
index 0000000..2a3b1d1
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesNoTasksTest.java
@@ -0,0 +1,102 @@
+/****************************************************************
+ * 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 io.restassured.RestAssured.when;
+
+import org.apache.james.task.Hostname;
+import org.apache.james.task.MemoryTaskManager;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.WebAdminUtils;
+import org.apache.james.webadmin.tasks.TaskFromRequestRegistry;
+import org.apache.james.webadmin.utils.ErrorResponder;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.eclipse.jetty.http.HttpStatus;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableSet;
+
+import io.restassured.RestAssured;
+
+class MailboxesRoutesNoTasksTest {
+    private static final ImmutableSet<TaskFromRequestRegistry.TaskRegistration> NO_ADDITIONAL_REGISTRATION = ImmutableSet.of();
+
+    private WebAdminServer webAdminServer;
+    private MemoryTaskManager taskManager;
+
+    @BeforeEach
+    void beforeEach() {
+        taskManager = new MemoryTaskManager(new Hostname("foo"));
+        JsonTransformer jsonTransformer = new JsonTransformer();
+
+        webAdminServer = WebAdminUtils.createWebAdminServer(
+                new TasksRoutes(taskManager, jsonTransformer),
+                new MailboxesRoutes(taskManager,
+                    jsonTransformer,
+                    NO_ADDITIONAL_REGISTRATION,
+                    NO_ADDITIONAL_REGISTRATION,
+                    NO_ADDITIONAL_REGISTRATION))
+            .start();
+
+        RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer).build();
+        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
+    }
+
+    @AfterEach
+    void tearDown() {
+        webAdminServer.destroy();
+        taskManager.stop();
+    }
+
+    @Test
+    void allMailboxesEndpointShouldNotBeExposedWhenNoTasks() {
+        when()
+            .post("/mailboxes")
+        .then()
+            .statusCode(HttpStatus.NOT_FOUND_404)
+            .body("statusCode", Matchers.is(404))
+            .body("type", Matchers.is(ErrorResponder.ErrorType.NOT_FOUND.getType()))
+            .body("message", Matchers.is("POST /mailboxes can not be found"));
+    }
+
+    @Test
+    void oneMailboxEndpointShouldNotBeExposedWhenNoTasks() {
+        when()
+            .post("/mailboxes/36")
+        .then()
+            .statusCode(HttpStatus.NOT_FOUND_404)
+            .body("statusCode", Matchers.is(404))
+            .body("type", Matchers.is(ErrorResponder.ErrorType.NOT_FOUND.getType()))
+            .body("message", Matchers.is("POST /mailboxes/36 can not be found"));
+    }
+
+    @Test
+    void oneMailEndpointShouldNotBeExposedWhenNoTasks() {
+        when()
+            .post("/mailboxes/36/mails/7")
+        .then()
+            .statusCode(HttpStatus.NOT_FOUND_404)
+            .body("statusCode", Matchers.is(404))
+            .body("type", Matchers.is(ErrorResponder.ErrorType.NOT_FOUND.getType()))
+            .body("message", Matchers.is("POST /mailboxes/36/mails/7 can not be found"));
+    }
+}
\ No newline at end of file
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesTest.java
index 552356a..50da3b0 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MailboxesRoutesTest.java
@@ -51,7 +51,6 @@ import org.apache.james.task.MemoryTaskManager;
 import org.apache.james.webadmin.WebAdminServer;
 import org.apache.james.webadmin.WebAdminUtils;
 import org.apache.james.webadmin.service.PreviousReIndexingService;
-import org.apache.james.webadmin.tasks.TaskFromRequestRegistry;
 import org.apache.james.webadmin.utils.ErrorResponder;
 import org.apache.james.webadmin.utils.JsonTransformer;
 import org.apache.mailbox.tools.indexer.FullReindexingTask;
@@ -72,7 +71,6 @@ import io.restassured.RestAssured;
 class MailboxesRoutesTest {
     private static final Username USERNAME = Username.of("benwa@apache.org");
     private static final MailboxPath INBOX = MailboxPath.inbox(USERNAME);
-    private static final ImmutableSet<TaskFromRequestRegistry.TaskRegistration> NO_ADDITIONAL_REGISTRATION = ImmutableSet.of();
 
     private WebAdminServer webAdminServer;
     private ListeningMessageSearchIndex searchIndex;
@@ -97,13 +95,17 @@ class MailboxesRoutesTest {
 
         webAdminServer = WebAdminUtils.createWebAdminServer(
                 new TasksRoutes(taskManager, jsonTransformer),
-                new MailboxesRoutes(
-                    taskManager,
-                    new PreviousReIndexingService(taskManager),
-                    mailboxIdFactory,
-                    reIndexer,
+                new MailboxesRoutes(taskManager,
                     jsonTransformer,
-                    NO_ADDITIONAL_REGISTRATION))
+                    ImmutableSet.of(
+                        new MailboxesRoutes.ReIndexAllMailboxesTaskRegistration(
+                            reIndexer, new PreviousReIndexingService(taskManager), mailboxIdFactory)),
+                    ImmutableSet.of(
+                        new MailboxesRoutes.ReIndexOneMailboxTaskRegistration(
+                            reIndexer, mailboxIdFactory)),
+                    ImmutableSet.of(
+                        new MailboxesRoutes.ReIndexOneMailTaskRegistration(
+                            reIndexer, mailboxIdFactory))))
             .start();
 
         RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer).build();


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