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 2020/08/19 07:38:32 UTC

[james-project] 03/11: JAMES-3356 Refactoring: unify error handling for mailbox creation parsing/handling

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 6e15127facd944a90d318909d60707293dac79b9
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Aug 14 10:34:45 2020 +0700

    JAMES-3356 Refactoring: unify error handling for mailbox creation parsing/handling
    
    This makes it easier to follow the error management logic as it all goes though one place.
    
    Methods arguments within MailboxSetMethod are furthermore simplified.
---
 .../james/jmap/method/MailboxSetMethod.scala       | 55 ++++++++++------------
 1 file changed, 25 insertions(+), 30 deletions(-)

diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
index ae3bec0..94b64b2 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxSetMethod.scala
@@ -37,10 +37,9 @@ import play.api.libs.json._
 import reactor.core.scala.publisher.{SFlux, SMono}
 import reactor.core.scheduler.Schedulers
 
-import scala.collection.immutable
-
 case class MailboxHasMailException(mailboxId: MailboxId) extends Exception
 case class MailboxHasChildException(mailboxId: MailboxId) extends Exception
+case class MailboxCreationParseException(mailboxSetError: MailboxSetError) extends Exception
 
 sealed trait CreationResult {
   def mailboxCreationId: MailboxCreationId
@@ -51,6 +50,7 @@ case class CreationFailure(mailboxCreationId: MailboxCreationId, exception: Exce
     case e: MailboxNotFoundException => MailboxSetError.invalidArgument(Some(SetErrorDescription(e.getMessage)), Some(Properties(List("parentId"))))
     case e: MailboxExistsException => MailboxSetError.invalidArgument(Some(SetErrorDescription(e.getMessage)), Some(Properties(List("name"))))
     case e: MailboxNameException => MailboxSetError.invalidArgument(Some(SetErrorDescription(e.getMessage)), Some(Properties(List("name"))))
+    case e: MailboxCreationParseException => e.mailboxSetError
     case _: InsufficientRightsException => MailboxSetError.forbidden(Some(SetErrorDescription("Insufficient rights")), Some(Properties(List("parentId"))))
     case _ => MailboxSetError.serverFail(Some(SetErrorDescription(exception.getMessage)), None)
   }
@@ -107,27 +107,18 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
     metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
       asMailboxSetRequest(invocation.arguments)
         .flatMap(mailboxSetRequest => {
-          val (unparsableCreateRequests, createRequests) = parseCreateRequests(mailboxSetRequest)
           for {
-            creationResults <- createMailboxes(mailboxSession, createRequests, processingContext)
-            deletionResults <- deleteMailboxes(mailboxSession, mailboxSetRequest.destroy.getOrElse(Seq()), processingContext)
-          } yield createResponse(invocation, mailboxSetRequest, unparsableCreateRequests, creationResults, deletionResults)
+            creationResults <- createMailboxes(mailboxSession, mailboxSetRequest, processingContext)
+            deletionResults <- deleteMailboxes(mailboxSession, mailboxSetRequest, processingContext)
+          } yield createResponse(invocation, mailboxSetRequest, creationResults, deletionResults)
         }))
   }
 
-  private def parseCreateRequests(mailboxSetRequest: MailboxSetRequest): (immutable.Iterable[(MailboxCreationId, MailboxSetError)], immutable.Iterable[(MailboxCreationId, MailboxCreationRequest)]) = {
-    mailboxSetRequest.create
-      .getOrElse(Map.empty)
-      .view
-      .mapValues(value => Json.fromJson(value)(serializer.mailboxCreationRequest))
-      .toMap
-      .partitionMap { case (creationId, creationRequestParseResult) =>
-        creationRequestParseResult match {
-          case JsSuccess(creationRequest, _) => Right((creationId, creationRequest))
-          case JsError(errors) => Left(creationId, mailboxSetError(errors))
-        }
-      }
-  }
+  def parseCreate(jsObject: JsObject): Either[MailboxCreationParseException, MailboxCreationRequest] =
+    Json.fromJson(jsObject)(serializer.mailboxCreationRequest) match {
+      case JsSuccess(creationRequest, _) => Right(creationRequest)
+      case JsError(errors) => Left(MailboxCreationParseException(mailboxSetError(errors)))
+    }
 
   private def mailboxSetError(errors: collection.Seq[(JsPath, collection.Seq[JsonValidationError])]): MailboxSetError =
     errors.head match {
@@ -136,8 +127,8 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
       case (path, _) => MailboxSetError.invalidArgument(Some(SetErrorDescription(s"Unknown error on property '$path'")), None)
     }
 
