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

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

commit 8b31b688652ce38dea7a9dce6f3759232e03ecbf
Author: Tung TRAN <[email protected]>
AuthorDate: Tue Aug 3 18:06:16 2021 +0700

    JAMES-3621 Mailbox webadmin - Clearing content of mailbox - Task
---
 .../webadmin/service/ClearMailboxContentTask.java  | 214 +++++++++++++++++++++
 ...MailboxContentTaskAdditionalInformationDTO.java | 100 ++++++++++
 .../webadmin/service/UserMailboxesService.java     |  38 +++-
 3 files changed, 351 insertions(+), 1 deletion(-)

diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ClearMailboxContentTask.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ClearMailboxContentTask.java
new file mode 100644
index 0000000..32ffdd4
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ClearMailboxContentTask.java
@@ -0,0 +1,214 @@
+/****************************************************************
+ * 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.time.Clock;
+import java.time.Instant;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.james.core.Username;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.task.Task;
+import org.apache.james.task.TaskExecutionDetails;
+import org.apache.james.task.TaskType;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.james.webadmin.validation.MailboxName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+import reactor.core.scheduler.Schedulers;
+
+public class ClearMailboxContentTask implements Task {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(ClearMailboxContentTask.class);
+
+    public static class Context {
+        public static class Snapshot {
+            private final long messagesSuccessCount;
+            private final long messagesFailedCount;
+
+            private Snapshot(long messagesSuccessCount, long 
messagesFailedCount) {
+                this.messagesSuccessCount = messagesSuccessCount;
+                this.messagesFailedCount = messagesFailedCount;
+            }
+
+            public long getMessagesSuccessCount() {
+                return messagesSuccessCount;
+            }
+
+            public long getMessagesFailedCount() {
+                return messagesFailedCount;
+            }
+
+            @Override
+            public final boolean equals(Object o) {
+                if (o instanceof Snapshot) {
+                    Snapshot that = (Snapshot) o;
+
+                    return Objects.equals(this.messagesSuccessCount, 
that.messagesSuccessCount)
+                        && Objects.equals(this.messagesFailedCount, 
that.messagesFailedCount);
+                }
+                return false;
+            }
+
+            @Override
+            public final int hashCode() {
+                return Objects.hash(messagesSuccessCount, messagesFailedCount);
+            }
+
+            @Override
+            public String toString() {
+                return MoreObjects.toStringHelper(this)
+                    .add("messagesSuccessCount", messagesSuccessCount)
+                    .add("messagesFailedCount", messagesFailedCount)
+                    .toString();
+            }
+        }
+
+        private final AtomicLong messagesSuccessCount;
+        private final AtomicLong messagesFailedCount;
+
+        public Context() {
+            this.messagesSuccessCount = new AtomicLong();
+            this.messagesFailedCount = new AtomicLong();
+        }
+
+        public Context(long messagesSuccessCount, long messagesFailedCount) {
+            this.messagesSuccessCount = new AtomicLong(messagesSuccessCount);
+            this.messagesFailedCount = new AtomicLong(messagesFailedCount);
+        }
+
+        public void incrementSuccesses() {
+            messagesSuccessCount.incrementAndGet();
+        }
+
+
+        public void incrementMessageFails() {
+            messagesFailedCount.incrementAndGet();
+        }
+
+        public Snapshot snapshot() {
+            return new Snapshot(messagesSuccessCount.get(), 
messagesFailedCount.get());
+        }
+    }
+
+    public static class AdditionalInformation implements 
TaskExecutionDetails.AdditionalInformation {
+
+        private static AdditionalInformation from(Username username,
+                                                  MailboxName mailboxName,
+                                                  Context context) {
+            Context.Snapshot snapshot = context.snapshot();
+            return new AdditionalInformation(username, mailboxName, 
Clock.systemUTC().instant(), snapshot.messagesSuccessCount, 
snapshot.messagesFailedCount);
+        }
+
+        private final Username username;
+        private final MailboxName mailboxName;
+        private final Instant timestamp;
+        private final long messagesSuccessCount;
+        private final long messagesFailCount;
+
+        public AdditionalInformation(Username username,
+                                     MailboxName mailboxName,
+                                     Instant timestamp,
+                                     long messagesSuccessCount,
+                                     long messagesFailCount) {
+            this.username = username;
+            this.mailboxName = mailboxName;
+            this.timestamp = timestamp;
+            this.messagesSuccessCount = messagesSuccessCount;
+            this.messagesFailCount = messagesFailCount;
+        }
+
+        public Username getUsername() {
+            return username;
+        }
+
+        public MailboxName getMailboxName() {
+            return mailboxName;
+        }
+
+        public Instant getTimestamp() {
+            return timestamp;
+        }
+
+        public long getMessagesSuccessCount() {
+            return messagesSuccessCount;
+        }
+
+        public long getMessagesFailCount() {
+            return messagesFailCount;
+        }
+
+        @Override
+        public Instant timestamp() {
+            return timestamp;
+        }
+    }
+
+    public static final TaskType TASK_TYPE = 
TaskType.of("ClearMailboxContentTask");
+
+    private final Context context;
+    private final Username username;
+    private final MailboxName mailboxName;
+    private final UserMailboxesService userMailboxesService;
+
+    public ClearMailboxContentTask(Username username,
+                                   MailboxName mailboxName,
+                                   UserMailboxesService userMailboxesService) {
+        this.username = username;
+        this.mailboxName = mailboxName;
+        this.userMailboxesService = userMailboxesService;
+        this.context = new Context();
+
+    }
+
+    @Override
+    public Result run() throws InterruptedException {
+        try {
+            return userMailboxesService.clearMailboxContent(username, 
mailboxName, context)
+                .subscribeOn(Schedulers.elastic())
+                .block();
+        } catch (UsersRepositoryException | MailboxException e) {
+            LOGGER.error("Has an error when clear the mailbox content. ", e);
+            throw new InterruptedException(e.getMessage());
+        }
+    }
+
+    @Override
+    public TaskType type() {
+        return TASK_TYPE;
+    }
+
+    @Override
+    public Optional<TaskExecutionDetails.AdditionalInformation> details() {
+        return Optional.of(AdditionalInformation.from(username, mailboxName, 
context));
+    }
+
+    public Username getUsername() {
+        return username;
+    }
+
+    public MailboxName getMailboxName() {
+        return mailboxName;
+    }
+}
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ClearMailboxContentTaskAdditionalInformationDTO.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ClearMailboxContentTaskAdditionalInformationDTO.java
new file mode 100644
index 0000000..0e37eb7
--- /dev/null
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ClearMailboxContentTaskAdditionalInformationDTO.java
@@ -0,0 +1,100 @@
+/****************************************************************
+ * 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.time.Instant;
+
+import org.apache.james.core.Username;
+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 org.apache.james.webadmin.validation.MailboxName;
+
+public class ClearMailboxContentTaskAdditionalInformationDTO implements 
AdditionalInformationDTO {
+
+    public static final 
AdditionalInformationDTOModule<ClearMailboxContentTask.AdditionalInformation, 
ClearMailboxContentTaskAdditionalInformationDTO> SERIALIZATION_MODULE =
+        
DTOModule.forDomainObject(ClearMailboxContentTask.AdditionalInformation.class)
+            
.convertToDTO(ClearMailboxContentTaskAdditionalInformationDTO.class)
+            
.toDomainObjectConverter(ClearMailboxContentTaskAdditionalInformationDTO::toDomainObject)
+            
.toDTOConverter(ClearMailboxContentTaskAdditionalInformationDTO::toDto)
+            .typeName(ClearMailboxContentTask.TASK_TYPE.asString())
+            .withFactory(AdditionalInformationDTOModule::new);
+
+    private static ClearMailboxContentTask.AdditionalInformation 
toDomainObject(ClearMailboxContentTaskAdditionalInformationDTO dto) {
+        return new ClearMailboxContentTask.AdditionalInformation(
+            Username.of(dto.getUsername()),
+            new MailboxName(dto.getMailboxName()),
+            dto.getTimestamp(),
+            dto.getMessagesSuccessCount(),
+            dto.getMessagesFailCount());
+    }
+
+    private static ClearMailboxContentTaskAdditionalInformationDTO 
toDto(ClearMailboxContentTask.AdditionalInformation domain, String type) {
+        return new ClearMailboxContentTaskAdditionalInformationDTO(
+            type,
+            domain.getUsername().asString(),
+            domain.getMailboxName().asString(),
+            domain.getTimestamp(),
+            domain.getMessagesSuccessCount(),
+            domain.getMessagesFailCount());
+    }
+
+    private final String type;
+    private final String username;
+    private final String mailboxName;
+    private final Instant timestamp;
+    private final long messagesSuccessCount;
+    private final long messagesFailCount;
+
+    public ClearMailboxContentTaskAdditionalInformationDTO(String type, String 
username, String mailboxName, Instant timestamp, long messagesSuccessCount, 
long messagesFailCount) {
+        this.type = type;
+        this.username = username;
+        this.mailboxName = mailboxName;
+        this.timestamp = timestamp;
+        this.messagesSuccessCount = messagesSuccessCount;
+        this.messagesFailCount = messagesFailCount;
+    }
+
+    @Override
+    public String getType() {
+        return type;
+    }
+
+    @Override
+    public Instant getTimestamp() {
+        return timestamp;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getMailboxName() {
+        return mailboxName;
+    }
+
+    public long getMessagesSuccessCount() {
+        return messagesSuccessCount;
+    }
+
+    public long getMessagesFailCount() {
+        return messagesFailCount;
+    }
+}
diff --git 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
index 4a839d4..dde29fe 100644
--- 
a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
+++ 
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
@@ -29,12 +29,17 @@ import javax.inject.Inject;
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.MessageUid;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxExistsException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.model.MailboxMetaData;
 import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageRange;
 import org.apache.james.mailbox.model.search.MailboxQuery;
+import org.apache.james.task.Task;
+import org.apache.james.task.Task.Result;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.webadmin.dto.MailboxResponse;
@@ -47,8 +52,9 @@ import com.github.fge.lambdas.Throwing;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
-
+import reactor.core.scheduler.Schedulers;
 
 public class UserMailboxesService {
     private static final Logger LOGGER = 
LoggerFactory.getLogger(UserMailboxesService.class);
@@ -99,6 +105,36 @@ public class UserMailboxesService {
             .block();
     }
 
+    public Mono<Result> clearMailboxContent(Username username, MailboxName 
mailboxName, ClearMailboxContentTask.Context context) throws 
UsersRepositoryException, MailboxException {
+        MailboxSession mailboxSession = 
mailboxManager.createSystemSession(username);
+        MessageManager messageManager = 
mailboxManager.getMailbox(MailboxPath.forUser(username, 
mailboxName.asString()), mailboxSession);
+
+        return 
Flux.from(messageManager.listMessagesMetadata(MessageRange.all(), 
mailboxSession))
+            .map(metaData -> metaData.getComposedMessageId().getUid())
+            .concatMap(messageUid -> deleteMessage(messageManager, messageUid, 
mailboxSession, context))
+            .onErrorResume(e -> {
+                LOGGER.error("Error when clear mailbox content. Mailbox {} for 
user {}", mailboxName.asString(), username, e);
+                context.incrementMessageFails();
+                return Mono.just(Result.PARTIAL);
+            })
+            .reduce(Task::combine)
+            .switchIfEmpty(Mono.just(Result.COMPLETED));
+    }
+
+    private Mono<Result> deleteMessage(MessageManager messageManager, 
MessageUid messageUid, MailboxSession mailboxSession, 
ClearMailboxContentTask.Context context) {
+        return Mono.fromCallable(() -> {
+                try {
+                    messageManager.delete(List.of(messageUid), mailboxSession);
+                    context.incrementSuccesses();
+                    return Result.COMPLETED;
+                } catch (MailboxException e) {
+                    context.incrementMessageFails();
+                    return Result.PARTIAL;
+                }
+            })
+            .subscribeOn(Schedulers.elastic());
+    }
+
     public void deleteMailbox(Username username, MailboxName mailboxName) 
throws MailboxException, UsersRepositoryException, MailboxHaveChildrenException 
{
         usernamePreconditions(username);
         MailboxSession mailboxSession = 
mailboxManager.createSystemSession(username);

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to