From 440a2ef49096ecd7051520c288256a264cbd6e73 Mon Sep 17 00:00:00 2001 From: Vlad Mihalcea Date: Wed, 29 Aug 2018 13:07:34 +0300 Subject: [PATCH] HHH-12929 - Add AtomikosJtaPlatform implementation --- .../chapters/transactions/Transactions.adoc | 1 + gradle/libraries.gradle | 3 + hibernate-core/hibernate-core.gradle | 2 + .../internal/StrategySelectorBuilder.java | 8 ++ .../internal/AtomikosJtaPlatform.java | 36 +++++++ .../internal/StandardJtaPlatformResolver.java | 8 ++ .../lazyload/AtomikosJtaLazyLoadingTest.java | 98 +++++++++++++++++++ 7 files changed, 156 insertions(+) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/transaction/jta/platform/internal/AtomikosJtaPlatform.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/lazyload/AtomikosJtaLazyLoadingTest.java diff --git a/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc b/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc index 1a0b4712ac..88848fc0a3 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc @@ -71,6 +71,7 @@ Hibernate tries to discover the `JtaPlatform` it should use through the use of a If that resolution does not work, or if you wish to provide a custom implementation you will need to specify the `hibernate.transaction.jta.platform` setting. Hibernate provides many implementations of the `JtaPlatform` contract, all with short names: +`Atomikos`:: `JtaPlatform` for Atomikos. `Borland`:: `JtaPlatform` for the Borland Enterprise Server. `Bitronix`:: `JtaPlatform` for Bitronix. `JBossAS`:: `JtaPlatform` for Arjuna/JBossTransactions/Narayana when used within the JBoss/WildFly Application Server. diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 95b34c7fbf..88fc0411ad 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -136,6 +136,9 @@ ext { agroal_api: "io.agroal:agroal-api:0.4", agroal_pool: "io.agroal:agroal-pool:0.4", + atomikos: "com.atomikos:transactions:4.0.6", + atomikos_jta: "com.atomikos:transactions-jta:4.0.6", + cdi: "javax.enterprise:cdi-api:${cdiVersion}", weld: "org.jboss.weld.se:weld-se-shaded:${weldVersion}", diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index 3025391aee..faab42e095 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -90,6 +90,8 @@ dependencies { testRuntime( libraries.javassist ) testRuntime( libraries.byteBuddy ) testRuntime( libraries.weld ) + testRuntime( libraries.atomikos ) + testRuntime( libraries.atomikos_jta ) testRuntime(libraries.wildfly_transaction_client) testCompile( project( ':hibernate-jpamodelgen' ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java index 8d2e581f98..7d10f55545 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java @@ -70,6 +70,7 @@ import org.hibernate.dialect.SybaseASE15Dialect; import org.hibernate.dialect.SybaseAnywhereDialect; import org.hibernate.dialect.TeradataDialect; import org.hibernate.dialect.TimesTenDialect; +import org.hibernate.engine.transaction.jta.platform.internal.AtomikosJtaPlatform; import org.hibernate.engine.transaction.jta.platform.internal.BitronixJtaPlatform; import org.hibernate.engine.transaction.jta.platform.internal.BorlandEnterpriseServerJtaPlatform; import org.hibernate.engine.transaction.jta.platform.internal.JBossAppServerJtaPlatform; @@ -252,6 +253,13 @@ public class StrategySelectorBuilder { } private void addJtaPlatforms(StrategySelectorImpl strategySelector) { + addJtaPlatforms( + strategySelector, + AtomikosJtaPlatform.class, + "Atomikos", + "org.hibernate.service.jta.platform.internal.AtomikosJtaPlatform" + ); + addJtaPlatforms( strategySelector, BorlandEnterpriseServerJtaPlatform.class, diff --git a/hibernate-core/src/main/java/org/hibernate/engine/transaction/jta/platform/internal/AtomikosJtaPlatform.java b/hibernate-core/src/main/java/org/hibernate/engine/transaction/jta/platform/internal/AtomikosJtaPlatform.java new file mode 100644 index 0000000000..e4e487739b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/transaction/jta/platform/internal/AtomikosJtaPlatform.java @@ -0,0 +1,36 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.engine.transaction.jta.platform.internal; + +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatformException; + +/** + * @author Vlad Mihalcea + */ +public class AtomikosJtaPlatform extends AbstractJtaPlatform { + public static final String TM_CLASS_NAME = "com.atomikos.icatch.jta.UserTransactionManager"; + + @Override + protected TransactionManager locateTransactionManager() { + try { + Class transactionManagerClass = serviceRegistry().getService( ClassLoaderService.class ).classForName( TM_CLASS_NAME ); + return (TransactionManager) transactionManagerClass.newInstance(); + } + catch (Exception e) { + throw new JtaPlatformException( "Could not instantiate Atomikos TransactionManager", e ); + } + } + + @Override + protected UserTransaction locateUserTransaction() { + return (UserTransaction) jndiService().locate( "java:comp/UserTransaction" ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/transaction/jta/platform/internal/StandardJtaPlatformResolver.java b/hibernate-core/src/main/java/org/hibernate/engine/transaction/jta/platform/internal/StandardJtaPlatformResolver.java index a04af918a0..df2ec1b85c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/transaction/jta/platform/internal/StandardJtaPlatformResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/transaction/jta/platform/internal/StandardJtaPlatformResolver.java @@ -82,6 +82,14 @@ public class StandardJtaPlatformResolver implements JtaPlatformResolver { catch (ClassLoadingException ignore) { } + // Atomikos ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + try { + classLoaderService.classForName( AtomikosJtaPlatform.TM_CLASS_NAME ); + return new AtomikosJtaPlatform(); + } + catch (ClassLoadingException ignore) { + } + // Bitronix ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ try { classLoaderService.classForName( BitronixJtaPlatform.TM_CLASS_NAME ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/lazyload/AtomikosJtaLazyLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/test/lazyload/AtomikosJtaLazyLoadingTest.java new file mode 100644 index 0000000000..3e37616ca4 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/lazyload/AtomikosJtaLazyLoadingTest.java @@ -0,0 +1,98 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.lazyload; + +import org.hibernate.Hibernate; +import org.hibernate.Session; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.transaction.jta.platform.internal.AtomikosJtaPlatform; +import org.hibernate.persister.entity.CustomSqlSchemaResolvingTest; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.jta.TestingJtaBootstrap; +import org.hibernate.testing.jta.TestingJtaPlatformImpl; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +/** + * @author Vlad Mihalcea + */ +public class AtomikosJtaLazyLoadingTest + extends BaseCoreFunctionalTestCase { + + private static final int CHILDREN_SIZE = 3; + private Long parentID; + private Long lastChildID; + + protected void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); + + TestingJtaBootstrap.prepare( cfg.getProperties() ); + cfg.setProperty( AvailableSettings.JTA_PLATFORM, "Atomikos" ); + } + + protected Class[] getAnnotatedClasses() { + return new Class[] { + Parent.class, + Child.class + }; + } + + protected void prepareTest() + throws Exception { + doInHibernate( this::sessionFactory, session -> { + Parent p = new Parent(); + for ( int i = 0; i < CHILDREN_SIZE; i++ ) { + final Child child = p.makeChild(); + session.persist( child ); + lastChildID = child.getId(); + } + session.persist( p ); + parentID = p.getId(); + } ); + } + + @Test + @TestForIssue(jiraKey = "HHH-7971") + public void testLazyCollectionLoadingAfterEndTransaction() { + Parent loadedParent = doInHibernate( this::sessionFactory, session -> { + return session.load( Parent.class, parentID ); + } ); + + assertFalse( Hibernate.isInitialized( loadedParent.getChildren() ) ); + + int i = 0; + for ( Child child : loadedParent.getChildren() ) { + i++; + assertNotNull( child ); + } + + assertEquals( CHILDREN_SIZE, i ); + + Child loadedChild = doInHibernate( this::sessionFactory, session -> { + return session.load( Child.class, lastChildID ); + } ); + + Parent p = loadedChild.getParent(); + int j = 0; + for ( Child child : p.getChildren() ) { + j++; + assertNotNull( child ); + } + + assertEquals( CHILDREN_SIZE, j ); + } + +}