chibenwa commented on a change in pull request #391:
URL: https://github.com/apache/james-project/pull/391#discussion_r620953442
##########
File path:
server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedAuthenticationTest.java
##########
@@ -51,7 +52,8 @@
.extension(new RabbitMQExtension())
.extension(new AwsS3BlobStoreExtension())
.server(configuration ->
CassandraRabbitMQJamesServerMain.createServer(configuration)
- .overrideWith(new TestJMAPServerModule()))
+ .overrideWith(new TestJMAPServerModule())
+ .overrideWith(new TypeNameModule()))
Review comment:
Why do we need to depend on a module of an unrelated contract (here and
in other places?)
##########
File path:
server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/CustomMethodContract.scala
##########
@@ -179,6 +250,80 @@ trait CustomMethodContract {
.build
}
+ @Test
+ def shouldSupportCustomTypeNameWithIntStateFromString(server:
GuiceJamesServer): Unit = {
Review comment:
I cannot see the difference between
shouldSupportCustomTypeNameWithIntStateFromString and
shouldSupportCustomTypeNameWithIntStateFromInt...
##########
File path:
server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxSetMethodContract.scala
##########
@@ -19,9 +19,6 @@
package org.apache.james.jmap.rfc8621.contract
-import java.nio.charset.StandardCharsets
Review comment:
Please do not change the import order
##########
File path:
server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/CustomMethodContract.scala
##########
@@ -154,6 +174,31 @@ class CustomMethodModule extends AbstractModule {
Multibinder.newSetBinder(binder(), classOf[Method])
.addBinding()
.to(classOf[CustomMethod])
+ Multibinder.newSetBinder(binder(), classOf[TypeName])
+ .addBinding()
+ .toInstance(CustomTypeName)
+ Multibinder.newSetBinder(binder(), classOf[GuiceProbe])
+ .addBinding()
+ .to(classOf[JmapEventBusProbe])
+ }
+}
+
+class TypeNameModule extends AbstractModule {
Review comment:
This TypeName module should be part of `RFC8621MethodsModule` ? (At
least the generic parts?)
##########
File path:
server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSetMethodContract.scala
##########
@@ -18,27 +18,19 @@
****************************************************************/
package org.apache.james.jmap.rfc8621.contract
-import java.io.ByteArrayInputStream
Review comment:
Please do not change the import order
##########
File path:
server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/WebSocketContract.scala
##########
@@ -18,14 +18,11 @@
****************************************************************/
package org.apache.james.jmap.rfc8621.contract
-import java.net.{ProtocolException, URI}
Review comment:
Please do not change the import order
##########
File path:
server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailSubmissionSetMethodContract.scala
##########
@@ -19,9 +19,6 @@
package org.apache.james.jmap.rfc8621.contract
-import java.nio.charset.StandardCharsets
Review comment:
Please do not change the import order
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/StateChange.scala
##########
@@ -80,29 +100,21 @@ case class TypeState(changes: Map[TypeName, State]) {
case class StateChangeEvent(eventId: EventId,
username: Username,
- vacationResponseState: Option[State],
- mailboxState: Option[State],
- emailState: Option[State],
- emailDeliveryState: Option[State]) extends Event {
- def asStateChange: StateChange =
+ map: Map[TypeName, State]) extends Event {
+ def asStateChange: StateChange = {
StateChange(Map(AccountId.from(username).fold(
failure => throw new IllegalArgumentException(failure),
success => success) ->
- TypeState(
- VacationResponseTypeName.asMap(vacationResponseState) ++
- MailboxTypeName.asMap(mailboxState) ++
- EmailDeliveryTypeName.asMap(emailDeliveryState) ++
- EmailTypeName.asMap(emailState))),
+ TypeState(map)),
PushState.fromOption(
- mailboxState.map(state => JavaState.of(state.value)),
- emailState.map(state => JavaState.of(state.value))))
+ map.find(element =>
element._1.asString().equals("Mailbox")).map(element => element._2),
Review comment:
Use :
```
case class StateChangeEvent {
def getState(typeName: TypeName): Option[State] = ???
}
```
Here too...
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/TypeStateFactory.scala
##########
@@ -0,0 +1,15 @@
+package org.apache.james.jmap.change
+
+import javax.inject.Inject
+import scala.jdk.CollectionConverters._
+
+case class TypeStateFactory @Inject()(setTypeName: java.util.Set[TypeName]) {
+ val all: scala.collection.mutable.Set[TypeName] = setTypeName.asScala
+
+ def parse(string: String): Either[IllegalArgumentException, TypeName] =
+ all.flatMap(typeName => typeName.parse(string))
Review comment:
```suggestion
all.flatMap(_.parse(string))
```
##########
File path:
server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/VacationResponseGetMethodContract.scala
##########
@@ -19,8 +19,6 @@
package org.apache.james.jmap.rfc8621.contract
-import java.time.ZonedDateTime
Review comment:
Please do not change the import order
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/VacationResponseSetMethod.scala
##########
@@ -88,11 +88,8 @@ class VacationResponseSetMethod
@Inject()(@Named(InjectionKeys.JMAP) eventBus: E
.map(updateResult => createResponse(invocation.invocation, request,
updateResult))
.flatMap(next => {
val event = StateChangeEvent(eventId = EventId.random(),
- mailboxState = None,
- emailState = None,
- emailDeliveryState = None,
username = mailboxSession.getUser,
- vacationResponseState = Some(State(UUID.randomUUID())))
+ map = Map(VacationResponseTypeName -> UuidState(UUID.randomUUID())))
Review comment:
Shouldn't we have `UuidState.generate()` ?
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/JmapEventSerializer.scala
##########
@@ -42,10 +41,10 @@ object StateChangeEventDTO {
getType = classOf[StateChangeEvent].getCanonicalName,
getEventId = event.eventId.getId.toString,
getUsername = event.username.asString(),
- getMailboxState = event.mailboxState.map(_.value).map(_.toString).toJava,
- getEmailState = event.emailState.map(_.value).map(_.toString).toJava,
- getVacationResponseState =
event.vacationResponseState.map(_.value).map(_.toString).toJava,
- getEmailDeliveryState =
event.emailDeliveryState.map(_.value).map(_.toString).toJava)
+ getMailboxState = event.map.find(element =>
element._1.asString().equals("Mailbox")).map(element =>
element._2.serialize).toJava,
Review comment:
How about adding the method:
```
case class StateChangeEvent {
def getState(typeName: TypeName): Option[State] = ???
}
```
##########
File path:
server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/TypeStateFactoryTest.scala
##########
@@ -0,0 +1,81 @@
+package org.apache.james.jmap.change
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.jupiter.api.Test
+
+import scala.jdk.CollectionConverters._
+
+class TypeStateFactoryTest {
+ val ALL: Set[TypeName] = Set(EmailTypeName, MailboxTypeName, ThreadTypeName,
IdentityTypeName, EmailSubmissionTypeName, EmailDeliveryTypeName)
+ val factory: TypeStateFactory = TypeStateFactory(ALL.asJava)
+
+ @Test
+ def parseEmailTypeNameStringShouldReturnRightEmailTypeName(): Unit = {
+ assertThat(factory.parse("Email")).isEqualTo(Right(EmailTypeName))
+ }
+
+ @Test
+ def parseMailboxTypeNameStringShouldReturnRightMailboxTypeName(): Unit = {
+ assertThat(factory.parse("Mailbox")).isEqualTo(Right(MailboxTypeName))
+ }
+
+ @Test
+ def parseThreadTypeNameStringShouldReturnRightThreadTypeName(): Unit = {
+ assertThat(factory.parse("Thread")).isEqualTo(Right(ThreadTypeName))
+ }
+
+ @Test
+ def parseIdentityTypeNameStringShouldReturnRightIdentityTypeName(): Unit = {
+ assertThat(factory.parse("Identity")).isEqualTo(Right(IdentityTypeName))
+ }
+
+ @Test
+ def
parseEmailSubmissionTypeNameStringShouldReturnRightEmailSubmissionTypeName():
Unit = {
+
assertThat(factory.parse("EmailSubmission")).isEqualTo(Right(EmailSubmissionTypeName))
+ }
+
+ @Test
+ def
parseEmailDeliveryTypeNameStringShouldReturnRightEmailDeliveryTypeName(): Unit
= {
+
assertThat(factory.parse("EmailDelivery")).isEqualTo(Right(EmailDeliveryTypeName))
+ }
+
+ @Test
+ def parseWrongTypeNameStringShouldReturnLeftIllegalArgumentException(): Unit
= {
+ assertThat(factory.parse("email").fold(
Review comment:
You can do asserts `.isInstanceOf(classOf[Left])` then you can drop all
the calls to .fold
Also please consider using SoftAssertions....
##########
File path:
server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/StateChangeListenerTest.scala
##########
@@ -31,25 +30,23 @@ import reactor.core.scala.publisher.SMono
import reactor.core.scheduler.Schedulers
class StateChangeListenerTest {
- private val mailboxState =
State.fromStringUnchecked("2f9f1b12-b35a-43e6-9af2-0106fb53a943")
- private val emailState =
State.fromStringUnchecked("2d9f1b12-b35a-43e6-9af2-0106fb53a943")
+ private val mailboxState =
UuidState.fromStringUnchecked("2f9f1b12-b35a-43e6-9af2-0106fb53a943")
+ private val emailState =
UuidState.fromStringUnchecked("2d9f1b12-b35a-43e6-9af2-0106fb53a943")
private val eventId = EventId.of("6e0dd59d-660e-4d9b-b22f-0354479f47b4")
@Test
def reactiveEventShouldSendAnOutboundMessage(): Unit = {
val sink: Sinks.Many[OutboundMessage] =
Sinks.many().unicast().onBackpressureBuffer()
val event = StateChangeEvent(eventId = eventId,
username = Username.of("bob"),
- mailboxState = Some(mailboxState),
- emailState = Some(emailState),
- vacationResponseState = None,
- emailDeliveryState = None)
+ map = (Map(MailboxTypeName -> mailboxState) ++
+ Map(EmailTypeName -> emailState)).toMap)
Review comment:
Single call to Map
##########
File path:
server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/StateChangeListenerTest.scala
##########
@@ -61,16 +58,14 @@ class StateChangeListenerTest {
val sink: Sinks.Many[OutboundMessage] =
Sinks.many().unicast().onBackpressureBuffer()
val event = StateChangeEvent(eventId = eventId,
username = Username.of("bob"),
- mailboxState = Some(mailboxState),
- emailState = Some(emailState),
- vacationResponseState = None,
- emailDeliveryState = None)
+ map = (Map(MailboxTypeName -> mailboxState) ++
+ Map(EmailTypeName -> emailState)).toMap)
Review comment:
Single call to Map
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/WebSocketRoutes.scala
##########
@@ -50,6 +45,11 @@ import reactor.core.scheduler.Schedulers
import reactor.netty.http.server.{HttpServerRequest, HttpServerResponse}
import reactor.netty.http.websocket.{WebsocketInbound, WebsocketOutbound}
+import java.nio.charset.StandardCharsets
Review comment:
Order import order
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/TypeStateFactory.scala
##########
@@ -0,0 +1,15 @@
+package org.apache.james.jmap.change
+
+import javax.inject.Inject
+import scala.jdk.CollectionConverters._
+
+case class TypeStateFactory @Inject()(setTypeName: java.util.Set[TypeName]) {
+ val all: scala.collection.mutable.Set[TypeName] = setTypeName.asScala
+
+ def parse(string: String): Either[IllegalArgumentException, TypeName] =
+ all.flatMap(typeName => typeName.parse(string))
+ .headOption
+ .map(typeName => Right(typeName))
Review comment:
```suggestion
.map(Right(_))
```
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/EventSourceRoutes.scala
##########
@@ -49,12 +44,16 @@ import reactor.core.scala.publisher.{SFlux, SMono}
import reactor.core.scheduler.Schedulers
import reactor.netty.http.server.{HttpServerRequest, HttpServerResponse}
+import java.nio.charset.StandardCharsets
Review comment:
Order import
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailGetSerializer.scala
##########
@@ -22,9 +22,9 @@ package org.apache.james.jmap.json
import eu.timepit.refined
import org.apache.james.jmap.api.model.Preview
import org.apache.james.jmap.core.Id.IdConstraint
-import org.apache.james.jmap.core.{Properties, State}
+import org.apache.james.jmap.core.{Properties, UuidState}
import org.apache.james.jmap.mail.Email.Size
-import org.apache.james.jmap.mail.{AddressesHeaderValue, BlobId, Charset,
DateHeaderValue, Disposition, EmailAddress, EmailAddressGroup, EmailBody,
EmailBodyMetadata, EmailBodyPart, EmailBodyValue, EmailChangesRequest,
EmailChangesResponse, EmailFastView, EmailFullView, EmailGetRequest,
EmailGetResponse, EmailHeader, EmailHeaderName, EmailHeaderValue,
EmailHeaderView, EmailHeaders, EmailIds, EmailMetadata, EmailMetadataView,
EmailNotFound, EmailView, EmailerName, FetchAllBodyValues, FetchHTMLBodyValues,
FetchTextBodyValues, GroupName, GroupedAddressesHeaderValue, HasAttachment,
HeaderMessageId, HeaderURL, IsEncodingProblem, IsTruncated, Keyword, Keywords,
Language, Languages, Location, MailboxIds, MessageIdsHeaderValue, Name, PartId,
RawHeaderValue, Subject, TextHeaderValue, ThreadId, Type, URLsHeaderValue,
UnparsedEmailId}
+import org.apache.james.jmap.mail._
Review comment:
Do not use a WILDCARD....
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala
##########
@@ -24,15 +24,14 @@ import eu.timepit.refined
import eu.timepit.refined.collection.NonEmpty
import eu.timepit.refined.refineV
import eu.timepit.refined.types.string.NonEmptyString
-import javax.inject.Inject
import org.apache.james.jmap.core.Id.IdConstraint
-import org.apache.james.jmap.core.{Id, SetError, State, UTCDate}
+import org.apache.james.jmap.core.{Id, SetError, UTCDate, UuidState}
import org.apache.james.jmap.mail.KeywordsFactory.STRICT_KEYWORDS_FACTORY
-import org.apache.james.jmap.mail.{AddressesHeaderValue, AsAddresses, AsDate,
AsGroupedAddresses, AsMessageIds, AsRaw, AsText, AsURLs, Attachment, BlobId,
Charset, ClientBody, ClientCid, ClientEmailBodyValue, ClientPartId,
DateHeaderValue, DestroyIds, Disposition, EmailAddress, EmailAddressGroup,
EmailCreationId, EmailCreationRequest, EmailCreationResponse, EmailHeader,
EmailHeaderName, EmailHeaderValue, EmailSetRequest, EmailSetResponse,
EmailSetUpdate, EmailerName, GroupName, GroupedAddressesHeaderValue,
HeaderMessageId, HeaderURL, IsEncodingProblem, IsTruncated, Keyword, Keywords,
Language, Languages, Location, MailboxIds, MessageIdsHeaderValue, Name,
ParseOption, RawHeaderValue, SpecificHeaderRequest, Subject, TextHeaderValue,
Type, URLsHeaderValue, UnparsedMessageId}
-import org.apache.james.jmap.mail.{AddressesHeaderValue, AsAddresses, AsDate,
AsGroupedAddresses, AsMessageIds, AsRaw, AsText, AsURLs, Attachment, BlobId,
Charset, ClientBody, ClientCid, ClientEmailBodyValue, ClientPartId,
DateHeaderValue, DestroyIds, Disposition, EmailAddress, EmailAddressGroup,
EmailCreationRequest, EmailCreationResponse, EmailHeader, EmailHeaderName,
EmailHeaderValue, EmailImport, EmailImportRequest, EmailImportResponse,
EmailSetRequest, EmailSetResponse, EmailSetUpdate, EmailerName, GroupName,
GroupedAddressesHeaderValue, HeaderMessageId, HeaderURL, IsEncodingProblem,
IsTruncated, Keyword, Keywords, Language, Languages, Location, MailboxIds,
MessageIdsHeaderValue, Name, ParseOption, RawHeaderValue,
SpecificHeaderRequest, Subject, TextHeaderValue, Type, URLsHeaderValue}
+import org.apache.james.jmap.mail._
Review comment:
Do not use a WILDCARD....
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/PushSerializer.scala
##########
@@ -0,0 +1,120 @@
+/****************************************************************
+ * 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.jmap.json
+
+import org.apache.james.jmap.change.{TypeName, TypeState, TypeStateFactory}
+import org.apache.james.jmap.core.{AccountId, OutboundMessage, PingMessage,
PushState, RequestId, State, StateChange, WebSocketError,
WebSocketInboundMessage, WebSocketPushDisable, WebSocketPushEnable,
WebSocketRequest, WebSocketResponse}
+import play.api.libs.json.{Format, JsError, JsNull, JsObject, JsResult,
JsString, JsSuccess, JsValue, Json, OWrites, Reads, Writes}
+
+import javax.inject.Inject
+import scala.util.Try
+
+case class PushSerializer @Inject()(typeStateFactory: TypeStateFactory) {
+ private implicit val stateWrites: Writes[State] = new Writes[State] {
+ def writes(state: State) = JsString(state.serialize)
+ }
Review comment:
```suggestion
private implicit val stateWrites: Writes[State] = state =>
JsString(state.serialize)
```
##########
File path:
server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/StateChangeEventSerializerTest.scala
##########
@@ -34,10 +34,10 @@ object StateChangeEventSerializerTest {
val USERNAME: Username = Username.of("bob")
val EVENT: StateChangeEvent = StateChangeEvent(eventId = EVENT_ID,
username = USERNAME,
- mailboxState = Some(State.INSTANCE),
- emailState =
Some(State.fromStringUnchecked("2d9f1b12-b35a-43e6-9af2-0106fb53a943")),
- vacationResponseState =
Some(State.fromStringUnchecked("2d9f1b12-3333-4444-5555-0106fb53a943")),
- emailDeliveryState =
Some(State.fromStringUnchecked("2d9f1b12-0000-1111-3333-0106fb53a943")))
+ map = (Map(MailboxTypeName -> UuidState.INSTANCE) ++
Review comment:
Please do a single call to `Map(...)`
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/EventSourceRoutes.scala
##########
@@ -69,11 +68,11 @@ object EventSourceOptions {
private def retrieveTypes(request: HttpServerRequest):
Either[IllegalArgumentException, Set[TypeName]] =
queryParam(request, "types") match {
case None => Left(new IllegalArgumentException("types parameter is
compulsory"))
- case Some(List("*")) => Right(TypeName.ALL)
+ case Some(List("*")) => Right(typeStateFactory.all.toSet)
case Some(list) => list.flatMap(_.split(","))
.map(string =>
- TypeName.parse(string)
- .left.map(errorMessage => new
IllegalArgumentException(errorMessage)))
+ typeStateFactory.parse(string)
+ .left.map(throwable => throwable))
Review comment:
You can remove `.left.map(throwable => throwable)` (it does nothing)
##########
File path:
server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/StateChangeEventSerializerTest.scala
##########
@@ -50,10 +50,8 @@ object StateChangeEventSerializerTest {
|}""".stripMargin
val EVENT_NO_DELIVERY: StateChangeEvent = StateChangeEvent(eventId =
EVENT_ID,
username = USERNAME,
- mailboxState = Some(State.INSTANCE),
- emailState =
Some(State.fromStringUnchecked("2d9f1b12-b35a-43e6-9af2-0106fb53a943")),
- emailDeliveryState = None,
- vacationResponseState = None)
+ map = (Map(MailboxTypeName -> UuidState.INSTANCE) ++
Review comment:
Single call to `Map` ?
##########
File path:
server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/core/WebSocketTransport.scala
##########
@@ -19,13 +19,12 @@
package org.apache.james.jmap.core
-import java.nio.charset.StandardCharsets
Review comment:
Please revert these import changes...
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]