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 rc...@apache.org on 2020/06/08 03:12:32 UTC

[james-project] 11/16: JAMES-3171 Add MailboxSession in Method and do a better handling of method processing in JMAPApiRoutes

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 10e46aa3e8a43eef367360dac0bc313e8e1978fc
Author: Rene Cordier <rc...@linagora.com>
AuthorDate: Fri May 22 16:37:26 2020 +0700

    JAMES-3171 Add MailboxSession in Method and do a better handling of method processing in JMAPApiRoutes
---
 .../james/jmap/rfc8621/RFC8621MethodsModule.java   |  4 +-
 .../{CoreEcho.scala => CoreEchoMethod.scala}       |  5 ++-
 .../org/apache/james/jmap/method/Method.scala      |  3 +-
 .../apache/james/jmap/routes/JMAPApiRoutes.scala   | 45 ++++++++++++++--------
 ...CoreEchoTest.scala => CoreEchoMethodTest.scala} | 11 ++++--
 .../james/jmap/routes/JMAPApiRoutesTest.scala      |  6 ++-
 6 files changed, 49 insertions(+), 25 deletions(-)

diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/rfc8621/RFC8621MethodsModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/rfc8621/RFC8621MethodsModule.java
index f085137..8d855de 100644
--- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/rfc8621/RFC8621MethodsModule.java
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/rfc8621/RFC8621MethodsModule.java
@@ -27,7 +27,7 @@ import org.apache.james.jmap.http.BasicAuthenticationStrategy;
 import org.apache.james.jmap.http.rfc8621.InjectionKeys;
 import org.apache.james.jmap.json.Serializer;
 import org.apache.james.jmap.jwt.JWTAuthenticationStrategy;
-import org.apache.james.jmap.method.CoreEcho;
+import org.apache.james.jmap.method.CoreEchoMethod;
 import org.apache.james.jmap.method.Method;
 import org.apache.james.jmap.routes.JMAPApiRoutes;
 import org.apache.james.metrics.api.MetricFactory;
@@ -47,7 +47,7 @@ public class RFC8621MethodsModule extends AbstractModule {
         bind(Serializer.class).in(Scopes.SINGLETON);
 
         Multibinder<Method> methods = Multibinder.newSetBinder(binder(), Method.class);
-        methods.addBinding().to(CoreEcho.class);
+        methods.addBinding().to(CoreEchoMethod.class);
     }
 
     @ProvidesIntoSet
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEcho.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
similarity index 86%
rename from server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEcho.scala
rename to server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
index efeb0e7..fad57d8 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEcho.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala
@@ -22,11 +22,12 @@ package org.apache.james.jmap.method
 import eu.timepit.refined.auto._
 import org.apache.james.jmap.model.Invocation
 import org.apache.james.jmap.model.Invocation.MethodName
+import org.apache.james.mailbox.MailboxSession
 import org.reactivestreams.Publisher
 import reactor.core.scala.publisher.SMono
 
