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 6f92767ee5277b597a3bfd75fbc25e6e39fe44fa
Author: Benoit Tellier <btell...@linagora.com>
AuthorDate: Mon Dec 16 14:38:31 2019 +0700

    JAMES-2993 Implement recompute all JMAP message preview task
---
 .../MemoryMessageFastViewProjection.java           |   7 +-
 .../protocols/webadmin/webadmin-data-jmap/pom.xml  |  71 +++++++++
 .../jmap/MessageFastViewProjectionCorrector.java   | 142 +++++++++++++++++
 .../data/jmap/RecomputeAllPreviewsTask.java        | 168 +++++++++++++++++++++
 ...uteAllPreviewsTaskAdditionalInformationDTO.java |  98 ++++++++++++
 ...llPreviewsTaskAdditionalInformationDTOTest.java |  47 ++++++
 .../RecomputeAllPreviewsTaskSerializationTest.java |  53 +++++++
 .../json/recomputeAll.additionalInformation.json   |   8 +
 .../src/test/resources/json/recomputeAll.task.json |   1 +
 9 files changed, 591 insertions(+), 4 deletions(-)

diff --git 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryMessageFastViewProjection.java
 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryMessageFastViewProjection.java
index 9492ab3..e39fcbe 100644
--- 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryMessageFastViewProjection.java
+++ 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryMessageFastViewProjection.java
@@ -28,7 +28,6 @@ import 
org.apache.james.jmap.api.projections.MessageFastViewProjection;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.metrics.api.Metric;
 import org.apache.james.metrics.api.MetricFactory;
-import org.reactivestreams.Publisher;
 
 import com.google.common.base.Preconditions;
 
@@ -48,7 +47,7 @@ public class MemoryMessageFastViewProjection implements 
MessageFastViewProjectio
     }
 
     @Override
