WebSocket Integration

Hi devs,

While cleaning up GitHub - xwiki-contrib/xwiki-contrib-websocket: XWiki Websocket Integration in order to integrate it in platform, because it is needed by the real-time editing feature, I realized that this extension doesn’t use the standard Java API for WebSocket (JSR356). Instead it proposed a custom API implemented using Netty. Using standard APIs is always better and in this case it also means we can rely on the servlet container implementation without needing any additional library. Based on this I published a proposal at https://design.xwiki.org/xwiki/bin/view/Proposal/WebSocketIntegration and I pushed the code on two branches:

The main thing is that developers will be able to implement WebSocket end-points using the standard API (javax.websocket.*) with just one small addition: they will have to mark their end-points using the org.xwiki.websocket.EndpointComponent interface (component role with no methods).

I’d like to include this in XWiki 13.6RC1 so please share your thoughts ASAP.

Thanks,
Marius

Sounds good to me. Just for information, you said in the proposal that there is a Jakarta Websocket 2.0 standard we cannot use for now because of Java 8: this will replace in the future Java API Websocket 1.1, or it’s a brand new implem? Said otherwise would that be easy to move towards that implementation if it’s going to replace Java API Websocket in a near future, so that we’re not stuck with an old deprecated implementation?

Hi @surli, as can be seen from Jakarta WebSocket Specification the only significant change is the package rename, which is pain… In my proposal I haven’t added any abstraction layer on top of the WebSocket API (JSR356) because I think its too much work and it leads in the end to a custom WebSocket API…

So with my proposal, when you write a WebSocket end-point you are using directly the WebSocket API (JSR356) with its javax.websocket.* classes and interfaces. Moving to Jakarta WebSocket 2.0 would mean:

  • updating the pom to depend on the new API
  • updating the imported packages (javax.websocket.* to jakarta.websocket.*)
  • releasing a new version

From the point of view of XWiki Standard, we will start by supporting only JSR356, then add support for Jakarta WebSocket API and maintain both for some time (depending on the adoption by the servlet containers we support), and finally drop JSR356 and keep only Jakarta WebSocket API. This means we’ll have to duplicate some code while supporting both APIs…

Note that servlet containers won’t support both APIs at the same time. This is the current state:

  • Tomcat 9 (JSR-356 v1.1)
  • Tomcat 10 (Jakarta 2.0)
  • Jetty 9 (JSR-356 v1.0)
  • Jetty 10 (JSR-356 v1.1)
  • Jetty 11 (Jakarta 2.0)

XWiki Standard needs to work with multiple versions of Tomcat and Jetty so it needs to support / bundle both APIs, but only the one supported by the servlet container will be activated (i.e. only the WebSocket end-points that use the API supported by the servlet container will be deployed). This means that extension developers will have to maintain two versions (branches): one using JSR-356 and one using Jakarta 2.0. The administrator will have to install the extension version that works with the servlet container used.

On our side (XWiki Standard) we might be able to avoid code duplication by using the Maven Shade plugin. We basically maintain only one API (e.g. Jakarta) and we shade it to rename the pacakges:

  • xwiki-commons-websocket
    • xwiki-commons-websocket-jakarta (the one we maintain, where we keep the source code)
    • xwiki-commons-websocket-jsr356 (no source code here, just using the Maven Shade plugin to rename packages)

I experimented a bit with this and the main issue so far is that components.txt is not updated but I should be able to write a Resource Transformer.

WDYT?

Thanks,
Marius

Maintaining 2 branches (for the 2 versions of the WebSocket API) will be a pain for extension developers, so I’d like to investigate another approach:

  • ask extension developers to use only the 2.0 (Jakarta) version of the WebSocket API
  • on our side we either deploy the end-points directly, if the servlet container supports v2.0 or through a bridge (i.e. we deploy some v1.0 end-points that wrap the v2.0 end-points provided by the extension developers).

Note that there 2 ways in which you can define an end-point:

  • using annotations
  • extending the Endpoint abstract class

Creating a bridge for the end-points extending Endpoint should be doable and not extremely complex. The problem is with bridging the annotated end-points. This is quite complex and I’m thinking to leave this for later, i.e. to start by recommending extension developers to use only the second option (extend Endpoint) for now (which can be bridged, so it will run on any servlet container supporting any of the WebSocket API versions).

WDYT?

Thanks,
Marius

The move from javax to jakarta is not a websocket specific subject, so I don’t think it’s very accurate to talk about it only in this context. It’s a more general discussion we need to have, as this is going to affect a lot more than websocket extensions.

What is sure is that we are not going to support jakarta packages in the 13.x timeframe among other things because for most of those it means moving to Java 11 as minimum supported version, so IMO for now we should only manipulate the JSR-356 v1.1 API in the context of Websocket.

Thanks Thomas. This means I can merge my code as is (using the javax.* packages). We’ll see later (during 14.x cycle) what needs to be done to migrate to the jakarta.* packages. As you said, this concerns other modules also, not just the WebSocket integration, so we’ll have to apply a common solution.