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 7235590aaccc638d49c85180dfc442dd07670d55 Author: Benoit TELLIER <[email protected]> AuthorDate: Tue Dec 10 21:56:20 2024 +0100 [PERF] EventSerializer support: multiple events --- .../org/apache/james/events/EventSerializer.java | 6 ++++ .../james/events/EventSerializersAggregator.java | 36 ++++++++++++++++++++++ .../apache/james/events/EventBusTestFixture.java | 17 ++++++++++ .../james/event/json/MailboxEventSerializer.scala | 16 +++++++++- .../james/jmap/change/JmapEventSerializer.scala | 10 ++++++ 5 files changed, 84 insertions(+), 1 deletion(-) diff --git a/event-bus/api/src/main/java/org/apache/james/events/EventSerializer.java b/event-bus/api/src/main/java/org/apache/james/events/EventSerializer.java index 8cca2d2ee1..5f04bf14e9 100644 --- a/event-bus/api/src/main/java/org/apache/james/events/EventSerializer.java +++ b/event-bus/api/src/main/java/org/apache/james/events/EventSerializer.java @@ -20,16 +20,22 @@ package org.apache.james.events; import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.List; public interface EventSerializer { String toJson(Event event); + String toJson(Collection<Event> event); + default byte[] toJsonBytes(Event event) { return toJson(event).getBytes(StandardCharsets.UTF_8); } Event asEvent(String serialized); + List<Event> asEvents(String serialized); + default Event fromBytes(byte[] serialized) { return asEvent(new String(serialized, StandardCharsets.UTF_8)); } diff --git a/event-bus/api/src/main/java/org/apache/james/events/EventSerializersAggregator.java b/event-bus/api/src/main/java/org/apache/james/events/EventSerializersAggregator.java index ca2e6b383d..0661de6c00 100644 --- a/event-bus/api/src/main/java/org/apache/james/events/EventSerializersAggregator.java +++ b/event-bus/api/src/main/java/org/apache/james/events/EventSerializersAggregator.java @@ -19,6 +19,8 @@ package org.apache.james.events; +import java.util.Collection; +import java.util.List; import java.util.Optional; import java.util.Set; @@ -52,6 +54,24 @@ public class EventSerializersAggregator implements EventSerializer { .orElseThrow(() -> new RuntimeException("Could not deserialize event: " + serialized)); } + @Override + public String toJson(Collection<Event> events) { + return allEventSerializers.stream() + .map(eventSerializer -> serialize(events, eventSerializer)) + .flatMap(Optional::stream) + .findFirst() + .orElseThrow(() -> new RuntimeException("Could not serialize event: " + events)); + } + + @Override + public List<Event> asEvents(String serialized) { + return allEventSerializers.stream() + .map(eventSerializer -> deserializeEvents(serialized, eventSerializer)) + .flatMap(Optional::stream) + .findFirst() + .orElseThrow(() -> new RuntimeException("Could not deserialize event: " + serialized)); + } + private Optional<String> serialize(Event event, EventSerializer eventSerializer) { try { return Optional.of(eventSerializer.toJson(event)); @@ -60,6 +80,14 @@ public class EventSerializersAggregator implements EventSerializer { } } + private Optional<String> serialize(Collection<Event> event, EventSerializer eventSerializer) { + try { + return Optional.of(eventSerializer.toJson(event)); + } catch (Exception ex) { + return Optional.empty(); + } + } + private Optional<Event> deserialize(String json, EventSerializer eventSerializer) { try { return Optional.of(eventSerializer.asEvent(json)); @@ -67,4 +95,12 @@ public class EventSerializersAggregator implements EventSerializer { return Optional.empty(); } } + + private Optional<List<Event>> deserializeEvents(String json, EventSerializer eventSerializer) { + try { + return Optional.of(eventSerializer.asEvents(json)); + } catch (Exception ex) { + return Optional.empty(); + } + } } diff --git a/event-bus/api/src/test/java/org/apache/james/events/EventBusTestFixture.java b/event-bus/api/src/test/java/org/apache/james/events/EventBusTestFixture.java index d5e9369728..4b6b16d766 100644 --- a/event-bus/api/src/test/java/org/apache/james/events/EventBusTestFixture.java +++ b/event-bus/api/src/test/java/org/apache/james/events/EventBusTestFixture.java @@ -24,10 +24,12 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; import org.apache.james.core.Username; @@ -189,6 +191,21 @@ public interface EventBusTestFixture { Username username = Username.of(Joiner.on("&").join(parts.stream().skip(2).collect(ImmutableList.toImmutableList()))); return new TestEvent(eventId, username); } + + @Override + public String toJson(Collection<Event> event) { + return event.stream() + .map(this::toJson) + .collect(Collectors.joining("^")); + } + + @Override + public List<Event> asEvents(String serialized) { + return Splitter.on('^') + .splitToStream(serialized) + .map(this::asEvent) + .collect(ImmutableList.toImmutableList()); + } } class TestRegistrationKey implements RegistrationKey { diff --git a/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala b/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala index 365620f75e..3eeee7fc55 100644 --- a/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala +++ b/mailbox/event/json/src/main/scala/org/apache/james/event/json/MailboxEventSerializer.scala @@ -20,6 +20,7 @@ package org.apache.james.event.json import java.time.Instant +import java.util import java.util.{TreeMap => JavaTreeMap} import jakarta.inject.Inject @@ -398,18 +399,27 @@ class JsonSerialize(mailboxIdFactory: MailboxId.Factory, messageIdFactory: Messa implicit val eventOFormat: OFormat[Event] = derived.oformat() def toJson(event: Event): String = Json.toJson(event).toString() + def toJson(event: Iterable[Event]): String = Json.toJson(event).toString() def toJsonBytes(event: Event): Array[Byte] = Json.toBytes(Json.toJson(event)) def fromJson(json: String): JsResult[Event] = Json.fromJson[Event](Json.parse(json)) + def fromJsonAsEvents(json: String): JsResult[List[Event]] = if (json.startsWith("{")) { + Json.fromJson[Event](Json.parse(json)).map(event => List(event)) + } else { + Json.fromJson[List[Event]](Json.parse(json)) + } } private val eventSerializerPrivateWrapper = new EventSerializerPrivateWrapper() def toJson(event: JavaEvent): String = eventSerializerPrivateWrapper.toJson(ScalaConverter.toScala(event)) + def toJson(event: util.Collection[JavaEvent]): String = eventSerializerPrivateWrapper.toJson(event.asScala.map(ScalaConverter.toScala)) def toJsonBytes(event: JavaEvent): Array[Byte] = eventSerializerPrivateWrapper.toJsonBytes(ScalaConverter.toScala(event)) def fromJson(json: String): JsResult[JavaEvent] = eventSerializerPrivateWrapper.fromJson(json) .map(event => event.toJava) + def fromJsonAsEvents(json: String): JsResult[List[JavaEvent]] = eventSerializerPrivateWrapper.fromJsonAsEvents(json) + .map(event => event.map(_.toJava)) } -class MailboxEventSerializer @Inject()(mailboxIdFactory: MailboxId.Factory, messageIdFactory: MessageId.Factory, quotaRootDeserializer: QuotaRootDeserializer) extends EventSerializer{ +class MailboxEventSerializer @Inject()(mailboxIdFactory: MailboxId.Factory, messageIdFactory: MessageId.Factory, quotaRootDeserializer: QuotaRootDeserializer) extends EventSerializer { private val jsonSerialize = new JsonSerialize(mailboxIdFactory, messageIdFactory, quotaRootDeserializer) override def toJson(event: JavaEvent): String = jsonSerialize.toJson(event) @@ -418,6 +428,10 @@ class MailboxEventSerializer @Inject()(mailboxIdFactory: MailboxId.Factory, mess def fromJson(json: String): JsResult[JavaEvent] = jsonSerialize.fromJson(json) + override def toJson(event: util.Collection[JavaEvent]): String = jsonSerialize.toJson(event) + + override def asEvents(serialized: String): util.List[JavaEvent] = jsonSerialize.fromJsonAsEvents(serialized).get.asJava + override def asEvent(serialized: String): JavaEvent = fromJson(serialized).get } diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/JmapEventSerializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/JmapEventSerializer.scala index 76fc8b6974..d6f4f4c65e 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/JmapEventSerializer.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/change/JmapEventSerializer.scala @@ -20,8 +20,11 @@ package org.apache.james.jmap.change import java.util.Optional +import java.util import com.fasterxml.jackson.annotation.JsonProperty +import com.google.api.client.util.Preconditions +import com.google.common.collect.ImmutableList import jakarta.inject.Inject import org.apache.james.core.Username import org.apache.james.events.Event.EventId @@ -90,4 +93,11 @@ case class JmapEventSerializer @Inject()(stateChangeEventDTOFactory: StateChange override def toJsonBytes(event: Event): Array[Byte] = genericSerializer.serializeToBytes(event) override def fromBytes(serialized: Array[Byte]): Event = genericSerializer.deserializeFromBytes(serialized) + + override def toJson(event: util.Collection[Event]): String = { + Preconditions.checkArgument(event.size() == 1, "Not supported for multiple events, please serialize separately") + toJson(event.iterator().next()) + } + + override def asEvents(serialized: String): util.List[Event] = ImmutableList.of(asEvent(serialized)) } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