-    public Publisher<Void> store(MessageId messageId, 
MessageFastViewPrecomputedProperties precomputedProperties) {
+    public Mono<Void> store(MessageId messageId, 
MessageFastViewPrecomputedProperties precomputedProperties) {
         Preconditions.checkNotNull(messageId);
         Preconditions.checkNotNull(precomputedProperties);
 
@@ -56,7 +55,7 @@ public class MemoryMessageFastViewProjection implements 
MessageFastViewProjectio
     }
 
     @Override
-    public Publisher<MessageFastViewPrecomputedProperties> retrieve(MessageId 
messageId) {
+    public Mono<MessageFastViewPrecomputedProperties> retrieve(MessageId 
messageId) {
         Preconditions.checkNotNull(messageId);
 
         return Mono.fromSupplier(() -> previews.get(messageId))
@@ -65,7 +64,7 @@ public class MemoryMessageFastViewProjection implements 
MessageFastViewProjectio
     }
 
     @Override
-    public Publisher<Void> delete(MessageId messageId) {
+    public Mono<Void> delete(MessageId messageId) {
         Preconditions.checkNotNull(messageId);
 
         return Mono.fromRunnable(() -> previews.remove(messageId));
diff --git a/server/protocols/webadmin/webadmin-data-jmap/pom.xml 
b/server/protocols/webadmin/webadmin-data-jmap/pom.xml
index 9ac8a75..e42b17e 100644
--- a/server/protocols/webadmin/webadmin-data-jmap/pom.xml
+++ b/server/protocols/webadmin/webadmin-data-jmap/pom.xml
@@ -33,15 +33,86 @@
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-api</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-json</artifactId>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>james-server-data-jmap</artifactId>
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>james-server-data-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-data-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>james-server-jmap-draft</artifactId>
         </dependency>
         <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>james-server-task-json</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-task-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-webadmin-core</artifactId>
+        </dependency>
+        <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>james-server-webadmin-core</artifactId>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>testing-base</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.javacrumbs.json-unit</groupId>
+            <artifactId>json-unit-assertj</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 </project>
\ No newline at end of file
diff --git 
a/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
 
b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
new file mode 100644
index 0000000..6fc4c86
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java
@@ -0,0 +1,142 @@
+/****************************************************************
+ * 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.data.jmap;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.inject.Inject;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.core.Username;
+import 
org.apache.james.jmap.api.projections.MessageFastViewPrecomputedProperties;
+import org.apache.james.jmap.api.projections.MessageFastViewProjection;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.FetchGroup;
+import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.model.search.MailboxQuery;
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.james.util.streams.Iterators;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.github.fge.lambdas.Throwing;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public class MessageFastViewProjectionCorrector {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(MessageFastViewProjectionCorrector.class);
+
+    static class Progress {
+        private final AtomicLong processedUserCount;
+        private final AtomicLong processedMessageCount;
+        private final AtomicLong failedUserCount;
+        private final AtomicLong failedMessageCount;
+
+        Progress() {
+            failedUserCount = new AtomicLong();
+            processedMessageCount = new AtomicLong();
+            processedUserCount = new AtomicLong();
+            failedMessageCount = new AtomicLong();
+        }
+
+        long getProcessedUserCount() {
+            return processedUserCount.get();
+        }
+
+        long getProcessedMessageCount() {
+            return processedMessageCount.get();
+        }
+
+        long getFailedUserCount() {
+            return failedUserCount.get();
+        }
+
+        long getFailedMessageCount() {
+            return failedMessageCount.get();
+        }
+
+        boolean failed() {
+            return failedMessageCount.get() > 0 || failedUserCount.get() > 0;
+        }
+    }
+
+    private final UsersRepository usersRepository;
+    private final MailboxManager mailboxManager;
+    private final MessageFastViewProjection messageFastViewProjection;
+    private final MessageFastViewPrecomputedProperties.Factory 
projectionItemFactory;
+
+    @Inject
+    MessageFastViewProjectionCorrector(UsersRepository usersRepository, 
MailboxManager mailboxManager,
+                                       MessageFastViewProjection 
messageFastViewProjection,
+                                       
MessageFastViewPrecomputedProperties.Factory projectionItemFactory) {
+        this.usersRepository = usersRepository;
+        this.mailboxManager = mailboxManager;
+        this.messageFastViewProjection = messageFastViewProjection;
+        this.projectionItemFactory = projectionItemFactory;
+    }
+
+    Mono<Void> correctAllProjectionItems(Progress progress) {
+        try {
+            return Iterators.toFlux(usersRepository.list())
+                .concatMap(username -> correctUsersProjectionItems(progress, 
username))
+                .then();
+        } catch (UsersRepositoryException e) {
+            return Mono.error(e);
+        }
+    }
+
+    private Mono<Void> correctUsersProjectionItems(Progress progress, Username 
username) {
+        try {
+            MailboxSession session = 
mailboxManager.createSystemSession(username);
+            return 
Flux.fromIterable(mailboxManager.search(MailboxQuery.privateMailboxesBuilder(session).build(),
 session))
+                .concatMap(mailboxMetadata -> Mono.fromCallable(() -> 
mailboxManager.getMailbox(mailboxMetadata.getId(), session)))
+                .concatMap(Throwing.function(messageManager -> 
correctMailboxProjectionItems(progress, messageManager, session)))
+                .doOnComplete(progress.processedUserCount::incrementAndGet)
+                .onErrorContinue((error, o) -> {
+                    LOGGER.error("JMAP preview re-computation aborted for {}", 
username, error);
+                    progress.failedUserCount.incrementAndGet();
+                })
+                .then();
+        } catch (MailboxException e) {
+            LOGGER.error("JMAP preview re-computation aborted for {} as we 
failed listing user mailboxes", username, e);
+            progress.failedUserCount.incrementAndGet();
+            return Mono.empty();
+        }
+    }
+
+    private Mono<Void> correctMailboxProjectionItems(Progress progress, 
MessageManager messageManager, MailboxSession session) throws MailboxException {
+        return Iterators.toFlux(messageManager.getMessages(MessageRange.all(), 
FetchGroup.MINIMAL, session))
+            .concatMap(Throwing.function(messageResult -> 
Iterators.toFlux(messageManager.getMessages(MessageRange.all(), 
FetchGroup.BODY_CONTENT, session))))
+            .map(Throwing.function(messageResult -> 
Pair.of(messageResult.getMessageId(), 
projectionItemFactory.from(messageResult))))
+            .concatMap(pair -> 
Mono.from(messageFastViewProjection.store(pair.getKey(), pair.getValue()))
+                .doOnSuccess(any -> 
progress.processedMessageCount.incrementAndGet()))
+            .onErrorContinue((error, triggeringValue) -> {
+                LOGGER.error("JMAP preview re-computation aborted for {} - 
{}", session.getUser(), triggeringValue, error);
+                progress.failedMessageCount.incrementAndGet();
+            })
+            .then();
+    }
+}
diff --git 
a/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTask.java
 
b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTask.java
new file mode 100644
index 0000000..bacf8ad
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTask.java
@@ -0,0 +1,168 @@
+/****************************************************************
+ * 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.data.jmap;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.james.json.DTOModule;
+import org.apache.james.server.task.json.dto.TaskDTO;
+import org.apache.james.server.task.json.dto.TaskDTOModule;
+import org.apache.james.task.Task;
+import org.apache.james.task.TaskExecutionDetails;
+import org.apache.james.task.TaskType;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import reactor.core.scheduler.Schedulers;
+
+public class RecomputeAllPreviewsTask implements Task {
+    static final TaskType TASK_TYPE = TaskType.of("RecomputeAllPreviewsTask");
+
+    public static class AdditionalInformation implements 
TaskExecutionDetails.AdditionalInformation {
+        private static AdditionalInformation 
from(MessageFastViewProjectionCorrector.Progress progress) {
+            return new AdditionalInformation(
+                progress.getProcessedUserCount(),
+                progress.getProcessedMessageCount(),
+                progress.getFailedUserCount(),
+                progress.getFailedMessageCount(),
+                Clock.systemUTC().instant());
+        }
+
+        private final long processedUserCount;
+        private final long processedMessageCount;
+        private final long failedUserCount;
+        private final long failedMessageCount;
+        private final Instant timestamp;
+
+        public AdditionalInformation(long processedUserCount, long 
processedMessageCount, long failedUserCount, long failedMessageCount, Instant 
timestamp) {
+            this.processedUserCount = processedUserCount;
+            this.processedMessageCount = processedMessageCount;
+            this.failedUserCount = failedUserCount;
+            this.failedMessageCount = failedMessageCount;
+            this.timestamp = timestamp;
+        }
+
+        public long getProcessedUserCount() {
+            return processedUserCount;
+        }
+
+        public long getProcessedMessageCount() {
+            return processedMessageCount;
+        }
+
+        public long getFailedUserCount() {
+            return failedUserCount;
+        }
+
+        public long getFailedMessageCount() {
+            return failedMessageCount;
+        }
+
+        @Override
+        public Instant timestamp() {
+            return timestamp;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof AdditionalInformation) {
+                AdditionalInformation that = (AdditionalInformation) o;
+
+                return Objects.equals(this.processedUserCount, 
that.processedUserCount)
+                    && Objects.equals(this.processedMessageCount, 
that.processedMessageCount)
+                    && Objects.equals(this.failedUserCount, 
that.failedUserCount)
+                    && Objects.equals(this.failedMessageCount, 
that.failedMessageCount)
+                    && Objects.equals(this.timestamp, that.timestamp);
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(processedUserCount, processedMessageCount, 
failedUserCount, failedMessageCount, timestamp);
+        }
+    }
+
+    public static class RecomputeAllPreviousTaskDTO implements TaskDTO {
+        private final String type;
+
+        public RecomputeAllPreviousTaskDTO(@JsonProperty("type") String type) {
+            this.type = type;
+        }
+
+        @Override
+        public String getType() {
+            return type;
+        }
+    }
+
+    public static TaskDTOModule<RecomputeAllPreviewsTask, 
RecomputeAllPreviousTaskDTO> module(MessageFastViewProjectionCorrector 
corrector) {
+        return DTOModule
+            .forDomainObject(RecomputeAllPreviewsTask.class)
+            .convertToDTO(RecomputeAllPreviousTaskDTO.class)
+            .toDomainObjectConverter(dto -> new 
RecomputeAllPreviewsTask(corrector))
+            .toDTOConverter((task, type) -> new 
RecomputeAllPreviousTaskDTO(type))
+            .typeName(TASK_TYPE.asString())
+            .withFactory(TaskDTOModule::new);
+    }
+
+    private final MessageFastViewProjectionCorrector corrector;
+    private final MessageFastViewProjectionCorrector.Progress progress;
+
+    RecomputeAllPreviewsTask(MessageFastViewProjectionCorrector corrector) {
+        this.corrector = corrector;
+        this.progress = new MessageFastViewProjectionCorrector.Progress();
+    }
+
+    @Override
+    public Result run() {
+        corrector.correctAllProjectionItems(progress)
+            .subscribeOn(Schedulers.boundedElastic())
+            .block();
+
+        if (progress.failed()) {
+            return Result.PARTIAL;
+        }
+        return Result.COMPLETED;
+    }
+
+    @Override
+    public TaskType type() {
+        return TASK_TYPE;
+    }
+
+    @Override
+    public Optional<TaskExecutionDetails.AdditionalInformation> details() {
+        return Optional.of(AdditionalInformation.from(progress));
+    }
+
+    @Override
+    public final boolean equals(Object o) {
+        return o instanceof RecomputeAllPreviewsTask;
+    }
+
+    @Override
+    public final int hashCode() {
+        return Objects.hash(RecomputeAllPreviewsTask.class);
+    }
+}
\ No newline at end of file
diff --git 
a/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTO.java
 
b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTO.java
new file mode 100644
index 0000000..aab6aa7
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTO.java
@@ -0,0 +1,98 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.webadmin.data.jmap;
+
+import java.time.Instant;
+
+import org.apache.james.json.DTOModule;
+import org.apache.james.server.task.json.dto.AdditionalInformationDTO;
+import org.apache.james.server.task.json.dto.AdditionalInformationDTOModule;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.annotations.VisibleForTesting;
+
+public class RecomputeAllPreviewsTaskAdditionalInformationDTO implements 
AdditionalInformationDTO {
+    public static final 
AdditionalInformationDTOModule<RecomputeAllPreviewsTask.AdditionalInformation, 
RecomputeAllPreviewsTaskAdditionalInformationDTO> SERIALIZATION_MODULE =
+        
DTOModule.forDomainObject(RecomputeAllPreviewsTask.AdditionalInformation.class)
+            
.convertToDTO(RecomputeAllPreviewsTaskAdditionalInformationDTO.class)
+            .toDomainObjectConverter(dto -> new 
RecomputeAllPreviewsTask.AdditionalInformation(
+                dto.getProcessedUserCount(),
+                dto.getProcessedMessageCount(),
+                dto.getFailedUserCount(),
+                dto.getFailedMessageCount(),
+                dto.timestamp))
+            .toDTOConverter((details, type) -> new 
RecomputeAllPreviewsTaskAdditionalInformationDTO(
+                type,
+                details.timestamp(),
+                details.getProcessedUserCount(),
+                details.getProcessedMessageCount(),
+                details.getFailedUserCount(),
+                details.getFailedMessageCount()))
+            .typeName(RecomputeAllPreviewsTask.TASK_TYPE.asString())
+            .withFactory(AdditionalInformationDTOModule::new);
+
+    private final String type;
+    private final Instant timestamp;
+    private final long processedUserCount;
+    private final long processedMessageCount;
+    private final long failedUserCount;
+    private final long failedMessageCount;
+
+    @VisibleForTesting
+    RecomputeAllPreviewsTaskAdditionalInformationDTO(@JsonProperty("type") 
String type,
+                                                     
@JsonProperty("timestamp") Instant timestamp,
+                                                     
@JsonProperty("processedUserCount") long processedUserCount,
+                                                     
@JsonProperty("processedMessageCount") long processedMessageCount,
+                                                     
@JsonProperty("failedUserCount") long failedUserCount,
+                                                     
@JsonProperty("failedMessageCount") long failedMessageCount) {
+        this.type = type;
+        this.timestamp = timestamp;
+        this.processedUserCount = processedUserCount;
+        this.processedMessageCount = processedMessageCount;
+        this.failedUserCount = failedUserCount;
+        this.failedMessageCount = failedMessageCount;
+    }
+
+    @Override
+    public String getType() {
+        return type;
+    }
+
+    @Override
+    public Instant getTimestamp() {
+        return timestamp;
+    }
+
+    public long getProcessedUserCount() {
+        return processedUserCount;
+    }
+
+    public long getProcessedMessageCount() {
+        return processedMessageCount;
+    }
+
+    public long getFailedUserCount() {
+        return failedUserCount;
+    }
+
+    public long getFailedMessageCount() {
+        return failedMessageCount;
+    }
+}
diff --git 
a/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTOTest.java
 
b/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTOTest.java
new file mode 100644
index 0000000..125464f
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTOTest.java
@@ -0,0 +1,47 @@
+/****************************************************************
+ * 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.data.jmap;
+
+import java.time.Instant;
+
+import org.apache.james.JsonSerializationVerifier;
+import org.apache.james.util.ClassLoaderUtils;
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class RecomputeAllPreviewsTaskAdditionalInformationDTOTest {
+    private static final Instant INSTANT = 
Instant.parse("2007-12-03T10:15:30.00Z");
+    private static final RecomputeAllPreviewsTask.AdditionalInformation 
DOMAIN_OBJECT = new RecomputeAllPreviewsTask.AdditionalInformation(1, 2, 3, 4, 
INSTANT);
+
+    @Test
+    void shouldMatchJsonSerializationContract() throws Exception {
+        
JsonSerializationVerifier.dtoModule(RecomputeAllPreviewsTaskAdditionalInformationDTO.SERIALIZATION_MODULE)
+            .bean(DOMAIN_OBJECT)
+            
.json(ClassLoaderUtils.getSystemResourceAsString("json/recomputeAll.additionalInformation.json"))
+            .verify();
+    }
+
+    @Test
+    void shouldMatchBeanContract() {
+        
EqualsVerifier.forClass(RecomputeAllPreviewsTask.AdditionalInformation.class)
+            .verify();
+    }
+}
\ No newline at end of file
diff --git 
a/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskSerializationTest.java
 
b/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskSerializationTest.java
new file mode 100644
index 0000000..e56432a
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskSerializationTest.java
@@ -0,0 +1,53 @@
+/****************************************************************
+ * 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.data.jmap;
+
+import static org.mockito.Mockito.mock;
+
+import org.apache.james.JsonSerializationVerifier;
+import org.apache.james.util.ClassLoaderUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+class RecomputeAllPreviewsTaskSerializationTest {
+    MessageFastViewProjectionCorrector corrector;
+
+    @BeforeEach
+    void setUp() {
+        corrector = mock(MessageFastViewProjectionCorrector.class);
+    }
+
+    @Test
+    void shouldMatchJsonSerializationContract() throws Exception {
+        
JsonSerializationVerifier.dtoModule(RecomputeAllPreviewsTask.module(corrector))
+            .bean(new RecomputeAllPreviewsTask(corrector))
+            
.json(ClassLoaderUtils.getSystemResourceAsString("json/recomputeAll.task.json"))
+            .verify();
+    }
+
+    @Test
+    void shouldMatchBeanContract() {
+        EqualsVerifier.forClass(RecomputeAllPreviewsTask.class)
+            .withIgnoredFields("corrector", "progress")
+            .verify();
+    }
+}
\ No newline at end of file
diff --git 
a/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.additionalInformation.json
 
b/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.additionalInformation.json
new file mode 100644
index 0000000..bc3d81f
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.additionalInformation.json
@@ -0,0 +1,8 @@
+{
+  "type":"RecomputeAllPreviewsTask",
+  "timestamp":"2007-12-03T10:15:30Z",
+  "processedUserCount":1,
+  "processedMessageCount":2,
+  "failedUserCount":3,
+  "failedMessageCount":4
+}
\ No newline at end of file
diff --git 
a/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.task.json
 
b/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.task.json
new file mode 100644
index 0000000..a447293
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.task.json
@@ -0,0 +1 @@
+{"type":"RecomputeAllPreviewsTask"}
\ No newline at end of file


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

Reply via email to