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]

Reply via email to