Repository: quarkusio/quarkus
Issue: Hibernate ORM's JTAPlatform implementation is leaking a reference to its registry

**Describe the bug**
The `QuarkusJtaPlatform` implementation is extending a base class from upstream ORM which maks it a bad choice for also being used as a static singleton.
In particular this leads the classloader to hold on to a reference of the ORM `ServiceRegistry`, in turn leaking a significant amount of memory.

We can easily fix it to be a real stateless JtaPlatform, as we don't need the registry.

Changed files:
extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/customized/QuarkusJtaPlatform.java

diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/customized/QuarkusJtaPlatform.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/customized/QuarkusJtaPlatform.java
index 66c60a703ff..bcef7173c40 100644
--- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/customized/QuarkusJtaPlatform.java
+++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/customized/QuarkusJtaPlatform.java
@@ -1,26 +1,72 @@
 package io.quarkus.hibernate.orm.runtime.customized;
 
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
 import javax.transaction.TransactionManager;
 import javax.transaction.UserTransaction;
 
-import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;
+import org.hibernate.engine.transaction.jta.platform.internal.JtaSynchronizationStrategy;
+import org.hibernate.engine.transaction.jta.platform.internal.TransactionManagerAccess;
+import org.hibernate.engine.transaction.jta.platform.internal.TransactionManagerBasedSynchronizationStrategy;
+import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
 
-public final class QuarkusJtaPlatform extends AbstractJtaPlatform {
+public final class QuarkusJtaPlatform implements JtaPlatform, TransactionManagerAccess {
 
     public static final QuarkusJtaPlatform INSTANCE = new QuarkusJtaPlatform();
 
+    private final JtaSynchronizationStrategy tmSynchronizationStrategy = new TransactionManagerBasedSynchronizationStrategy(
+            this);
+    private volatile TransactionManager transactionManager;
+    private volatile UserTransaction userTransaction;
+
     private QuarkusJtaPlatform() {
         //nothing
     }
 
     @Override
-    protected TransactionManager locateTransactionManager() {
-        return com.arjuna.ats.jta.TransactionManager.transactionManager();
+    public TransactionManager retrieveTransactionManager() {
+        TransactionManager transactionManager = this.transactionManager;
+        if (transactionManager == null) {
+            transactionManager = com.arjuna.ats.jta.TransactionManager.transactionManager();
+            this.transactionManager = transactionManager;
+        }
+        return transactionManager;
+    }
+
+    @Override
+    public TransactionManager getTransactionManager() {
+        return retrieveTransactionManager();
+    }
+
+    @Override
+    public UserTransaction retrieveUserTransaction() {
+        UserTransaction userTransaction = this.userTransaction;
+        if (this.userTransaction == null) {
+            userTransaction = com.arjuna.ats.jta.UserTransaction.userTransaction();
+            this.userTransaction = userTransaction;
+        }
+        return userTransaction;
+    }
+
+    @Override
+    public Object getTransactionIdentifier(final Transaction transaction) {
+        return transaction;
+    }
+
+    @Override
+    public void registerSynchronization(Synchronization synchronization) {
+        this.tmSynchronizationStrategy.registerSynchronization(synchronization);
+    }
+
+    @Override
+    public boolean canRegisterSynchronization() {
+        return this.tmSynchronizationStrategy.canRegisterSynchronization();
     }
 
     @Override
-    protected UserTransaction locateUserTransaction() {
-        return com.arjuna.ats.jta.UserTransaction.userTransaction();
+    public int getCurrentStatus() throws SystemException {
+        return this.retrieveTransactionManager().getStatus();
     }
 
 }