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 <[email protected]> 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: [email protected] For additional commands, e-mail: [email protected]