-class CoreEcho extends Method {
+class CoreEchoMethod extends Method {
   override val methodName = MethodName("Core/echo")
 
-  override def process(invocation: Invocation): Publisher[Invocation] = SMono.just(invocation)
+  override def process(invocation: Invocation, mailboxSession: MailboxSession): Publisher[Invocation] = SMono.just(invocation)
 }
\ No newline at end of file
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
index 8ff5b6d..21b33b5 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala
@@ -21,11 +21,12 @@ package org.apache.james.jmap.method
 
 import org.apache.james.jmap.model.Invocation
 import org.apache.james.jmap.model.Invocation.MethodName
+import org.apache.james.mailbox.MailboxSession
 import org.reactivestreams.Publisher
 
 trait Method {
   val methodName: MethodName
 
-  def process(invocation: Invocation): Publisher[Invocation]
+  def process(invocation: Invocation, mailboxSession: MailboxSession): Publisher[Invocation]
 }
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
index 410ad77..478cdcc 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala
@@ -35,10 +35,11 @@ import org.apache.james.jmap.exceptions.UnauthorizedException
 import org.apache.james.jmap.http.Authenticator
 import org.apache.james.jmap.http.rfc8621.InjectionKeys
 import org.apache.james.jmap.json.Serializer
-import org.apache.james.jmap.method.CoreEcho
+import org.apache.james.jmap.method.Method
 import org.apache.james.jmap.model.Invocation.{Arguments, MethodName}
 import org.apache.james.jmap.model.{Invocation, RequestObject, ResponseObject}
 import org.apache.james.jmap.{Endpoint, JMAPRoute, JMAPRoutes}
+import org.apache.james.mailbox.MailboxSession
 import org.slf4j.{Logger, LoggerFactory}
 import play.api.libs.json.{JsError, JsSuccess, Json}
 import reactor.core.publisher.Mono
@@ -46,13 +47,25 @@ import reactor.core.scala.publisher.{SFlux, SMono}
 import reactor.core.scheduler.Schedulers
 import reactor.netty.http.server.{HttpServerRequest, HttpServerResponse}
 
+import scala.collection.mutable
+import scala.jdk.CollectionConverters._
+
 object JMAPApiRoutes {
   val LOGGER: Logger = LoggerFactory.getLogger(classOf[JMAPApiRoutes])
 }
 
-class JMAPApiRoutes @Inject() (@Named(InjectionKeys.RFC_8621) val authenticator: Authenticator,
-                               val serializer: Serializer) extends JMAPRoutes {
-  private val coreEcho = new CoreEcho
+class JMAPApiRoutes (val authenticator: Authenticator,
+                     serializer: Serializer,
+                     methods: Set[Method]) extends JMAPRoutes {
+
+  private val methodsByName: Map[MethodName, Method] = methods.map(method => method.methodName -> method).toMap
+
+  @Inject
+  def this(@Named(InjectionKeys.RFC_8621) authenticator: Authenticator,
+           serializer: Serializer,
+           javaMethods: java.util.Set[Method]) {
+    this(authenticator, serializer, javaMethods.asScala.toSet)
+  }
 
   override def routes(): stream.Stream[JMAPRoute] = Stream.of(
     JMAPRoute.builder
@@ -66,8 +79,8 @@ class JMAPApiRoutes @Inject() (@Named(InjectionKeys.RFC_8621) val authenticator:
 
   private def post(httpServerRequest: HttpServerRequest, httpServerResponse: HttpServerResponse): Mono[Void] =
     SMono(authenticator.authenticate(httpServerRequest))
-      .flatMap(_ => this.requestAsJsonStream(httpServerRequest)
-        .flatMap(requestObject => this.process(requestObject, httpServerResponse)))
+      .flatMap((mailboxSession: MailboxSession) => this.requestAsJsonStream(httpServerRequest)
+        .flatMap(requestObject => this.process(requestObject, httpServerResponse, mailboxSession)))
       .onErrorResume(throwable => handleError(throwable, httpServerResponse))
       .subscribeOn(Schedulers.elastic)
       .asJava()
@@ -87,10 +100,12 @@ class JMAPApiRoutes @Inject() (@Named(InjectionKeys.RFC_8621) val authenticator:
       case JsError(_) => SMono.raiseError(new IllegalArgumentException("Invalid RequestObject"))
     }
 
-  private def process(requestObject: RequestObject, httpServerResponse: HttpServerResponse): SMono[Void] =
+  private def process(requestObject: RequestObject,
+                      httpServerResponse: HttpServerResponse,
+                      mailboxSession: MailboxSession): SMono[Void] =
     requestObject
       .methodCalls
-      .map(this.processMethodWithMatchName)
+      .map(invocation => this.processMethodWithMatchName(invocation, mailboxSession))
       .foldLeft(SFlux.empty[Invocation]) { (flux: SFlux[Invocation], mono: SMono[Invocation]) => flux.mergeWith(mono) }
       .collectSeq()
       .flatMap((invocations: Seq[Invocation]) =>
@@ -103,13 +118,13 @@ class JMAPApiRoutes @Inject() (@Named(InjectionKeys.RFC_8621) val authenticator:
           ).`then`())
       )
 
-  private def processMethodWithMatchName(invocation: Invocation): SMono[Invocation] = invocation.methodName match {
-    case coreEcho.methodName => SMono.fromPublisher(coreEcho.process(invocation))
-    case _ => SMono.just(new Invocation(
-      MethodName("error"),
-      Arguments(Json.obj("type" -> "Not implemented")),
-      invocation.methodCallId))
-  }
+  private def processMethodWithMatchName(invocation: Invocation, mailboxSession: MailboxSession): SMono[Invocation] =
+    SMono.justOrEmpty(methodsByName.get(invocation.methodName))
+      .flatMap(method => SMono.fromPublisher(method.process(invocation, mailboxSession)))
+      .switchIfEmpty(SMono.just(new Invocation(
+        MethodName("error"),
+        Arguments(Json.obj("type" -> "Not implemented")),
+        invocation.methodCallId)))
 
   private def handleError(throwable: Throwable, httpServerResponse: HttpServerResponse): SMono[Void] = throwable match {
     case exception: IllegalArgumentException => SMono.fromPublisher(httpServerResponse.status(SC_BAD_REQUEST)
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
similarity index 84%
rename from server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoTest.scala
rename to server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
index 2d78e5f..583e832 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala
@@ -20,25 +20,28 @@ package org.apache.james.jmap.method
 
 import org.apache.james.jmap.json.Fixture.{invocation1, invocation2}
 import org.apache.james.jmap.model.Invocation
+import org.apache.james.mailbox.MailboxSession
+import org.mockito.Mockito.mock
 import org.scalatest.matchers.should.Matchers
 import org.scalatest.wordspec.AnyWordSpec
 import reactor.core.scala.publisher.SMono
 
-class CoreEchoTest extends AnyWordSpec with Matchers {
-  private val echoMethod: CoreEcho = new CoreEcho()
+class CoreEchoMethodTest extends AnyWordSpec with Matchers {
+  private val echoMethod: CoreEchoMethod = new CoreEchoMethod()
+  private val mockedSession: MailboxSession = mock(classOf[MailboxSession])
 
   "CoreEcho" should {
     "Process" should {
       "success and return the same with parameters as the invocation request" in {
         val expectedResponse: Invocation = invocation1
-        val dataResponse = SMono.fromPublisher(echoMethod.process(invocation1)).block()
+        val dataResponse = SMono.fromPublisher(echoMethod.process(invocation1, mockedSession)).block()
 
         dataResponse shouldBe expectedResponse
       }
 
       "success and not return anything else different than the original invocation" in {
         val wrongExpected: Invocation = invocation2
-        val dataResponse = SMono.fromPublisher(echoMethod.process(invocation1)).block()
+        val dataResponse = SMono.fromPublisher(echoMethod.process(invocation1, mockedSession)).block()
         
         dataResponse should not be(wrongExpected)
       }
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
index f23e835..37ffb9a 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
@@ -37,6 +37,7 @@ import org.apache.james.jmap.JMAPUrls.JMAP
 import org.apache.james.jmap._
 import org.apache.james.jmap.http.{Authenticator, BasicAuthenticationStrategy}
 import org.apache.james.jmap.json.Serializer
+import org.apache.james.jmap.method.{CoreEchoMethod, Method}
 import org.apache.james.jmap.routes.JMAPApiRoutesTest._
 import org.apache.james.mailbox.MailboxManager
 import org.apache.james.mailbox.extension.PreDeletionHook
@@ -67,7 +68,10 @@ object JMAPApiRoutesTest {
   private val mailboxManager: MailboxManager = MemoryMailboxManagerProvider.provideMailboxManager(empty_set)
   private val authenticationStrategy: BasicAuthenticationStrategy = new BasicAuthenticationStrategy(usersRepository, mailboxManager)
   private val AUTHENTICATOR: Authenticator = Authenticator.of(new RecordingMetricFactory, authenticationStrategy)
-  private val JMAP_API_ROUTE: JMAPApiRoutes = new JMAPApiRoutes(AUTHENTICATOR, SERIALIZER)
+
+  private val JMAP_METHODS: Set[Method] = Set(new CoreEchoMethod)
+
+  private val JMAP_API_ROUTE: JMAPApiRoutes = new JMAPApiRoutes(AUTHENTICATOR, SERIALIZER, JMAP_METHODS)
   private val ROUTES_HANDLER: ImmutableSet[JMAPRoutesHandler] = ImmutableSet.of(new JMAPRoutesHandler(Version.RFC8621, JMAP_API_ROUTE))
 
   private val userBase64String: String = Base64.getEncoder.encodeToString("user1:password".getBytes(StandardCharsets.UTF_8))


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