Benoit Tellier created JAMES-3581:
-------------------------------------
Summary: As a JMAP extension writer, I want to PUSH state changes
for my extensions
Key: JAMES-3581
URL: https://issues.apache.org/jira/browse/JAMES-3581
Project: James Server
Issue Type: Improvement
Components: JMAP
Affects Versions: 3.6.0
Reporter: Benoit Tellier
Assignee: Antoine Duprat
Fix For: 3.7.0
# Why?
JMAP specifications defines the minimal features to get a basic email
reading/writing experience.
However, as part of our job at Linagora, writing a collaborative email suite,
we need advanced collaborative features that uses custom, off-spec, JMAP
extensions.
We thus want to implement these collaborative features as JMAP extensions
(because JMAP is so much of a nice protocol!).
We were able to:
- Write custom methods pretty much directly.
- We needed to contribute modular definition of session "capabilities" to be
advertising our custom ones.
But we are missing the push for custom extensions.
# What?
As an extension developper I want to be able to register my type states and
have states matching my format:
{code:java}
object IntState {
def parse(string: String): Either[IllegalArgumentException, IntState] =
Try(Integer.parseInt(string))
.toEither
.map(IntState(_))
.left.map(new IllegalArgumentException(_))
}
case class IntState(i: Int) extends State {
override def serialize: String = i.toString
}
case object CustomTypeName extends TypeName {
override val asString: String = "MyTypeName"
override def parse(string: String): Option[TypeName] = string match {
case CustomTypeName.asString => Some(CustomTypeName)
case _ => None
}
override def parseState(string: String): Either[IllegalArgumentException,
IntState] = IntState.parse(string)
}
{code}
Given this, I want to be injecting my extensions to the push in the guice
module definition:
{code:java}
Multibinder.newSetBinder(binder(), classOf[TypeName])
.addBinding()
.toInstance(CustomTypeName)
Multibinder.newSetBinder(binder(), classOf[GuiceProbe])
.addBinding()
.to(classOf[JmapEventBusProbe])
{code}
Doing so should allow me to emit 'custon' state change push notifications:
{code:java}
val stateChangeEvent: StateChangeEvent = StateChangeEvent(eventId =
CustomMethodContract.eventId, username = BOB, map = Map(CustomTypeName ->
intState))
SMono(jmapEventBus.dispatch(stateChangeEvent,
AccountIdRegistrationKey(accountId))).block()
{code}
Which allows generating state change events PUSH notifications carried over via
webSocket or SSE for your extensions :-)
# How?
Modularize the definition of State (extensions might not want to have it backed
by a UUID), allow creating custom type states (parse them, and from them be
able to parse the associated state). We also need to transport these additional
type states as part of our event system.
# Definition of done
Write an integration test where you emit a custom type state with an exotic
state implementation (meaning not backed by a UUID) and have the StateChange
event carried over to the client, for instance using WebSocket.
# Proof of concept
Quan had been putting this PR together:
https://github.com/apache/james-project/pull/391
--
This message was sent by Atlassian Jira
(v8.3.4#803005)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]