From 1cef2d42c904a1c7983ec9a28497a4857573d543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20Op=C3=A1lka?= Date: Fri, 26 May 2023 21:12:54 +0200 Subject: [PATCH] [WFLY-16296] Jakarta EE based WildFly have to communicate successfully with previous Java EE based WildFly versions --- ...96_JavaEE_And_JakartaEE_Compatibility.adoc | 214 ++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 backward-compatibility/WFLY-16296_JavaEE_And_JakartaEE_Compatibility.adoc diff --git a/backward-compatibility/WFLY-16296_JavaEE_And_JakartaEE_Compatibility.adoc b/backward-compatibility/WFLY-16296_JavaEE_And_JakartaEE_Compatibility.adoc new file mode 100644 index 000000000..f736f81c9 --- /dev/null +++ b/backward-compatibility/WFLY-16296_JavaEE_And_JakartaEE_Compatibility.adoc @@ -0,0 +1,214 @@ += Jakarta EE based WildFly have to communicate successfully with previous Java EE based WildFly +:author: Richard Opalka; Flavia Rainone +:email: ropalka@redhat.com; frainone@@redhat.com +:toc: left +:icons: font +:idprefix: +:idseparator: - + +== Overview + +This feature will ensure bidirectional EJB, JNDI & HTTP remote protocols backward +compatibility between Java EE 8- and Jakarta EE 9+ WildFly versions. + +== Issue Metadata + +=== Issue: + +* https://issues.redhat.com/browse/WFLY-16296[WFLY-16296] + +=== Dev Contacts: +* mailto:ropalka@redhat.com[Richard Opalka] +* mailto:frainone@redhat.com[Flavia Rainone] + +=== QE Contacts: +TODO!!! + +=== Testing By +* [ ] Engineering + +* [x] QE + +=== Affected Projects or Components: + +* JBoss Marshalling, JBoss EJB Client, WildFly Naming Client, WildFly Http Client + +=== Relevant Installation Types +* [x] Traditional standalone server (unzipped or provisioned by Galleon) + +* [x] Managed domain + +* [x] OpenShift s2i + +* [x] Bootable jar + +== Requirements + +=== Hard requirements + +* Ability of Java EE 8- client/server to communicate with Jakarta EE 9+ server/client via EJB, JNDI and HTTP remote protocols. +* Ability of Jakarta EE 9+ client/server to communicate with Java EE 8- server/client via EJB, JNDI and HTTP remote protocols. +* Java EE 8- WildFly versions cannot be modified in order to be able to communicate with Jakarta EE9+ WildFly variants. +* Backward compatibility mode is off by default, and can be enabled by setting the `org.wildfly.ee.namespace.interop` system +property to `true`. +* If the property is set to `true` on a Java EE 8- server/client, it is ignored, as those clients and servers are not +responsible for handling interoperability. + + +=== None requirements + +* Infinispan and Clustering protocols backward compatibility. +* ABI compatibility for non existing mapping of classes/methods available in Java EE 8- but not in Jakarta EE 9+ and vice versa. + Users will need to migrate their clients/applications for such problematic scenarios manually. + +== Test Plan + +The test will be created for hard requirements scenarios. This test will reside in QE's testsuite and will become +one of the must-execute tests for ensuring backward compatibility between Java EE based WildFly and Jakarta EE based WildFly variants. + +== Community Documentation + +Community documentation will be provided for how the aforementioned compatibility among remote EE clients and servers. +It will be added to the WildFly documentation, and it will be based on this analysis document as reference. + +Also, the wildfly-http-client project documentation must also be updated describing the changes applied to the WildFly +HTTP Client protocol. + +== Release Note Content +Bullet point: support interoperability between Jakarta EE 9 servers and Java EE 8 or older servers + +== Design Notes + +The backward compatibility between two Java EE 8- and Jakarta EE 9+ remote endpoints has to be enabled at the endpoint +that supports Jakarta EE 9+. To accomplish that, the Jakarta EE 9+ endpoint (a client or a server) is started with the system +property `org.wildfly.ee.namespace.interop` set to `true`. With this property enabled, a Jakarta EE 9+ server or client +becomes compatible with other Java EE 8- servers/clients, while still keeping the ability to communicate with other +Jakarta EE 9+ endpoints(as long as those endpoints have the same property enabled, see +<>). We say that this particular server or client is running on *EE namespace +interoperable mode*. + +Only Jakarta EE 9+ endpoints can run on EE namespace interoperable mode. For other endpoints, this property will be +ignored if set to `true`. + +To implement that, we propose the following changes to the following libraries: + + +=== JBoss Marshalling + +* Introduce new abstraction ClassNameTransformer that will allow to remap one java type to another java type. +* Provide hooks for that abstraction to allow renaming java types before/after marshalling/unmarshalling them. +* Provide default Java EE <-> Jakarta EE class name transformer implementation. + +=== JBoss EJB Client + +Since JBoss EJB protocol supports 'handshake' kind of messages it is possible to detect other side protocol version before exchanging messages. Because of this we propose to: + +* Introduce new major version 4 of remote EJB protocol to indicate EJB client/server is supporting Jakarta EE 9+. +* Activate version 4 of EJB protocol if and only if JBoss EJB client/server is used in Jakarta EE9+ environment. +* Install Java EE <-> Jakarta EE class name transformer if and only if the client/server is running on EE namespace +interoperable mode, and the other side is using version 1 or 2 or 3 of the protocol. + +=== WildFly Naming Client + +Since WildFly NAMING protocol supports 'handshake' kind of messages it is possible to detect other side protocol version before exchanging messages. Because of this we propose to: + +* Introduce new major version 3 of remote NAMING protocol to indicate NAMING client/server is supporting Jakarta EE 9+. +* Activate version 3 of NAMING protocol if and only if WildFly NAMING client/server is used in Jakarta EE9+ environment. +* Install Java EE <-> Jakarta EE class name transformer if and only if the client/server is running on EE namespace +interoperable mode, and the other side is using version 1 or 2 of the protocol. + +=== WildFly Http Client + +Since WildFly HTTP protocol doesn't support 'handshake' kind of messages it is not possible to detect other side +protocol version in advance. The version number is in the URL of the particular service provided by the server, and the request +is sent directly to that particular URL, without prior negotiation. Because of this we propose to: + +* implement a handshake based on a HTTP header +* Install Java EE <-> Jakarta EE class name transformer if and only if the server is on EE namespace interoperable mode +and the handshake indicates the connection requires such transformer + +The handshaking between two Jakarta 9+ client and servers, both running on EE namespace interoperable mode, works as follows: + +* whenever the client side opens a new connection to a server, the first request it sends via that connection contains +the `x-wf-ee-ns: interop` HTTP header, and that first request is marshalled +with the Java EE 8- <-> Jakarta EE 9+ class transformer, transforming the EE api classes in the request to `javax` EE +namespace +* the server receives the request, verifies it has the `x-wf-ee-ns: interop` header, and enables the class name +transformer to transform the request back to `jakarta` namespace. The server though sends the response without the +transformer, with the Jakarta EE 9+ classes intact, and adds the `x-wf-ee-ns: jakarta` header to the response +* the client receives such response and reads the header. It indicates that this connection is a +Jakarta EE 9+ connection at both ends, and the client is not supposed to transform the namespace of the EE classes +contained in the response data. +* from that point on, whenever the client uses the same connection, no transformation is done on its side. Furhtermore, +all requests sent by the client through this connection contain the +`x-wf-ee-ns: jakarta` header +* whenever the server receives a request with the `x-wf-ee-ns: jakarta` header, it knows that the client is a +Jakarta EE 9+ client running on EE namespace interoperable mode. So, it does not use any class file transformer +for reading the request and writing the response. + +Here is how the handshaking works when an EE namespace interoperable client sends a request to a Java EE 8- server: + +* as in the previous case, the client side opens a new connection to a server, and the first request it sends via that +connection contains the `x-wf-ee-ns: interop` HTTP header. Also, that first request is marshalled +with the Java EE <-> Jakarta EE class transformer, porting the request from `javakarta` to `javax` EE namespace +* the Java EE 8- server receives the request in Java EE format and handles the request normally, ignoring the +`x-wf-ee-ns: interop` header. +* the client receives the server response and checks it does not contain the `x-wf-ee-ns` header. So, it enables the +Java EE <-> Jakarta EE class name transformer for that connection's lifetime. +* from that point on, whenever the client uses the same connection, no extra header is added, and the +class name transformer is always enabled, guaranteeing that the Jakarta EE 9+ classes are ported to Java EE 8- namespace +on every request, and transformed back on every response + +The final handshake scenario is a Java EE 8- client sending a request to a EE namespace interoperable server: + +* client sends the request to the server in the standard way, and the request naturally can contain `javax` EE +namespace classes +* the server receives the request and verifies it does not contain the `x-wf-ee-ns` header. The server interprets +this as an indication that the client is Java EE 8-, and it enables the class name transformer for both reading the request +and writing the response back to the client. + +If a Jakarta EE9+ server receives a request from an EE namespace interoperable client, even if the server is not on +interoperable mode it will be able to respond, because it will check the presence of the `x-wf-ee-ns: interop` +header. In this case, it will apply the class name transformation to the request on read, and it will add the +`x-wf-ee-ns: jakarta` header to the response on write. This allows the non-interoperable server to be able to serve +requests from interoperable clients. + +=== Communication Across Multiple Endpoints +The following table summarizes the possible scenarios where a client can +communicate with a server remotely: + +|=== +| |Java EE 8- client | Jakarta EE 9+ client | Jakarta EE 9+ namespace interoperable client +|Java EE 8- server | Yes | No | Yes +|Jakarta EE 9+ server | No | Yes | Yes +|Jakarta EE 9+ namespace interoperable server | Yes | No | Yes +|=== + +Notice that, in order for a Jakarta EE 9+ client to be able to communicate with a Jakarta EE 9+ interoperable server, +the client must be also running on EE namespace interoperable mode. + +Regarding handling cases where a server is non interoperable and receives a Javax EE namespace request, the code could, +in the future, be smarter and detect potential mismatches between the endpoints that will cause the +communication to fail. Such as current endpoint is not EE namespace interoperable while the other end is otherwise, or +even if the other end is a Java EE 8- instance. If we do so, we could print a warning indicating that the EE namespace +interoperability must be enabled at this server/client, so it can establish proper communication with the remote +endpoint. However, there are two options to print this warning: + +* verifying if the message indicates the remote endpoint is running on EE namespace interoperability mode +* or catching a ClassCastException when marshalling/unmarshalling and checking if the exception message contains `"javax"` + +While the former option sounds more elegant. The client would not have a way of detecting if it is invoking an incompatible +server, unless we change the protocol to apply a `x-wf-ee-ns:javax` header to +Java 8- clients requests. Both extra actions at the two ends will result in a performance penalty. The solution +we propose at this moment was designed in a way to prevent by all means any kind of overhead in the standard +communication between two Jakarta EE 9+ endpoints, leaving the extra overhead to the special case of an Java EE 9+ +endpoint needing to communicate with Java EE8- endpoints. + +[IMPORTANT] +==== +All servers and clients are interoperable if the communication does not involve any EE class. +This might lead a user to mistakenly believe that no such configuration was needed _"before, when my code was doing one +thing, but now it has changed and it no longer works"_. However, *full interoperability among the clients and servers +with mixed different EE libraries (i.e, `javax` vs `jakarta` namespace) is only guaranteed when all Jakarta EE 9+ +elements of that communication are running on _EE namespace interoperable mode_*. +====