-  private def deleteMailboxes(mailboxSession: MailboxSession, deleteRequests: immutable.Iterable[UnparsedMailboxId], processingContext: ProcessingContext): SMono[DeletionResults] = {
-    SFlux.fromIterable(deleteRequests)
+  private def deleteMailboxes(mailboxSession: MailboxSession, mailboxSetRequest: MailboxSetRequest, processingContext: ProcessingContext): SMono[DeletionResults] = {
+    SFlux.fromIterable(mailboxSetRequest.destroy.getOrElse(Seq()))
       .flatMap(id => delete(mailboxSession, processingContext, id)
         .onErrorRecover(e => DeletionFailure(id, e)))
       .collectSeq()
@@ -165,12 +156,15 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
   }
 
   private def createMailboxes(mailboxSession: MailboxSession,
-                              createRequests: immutable.Iterable[(MailboxCreationId, MailboxCreationRequest)],
+                              mailboxSetRequest: MailboxSetRequest,
                               processingContext: ProcessingContext): SMono[CreationResults] = {
-    SFlux.fromIterable(createRequests).flatMap {
-      case (mailboxCreationId: MailboxCreationId, mailboxCreationRequest: MailboxCreationRequest) =>
+    SFlux.fromIterable(mailboxSetRequest.create
+      .getOrElse(Map.empty)
+      .view)
+      .flatMap {
+      case (mailboxCreationId: MailboxCreationId, jsObject: JsObject) =>
         SMono.fromCallable(() => {
-          createMailbox(mailboxSession, mailboxCreationId, mailboxCreationRequest, processingContext)
+          createMailbox(mailboxSession, mailboxCreationId, jsObject, processingContext)
         }).subscribeOn(Schedulers.elastic())
     }
       .collectSeq()
@@ -179,9 +173,10 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
 
   private def createMailbox(mailboxSession: MailboxSession,
                             mailboxCreationId: MailboxCreationId,
-                            mailboxCreationRequest: MailboxCreationRequest,
+                            jsObject: JsObject,
                             processingContext: ProcessingContext): CreationResult = {
-    resolvePath(mailboxSession, mailboxCreationRequest)
+    parseCreate(jsObject)
+        .flatMap(mailboxCreationRequest => resolvePath(mailboxSession, mailboxCreationRequest))
       .map(path => createMailbox(mailboxSession, mailboxCreationId, processingContext, path))
       .fold(e => CreationFailure(mailboxCreationId, e), r => r)
   }
@@ -229,8 +224,8 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
     }
 
   private def createResponse(invocation: Invocation, mailboxSetRequest: MailboxSetRequest,
-                             unparsableCreateRequests: immutable.Iterable[(MailboxCreationId, MailboxSetError)],
-                             creationResults: CreationResults, deletionResults: DeletionResults): Invocation = {
+                             creationResults: CreationResults,
+                             deletionResults: DeletionResults): Invocation = {
     val created: Map[MailboxCreationId, MailboxId] = creationResults.retrieveCreated
 
     Invocation(methodName, Arguments(serializer.serialize(MailboxSetResponse(
@@ -251,7 +246,7 @@ class MailboxSetMethod @Inject()(serializer: Serializer,
         quotas = None,
         isSubscribed = IsSubscribed(true)
       )))).filter(_.nonEmpty),
-      notCreated = Some(unparsableCreateRequests.toMap ++ creationResults.retrieveErrors).filter(_.nonEmpty),
+      notCreated = Some(creationResults.retrieveErrors).filter(_.nonEmpty),
       updated = None,
       notUpdated = None,
       notDestroyed = Some(deletionResults.retrieveErrors).filter(_.nonEmpty)


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