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 a667ad5f4db98e1c9fbe9c33d6c63667b6bddcec Author: Rémi Kowalski <[email protected]> AuthorDate: Thu Sep 24 13:58:47 2020 +0200 JAMES-3387 refactor extract InvocationWithContext --- .../apache/james/jmap/method/CoreEchoMethod.scala | 6 ++-- .../apache/james/jmap/method/EmailGetMethod.scala | 9 +++-- .../james/jmap/method/EmailQueryMethod.scala | 30 +++------------- .../james/jmap/method/MailboxGetMethod.scala | 15 ++++---- .../james/jmap/method/MailboxQueryMethod.scala | 10 +++--- .../james/jmap/method/MailboxSetMethod.scala | 10 +++--- .../org/apache/james/jmap/method/Method.scala | 37 ++++++++++++++------ .../jmap/method/VacationResponseGetMethod.scala | 17 +++++---- .../jmap/method/VacationResponseSetMethod.scala | 11 +++--- .../apache/james/jmap/routes/JMAPApiRoutes.scala | 40 ++++++++++------------ .../james/jmap/method/CoreEchoMethodTest.scala | 11 +++--- .../james/jmap/routes/JMAPApiRoutesTest.scala | 2 +- 12 files changed, 93 insertions(+), 105 deletions(-) diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala index c956a81..dfe2aa5 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEchoMethod.scala @@ -20,12 +20,10 @@ package org.apache.james.jmap.method import eu.timepit.refined.auto._ -import org.apache.james.jmap.http.SessionSupplier import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier import org.apache.james.jmap.model.DefaultCapabilities.CORE_CAPABILITY import org.apache.james.jmap.model.Invocation.MethodName -import org.apache.james.jmap.model.{Capabilities, Invocation} -import org.apache.james.jmap.routes.ProcessingContext +import org.apache.james.jmap.model.{Capabilities} import org.apache.james.mailbox.MailboxSession import org.reactivestreams.Publisher import reactor.core.scala.publisher.SMono @@ -33,7 +31,7 @@ import reactor.core.scala.publisher.SMono class CoreEchoMethod extends Method { override val methodName = MethodName("Core/echo") - override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = SMono.just((invocation, processingContext)) + override def process(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): Publisher[InvocationWithContext] = SMono.just(invocation) override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY) } \ No newline at end of file diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala index 0dbae7e..36d4e93 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailGetMethod.scala @@ -33,7 +33,6 @@ import org.apache.james.jmap.model.DefaultCapabilities.{CORE_CAPABILITY, MAIL_CA import org.apache.james.jmap.model.Invocation.{Arguments, MethodName} import org.apache.james.jmap.model.State.INSTANCE import org.apache.james.jmap.model.{AccountId, Capabilities, ErrorCode, Invocation, Properties} -import org.apache.james.jmap.routes.ProcessingContext import org.apache.james.mailbox.MailboxSession import org.apache.james.mailbox.model.MessageId import org.apache.james.metrics.api.MetricFactory @@ -87,11 +86,11 @@ class EmailGetMethod @Inject() (readerFactory: EmailViewReaderFactory, override val methodName = MethodName("Email/get") override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY) - override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: EmailGetRequest): SMono[(Invocation, ProcessingContext)] = { - computeResponseInvocation(request, invocation, mailboxSession).onErrorResume({ - case e: IllegalArgumentException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId)) + override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: EmailGetRequest): SMono[InvocationWithContext] = { + computeResponseInvocation(request, invocation.invocation, mailboxSession).onErrorResume({ + case e: IllegalArgumentException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.invocation.methodCallId)) case e: Throwable => SMono.raiseError(e) - }).map(invocationResult => (invocationResult, processingContext)) + }).map(invocationResult => InvocationWithContext(invocationResult, invocation.processingContext)) } override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[EmailGetRequest] = asEmailGetRequest(invocation.arguments) diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala index 4787cb3..5099c18 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailQueryMethod.scala @@ -23,17 +23,15 @@ import eu.timepit.refined.auto._ import javax.inject.Inject import org.apache.james.jmap.http.SessionSupplier import org.apache.james.jmap.json.{EmailQuerySerializer, ResponseSerializer} -import org.apache.james.jmap.mail.{Comparator, EmailQueryRequest, EmailQueryResponse, UnsupportedFilterException, UnsupportedRequestParameterException, UnsupportedSortException} +import org.apache.james.jmap.mail.{Comparator, EmailQueryRequest, EmailQueryResponse, UnsupportedRequestParameterException} import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier import org.apache.james.jmap.model.DefaultCapabilities.{CORE_CAPABILITY, MAIL_CAPABILITY} import org.apache.james.jmap.model.Invocation.{Arguments, MethodName} import org.apache.james.jmap.model.Limit.Limit import org.apache.james.jmap.model.Position.Position -import org.apache.james.jmap.model.{CanCalculateChanges, Capabilities, ErrorCode, Invocation, Limit, Position, QueryState} -import org.apache.james.jmap.routes.ProcessingContext +import org.apache.james.jmap.model.{CanCalculateChanges, Capabilities, Invocation, Limit, Position, QueryState} import org.apache.james.jmap.utils.search.MailboxFilter import org.apache.james.jmap.utils.search.MailboxFilter.QueryFilter -import org.apache.james.mailbox.exception.MailboxNotFoundException import org.apache.james.mailbox.model.MultimailboxesSearchQuery import org.apache.james.mailbox.{MailboxManager, MailboxSession} import org.apache.james.metrics.api.MetricFactory @@ -49,29 +47,11 @@ class EmailQueryMethod @Inject() (serializer: EmailQuerySerializer, override val methodName: MethodName = MethodName("Email/query") override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY) - override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: EmailQueryRequest): SMono[(Invocation, ProcessingContext)] = { - processRequest(mailboxSession, invocation, request, capabilities) - .onErrorResume { - case e: UnsupportedRequestParameterException => SMono.just(Invocation.error( - ErrorCode.InvalidArguments, - s"The following parameter ${e.unsupportedParam} is syntactically valid, but is not supported by the server.", - invocation.methodCallId)) - case e: UnsupportedSortException => SMono.just(Invocation.error( - ErrorCode.UnsupportedSort, - s"The sort ${e.unsupportedSort} is syntactically valid, but it includes a property the server does not support sorting on or a collation method it does not recognise.", - invocation.methodCallId)) - case e: UnsupportedFilterException => SMono.just(Invocation.error( - ErrorCode.UnsupportedFilter, - s"The filter ${e.unsupportedFilter} is syntactically valid, but the server cannot process it. If the filter was the result of a user’s search input, the client SHOULD suggest that the user simplify their search.", - invocation.methodCallId)) - case e: IllegalArgumentException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId)) - case e: MailboxNotFoundException => SMono.just(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId)) - case e: Throwable => SMono.raiseError(e) - } - .map(invocationResult => (invocationResult, processingContext)) + override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: EmailQueryRequest): SMono[InvocationWithContext] = { + processRequest(mailboxSession, invocation.invocation, request, capabilities) + .map(invocationResult => InvocationWithContext(invocationResult, invocation.processingContext)) } - private def processRequest(mailboxSession: MailboxSession, invocation: Invocation, request: EmailQueryRequest, diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala index 6e660c8..d747717 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala @@ -74,28 +74,27 @@ class MailboxGetMethod @Inject() (serializer: MailboxSerializer, } override def process(capabilities: Set[CapabilityIdentifier], - invocation: Invocation, - mailboxSession: MailboxSession, - processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = { + invocation: InvocationWithContext, + mailboxSession: MailboxSession): Publisher[InvocationWithContext] = { metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value, - asMailboxGetRequest(invocation.arguments) + asMailboxGetRequest(invocation.invocation.arguments) .flatMap(mailboxGetRequest => { val requestedProperties: Properties = mailboxGetRequest.properties.getOrElse(Mailbox.allProperties) requestedProperties -- Mailbox.allProperties match { - case invalidProperties if invalidProperties.isEmpty() => getMailboxes(capabilities, mailboxGetRequest, processingContext, mailboxSession) + case invalidProperties if invalidProperties.isEmpty() => getMailboxes(capabilities, mailboxGetRequest, invocation.processingContext, mailboxSession) .reduce(MailboxGetResults.empty(), MailboxGetResults.merge) .map(mailboxes => mailboxes.asResponse(mailboxGetRequest.accountId)) .map(mailboxGetResponse => Invocation( methodName = methodName, arguments = Arguments(serializer.serialize(mailboxGetResponse, requestedProperties, capabilities).as[JsObject]), - methodCallId = invocation.methodCallId)) + methodCallId = invocation.invocation.methodCallId)) case invalidProperties: Properties => SMono.just(Invocation.error(errorCode = ErrorCode.InvalidArguments, description = s"The following properties [${invalidProperties.format()}] do not exist.", - methodCallId = invocation.methodCallId)) + methodCallId = invocation.invocation.methodCallId)) } }) - .map((_, processingContext))) + .map(InvocationWithContext(_, invocation.processingContext))) } private def asMailboxGetRequest(arguments: Arguments): SMono[MailboxGetRequest] = { diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala index 268dc1d..ea0200b 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxQueryMethod.scala @@ -41,19 +41,19 @@ class MailboxQueryMethod @Inject()(systemMailboxesProvider: SystemMailboxesProvi override val methodName = MethodName("Mailbox/query") override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY) - override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = + override def process(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): Publisher[InvocationWithContext] = metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value, - asMailboxQueryRequest(invocation.arguments) - .flatMap(processRequest(mailboxSession, invocation, _)) + asMailboxQueryRequest(invocation.invocation.arguments) + .flatMap(processRequest(mailboxSession, invocation.invocation, _)) .onErrorResume { case e: IllegalArgumentException => SMono.just( Invocation.error( errorCode = ErrorCode.InvalidArguments, description = e.getMessage, - methodCallId = invocation.methodCallId)) + methodCallId = invocation.invocation.methodCallId)) case e: Throwable => SMono.raiseError(e) } - .map(invocationResult => (invocationResult, processingContext))) + .map(invocationResult => InvocationWithContext(invocationResult, invocation.processingContext))) private def processRequest(mailboxSession: MailboxSession, invocation: Invocation, request: MailboxQueryRequest): SMono[Invocation] = { SFlux.fromPublisher(systemMailboxesProvider.getMailboxByRole(request.filter.role, mailboxSession.getUser)) 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 dc772c5..df6b77c 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 @@ -153,11 +153,11 @@ class MailboxSetMethod @Inject()(serializer: MailboxSerializer, override val methodName: MethodName = MethodName("Mailbox/set") override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY) - override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: MailboxSetRequest): SMono[(Invocation, ProcessingContext)] = for { - creationResultsWithUpdatedProcessingContext <- createMailboxes(mailboxSession, request, processingContext) - deletionResults <- deleteMailboxes(mailboxSession, request, processingContext) - updateResults <- updateMailboxes(mailboxSession, request, processingContext, capabilities) - } yield (createResponse(capabilities, invocation, request, creationResultsWithUpdatedProcessingContext._1, deletionResults, updateResults), creationResultsWithUpdatedProcessingContext._2) + override def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: MailboxSetRequest): SMono[InvocationWithContext] = for { + creationResultsWithUpdatedProcessingContext <- createMailboxes(mailboxSession, request, invocation.processingContext) + deletionResults <- deleteMailboxes(mailboxSession, request, invocation.processingContext) + updateResults <- updateMailboxes(mailboxSession, request, invocation.processingContext, capabilities) + } yield InvocationWithContext(createResponse(capabilities, invocation.invocation, request, creationResultsWithUpdatedProcessingContext._1, deletionResults, updateResults), creationResultsWithUpdatedProcessingContext._2) override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[MailboxSetRequest] = asMailboxSetRequest(invocation.arguments) 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 f4a40a5..5ee14cb 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 @@ -20,6 +20,7 @@ package org.apache.james.jmap.method import org.apache.james.jmap.http.SessionSupplier +import org.apache.james.jmap.mail.{UnsupportedFilterException, UnsupportedRequestParameterException, UnsupportedSortException} import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier import org.apache.james.jmap.model.Invocation.MethodName import org.apache.james.jmap.model.{AccountId, Capabilities, ErrorCode, Invocation, Session} @@ -30,6 +31,8 @@ import org.apache.james.metrics.api.MetricFactory import org.reactivestreams.Publisher import reactor.core.scala.publisher.SMono +case class InvocationWithContext(invocation: Invocation, processingContext: ProcessingContext) + trait Method { val JMAP_RFC8621_PREFIX: String = "JMAP-RFC8621-" @@ -37,7 +40,7 @@ trait Method { val requiredCapabilities: Capabilities - def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] + def process(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): Publisher[InvocationWithContext] } trait WithAccountId { @@ -47,18 +50,32 @@ trait MethodRequiringAccountId[REQUEST <: WithAccountId] extends Method { def metricFactory: MetricFactory def sessionSupplier: SessionSupplier - override def process(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = { + override def process(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): Publisher[InvocationWithContext] = { val result = (for { - request <- getRequest(mailboxSession, invocation) - response <- validateAccountId(request.accountId, mailboxSession, sessionSupplier, invocation).flatMap{ - case Right(_) => doProcess(capabilities, invocation, mailboxSession, processingContext, request) - case Left(invocation) => SMono.just((invocation, processingContext)) + request <- getRequest(mailboxSession, invocation.invocation) + response <- validateAccountId(request.accountId, mailboxSession, sessionSupplier, invocation.invocation).flatMap{ + case Right(_) => doProcess(capabilities, invocation, mailboxSession, request) + case Left(errorInvocation) => SMono.just(InvocationWithContext(errorInvocation, invocation.processingContext)) } } yield response) .onErrorResume { - case e: IllegalArgumentException => SMono.just((Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.methodCallId), processingContext)) - case e: Throwable => SMono.raiseError(e) - } + case e: UnsupportedRequestParameterException => SMono.just(InvocationWithContext(Invocation.error( + ErrorCode.InvalidArguments, + s"The following parameter ${e.unsupportedParam} is syntactically valid, but is not supported by the server.", + invocation.invocation.methodCallId), invocation.processingContext)) + case e: UnsupportedSortException => SMono.just(InvocationWithContext(Invocation.error( + ErrorCode.UnsupportedSort, + s"The sort ${e.unsupportedSort} is syntactically valid, but it includes a property the server does not support sorting on or a collation method it does not recognise.", + invocation.invocation.methodCallId), invocation.processingContext)) + case e: UnsupportedFilterException => SMono.just(InvocationWithContext(Invocation.error( + ErrorCode.UnsupportedFilter, + s"The filter ${e.unsupportedFilter} is syntactically valid, but the server cannot process it. If the filter was the result of a user’s search input, the client SHOULD suggest that the user simplify their search.", + invocation.invocation.methodCallId), invocation.processingContext)) + case e: IllegalArgumentException => SMono.just(InvocationWithContext(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.invocation.methodCallId), invocation.processingContext)) + case e: MailboxNotFoundException => SMono.just(InvocationWithContext(Invocation.error(ErrorCode.InvalidArguments, e.getMessage, invocation.invocation.methodCallId), invocation.processingContext)) + case e: Throwable => SMono.raiseError(e) + } + metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value, result) } @@ -70,7 +87,7 @@ trait MethodRequiringAccountId[REQUEST <: WithAccountId] extends Method { .switchIfEmpty(SMono.just(Left[Invocation, Session](Invocation.error(ErrorCode.AccountNotFound, invocation.methodCallId)))) } - def doProcess(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext, request: REQUEST): SMono[(Invocation, ProcessingContext)] + def doProcess(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession, request: REQUEST): SMono[InvocationWithContext] def getRequest(mailboxSession: MailboxSession, invocation: Invocation): SMono[REQUEST] } diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala index a3c3e8b..a9a3a7f 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseGetMethod.scala @@ -64,29 +64,28 @@ class VacationResponseGetMethod @Inject() (vacationRepository: VacationRepositor override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY, VACATION_RESPONSE_CAPABILITY) override def process(capabilities: Set[CapabilityIdentifier], - invocation: Invocation, - mailboxSession: MailboxSession, - processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = { + invocation: InvocationWithContext, + mailboxSession: MailboxSession): Publisher[InvocationWithContext] = { metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value, - asVacationResponseGetRequest(invocation.arguments) - .fold(e => handleRequestValidationErrors(e, invocation.methodCallId), + asVacationResponseGetRequest(invocation.invocation.arguments) + .fold(e => handleRequestValidationErrors(e, invocation.invocation.methodCallId), vacationResponseGetRequest => { val requestedProperties: Properties = vacationResponseGetRequest.properties.getOrElse(VacationResponse.allProperties) requestedProperties -- VacationResponse.allProperties match { - case invalidProperties if invalidProperties.isEmpty() => getVacationResponse(vacationResponseGetRequest, processingContext, mailboxSession) + case invalidProperties if invalidProperties.isEmpty() => getVacationResponse(vacationResponseGetRequest, invocation.processingContext, mailboxSession) .reduce(VacationResponseGetResult.empty, VacationResponseGetResult.merge) .map(vacationResult => vacationResult.asResponse(vacationResponseGetRequest.accountId)) .map(vacationResponseGetResponse => Invocation( methodName = methodName, arguments = Arguments(VacationSerializer.serialize(vacationResponseGetResponse, requestedProperties).as[JsObject]), - methodCallId = invocation.methodCallId)) + methodCallId = invocation.invocation.methodCallId)) case invalidProperties: Properties => SMono.just(Invocation.error(errorCode = ErrorCode.InvalidArguments, description = s"The following properties [${invalidProperties.format}] do not exist.", - methodCallId = invocation.methodCallId)) + methodCallId = invocation.invocation.methodCallId)) } }) - .map((_, processingContext))) + .map(InvocationWithContext(_, invocation.processingContext))) } private def asVacationResponseGetRequest(arguments: Arguments): Either[IllegalArgumentException, VacationResponseGetRequest] = diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala index 4b24625..c3febb9 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala @@ -80,14 +80,13 @@ class VacationResponseSetMethod @Inject() (vacationRepository: VacationRepositor override val requiredCapabilities: Capabilities = Capabilities(CORE_CAPABILITY, MAIL_CAPABILITY, VACATION_RESPONSE_CAPABILITY) override def process(capabilities: Set[CapabilityIdentifier], - invocation: Invocation, - mailboxSession: MailboxSession, - processingContext: ProcessingContext): Publisher[(Invocation, ProcessingContext)] = { + invocation: InvocationWithContext, + mailboxSession: MailboxSession): Publisher[InvocationWithContext] = { metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value, - asVacationResponseSetRequest(invocation.arguments) + asVacationResponseSetRequest(invocation.invocation.arguments) .flatMap(vacationResponseSetRequest => update(mailboxSession, vacationResponseSetRequest) - .map(updateResult => createResponse(invocation, vacationResponseSetRequest, updateResult))) - .map((_, processingContext))) + .map(updateResult => createResponse(invocation.invocation, vacationResponseSetRequest, updateResult))) + .map(InvocationWithContext(_, invocation.processingContext))) } private def update(mailboxSession: MailboxSession, vacationResponseSetRequest: VacationResponseSetRequest): SMono[VacationResponseUpdateResults] = { 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 ab870e1..3ddf463 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,7 +35,7 @@ import org.apache.james.jmap.exceptions.UnauthorizedException import org.apache.james.jmap.http.rfc8621.InjectionKeys import org.apache.james.jmap.http.{Authenticator, MailboxesProvisioner, SessionSupplier, UserProvisioning} import org.apache.james.jmap.json.ResponseSerializer -import org.apache.james.jmap.method.Method +import org.apache.james.jmap.method.{InvocationWithContext, Method} import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier import org.apache.james.jmap.model.Invocation.MethodName import org.apache.james.jmap.model.ProblemDetails.{notJSONProblem, notRequestProblem, unknownCapabilityProblem} @@ -120,25 +120,25 @@ class JMAPApiRoutes (val authenticator: Authenticator, SMono.raiseError(UnsupportedCapabilitiesException(unsupportedCapabilities)) } else { processSequentiallyAndUpdateContext(requestObject, mailboxSession, processingContext, capabilities) - .flatMap((invocations : Seq[(Invocation, ProcessingContext)]) => + .flatMap((invocations : Seq[InvocationWithContext]) => SMono.fromPublisher(httpServerResponse.status(OK) .header(CONTENT_TYPE, JSON_CONTENT_TYPE) .sendString( SMono.fromCallable(() => - ResponseSerializer.serialize(ResponseObject(ResponseObject.SESSION_STATE, invocations.map(_._1))).toString), + ResponseSerializer.serialize(ResponseObject(ResponseObject.SESSION_STATE, invocations.map(_.invocation))).toString), StandardCharsets.UTF_8) .`then`()) ) } } - private def processSequentiallyAndUpdateContext(requestObject: RequestObject, mailboxSession: MailboxSession, processingContext: ProcessingContext, capabilities: Set[CapabilityIdentifier]): SMono[Seq[(Invocation, ProcessingContext)]] = { + private def processSequentiallyAndUpdateContext(requestObject: RequestObject, mailboxSession: MailboxSession, processingContext: ProcessingContext, capabilities: Set[CapabilityIdentifier]): SMono[Seq[(InvocationWithContext)]] = { SFlux.fromIterable(requestObject.methodCalls) - .foldLeft(List[SMono[(Invocation, ProcessingContext)]]())((acc, elem) => { + .foldLeft(List[SMono[InvocationWithContext]]())((acc, elem) => { val lastProcessingContext: SMono[ProcessingContext] = acc.headOption - .map(last => last.map(_._2)) + .map(last => last.map(_.processingContext)) .getOrElse(SMono.just(processingContext)) - val invocation: SMono[(Invocation, ProcessingContext)] = lastProcessingContext.flatMap(context => process(capabilities, mailboxSession, context, elem)) + val invocation: SMono[InvocationWithContext] = lastProcessingContext.flatMap(context => process(capabilities, mailboxSession, InvocationWithContext(elem, context))) invocation.cache() :: acc }) .map(_.reverse) @@ -147,29 +147,27 @@ class JMAPApiRoutes (val authenticator: Authenticator, .collectSeq()) } - private def process(capabilities: Set[CapabilityIdentifier], mailboxSession: MailboxSession, processingContext: ProcessingContext, invocation: Invocation) : SMono[(Invocation, ProcessingContext)] = { + private def process(capabilities: Set[CapabilityIdentifier], mailboxSession: MailboxSession, invocation: InvocationWithContext) : SMono[InvocationWithContext] = { SMono.defer(() => { - processingContext.resolveBackReferences(invocation) match { - case Left(e) => SMono.just((Invocation.error( + invocation.processingContext.resolveBackReferences(invocation.invocation) match { + case Left(e) => SMono.just(InvocationWithContext(Invocation.error( errorCode = ErrorCode.InvalidResultReference, description = s"Failed resolving back-reference: ${e.message}", - methodCallId = invocation.methodCallId), processingContext)) - case Right(resolvedInvocation) => processMethodWithMatchName(capabilities, resolvedInvocation, mailboxSession, processingContext) - .map { - case (invocation: Invocation, updatedProcessingContext: ProcessingContext) => (invocation, updatedProcessingContext.recordInvocation(invocation)) - } + methodCallId = invocation.invocation.methodCallId), invocation.processingContext)) + case Right(resolvedInvocation) => processMethodWithMatchName(capabilities, InvocationWithContext(resolvedInvocation, invocation.processingContext), mailboxSession) + .map((invocationWithContext: InvocationWithContext) => InvocationWithContext(invocationWithContext.invocation, invocationWithContext.processingContext.recordInvocation(invocationWithContext.invocation))) } }) } - private def processMethodWithMatchName(capabilities: Set[CapabilityIdentifier], invocation: Invocation, mailboxSession: MailboxSession, processingContext: ProcessingContext): SMono[(Invocation, ProcessingContext)] = - SMono.justOrEmpty(methodsByName.get(invocation.methodName)) + private def processMethodWithMatchName(capabilities: Set[CapabilityIdentifier], invocation: InvocationWithContext, mailboxSession: MailboxSession): SMono[InvocationWithContext] = + SMono.justOrEmpty(methodsByName.get(invocation.invocation.methodName)) .flatMap(method => validateCapabilities(capabilities, method.requiredCapabilities) - .fold(e => SMono.just((Invocation.error(ErrorCode.UnknownMethod, e.description, invocation.methodCallId), processingContext)), - _ => SMono.fromPublisher(method.process(capabilities, invocation, mailboxSession, processingContext)) + .fold(e => SMono.just(InvocationWithContext(Invocation.error(ErrorCode.UnknownMethod, e.description, invocation.invocation.methodCallId), invocation.processingContext)), + _ => SMono.fromPublisher(method.process(capabilities, invocation, mailboxSession)) )) - .onErrorResume(throwable => SMono.just((Invocation.error(ErrorCode.ServerFail, throwable.getMessage, invocation.methodCallId), processingContext))) - .switchIfEmpty(SMono.just((Invocation.error(ErrorCode.UnknownMethod, invocation.methodCallId), processingContext))) + .onErrorResume(throwable => SMono.just(InvocationWithContext(Invocation.error(ErrorCode.ServerFail, throwable.getMessage, invocation.invocation.methodCallId), invocation.processingContext))) + .switchIfEmpty(SMono.just(InvocationWithContext(Invocation.error(ErrorCode.UnknownMethod, invocation.invocation.methodCallId), invocation.processingContext))) private def validateCapabilities(capabilities: Set[CapabilityIdentifier], requiredCapabilities: Capabilities): Either[MissingCapabilityException, Unit] = { val missingCapabilities = requiredCapabilities.ids -- capabilities diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala index 77da9e6..18a2624 100644 --- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala +++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoMethodTest.scala @@ -18,10 +18,9 @@ * ***************************************************************/ package org.apache.james.jmap.method -import org.apache.james.jmap.http.SessionSupplier import org.apache.james.jmap.json.Fixture.{invocation1, invocation2} import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier -import org.apache.james.jmap.model.{CapabilityIdentifier, Invocation, JmapRfc8621Configuration} +import org.apache.james.jmap.model.{CapabilityIdentifier, Invocation} import org.apache.james.jmap.routes.ProcessingContext import org.apache.james.mailbox.MailboxSession import org.mockito.Mockito.mock @@ -37,15 +36,15 @@ class CoreEchoMethodTest extends AnyWordSpec with Matchers { "CoreEcho" should { "Process" should { "success and return the same with parameters as the invocation request" in { - val expectedResponse: (Invocation, ProcessingContext) = (invocation1, ProcessingContext(Map.empty, Map.empty)) - val dataResponse = SMono.fromPublisher(echoMethod.process(capabilities, invocation1, mockedSession, ProcessingContext(Map.empty, Map.empty))).block() + val expectedResponse: InvocationWithContext = InvocationWithContext(invocation1, ProcessingContext(Map.empty, Map.empty)) + val dataResponse = SMono.fromPublisher(echoMethod.process(capabilities, InvocationWithContext(invocation1,ProcessingContext(Map.empty, Map.empty)), mockedSession)).block() dataResponse shouldBe expectedResponse } "success and not return anything else different than the original invocation" in { - val wrongExpected: (Invocation, ProcessingContext) = (invocation2, ProcessingContext(Map.empty, Map.empty)) - val dataResponse = SMono.fromPublisher(echoMethod.process(capabilities, invocation1, mockedSession, ProcessingContext(Map.empty, Map.empty))).block() + val wrongExpected: InvocationWithContext = InvocationWithContext(invocation2, ProcessingContext(Map.empty, Map.empty)) + val dataResponse = SMono.fromPublisher(echoMethod.process(capabilities, InvocationWithContext(invocation1, ProcessingContext(Map.empty, Map.empty)), 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 7e5298f..b9f23bc 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 @@ -437,7 +437,7 @@ class JMAPApiRoutesTest extends AnyFlatSpec with BeforeAndAfter with Matchers { doThrow(new RuntimeException("Unexpected Exception occur, the others method may proceed normally")) .doCallRealMethod() .when(mockCoreEchoMethod) - .process(any[Set[CapabilityIdentifier]], any(), any(), any()) + .process(any[Set[CapabilityIdentifier]], any(), any()) when(mockCoreEchoMethod.methodName).thenReturn(MethodName("Core/echo")) when(mockCoreEchoMethod.requiredCapabilities).thenReturn(Capabilities(CORE_CAPABILITY)) --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
