/* * 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 <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.jpa.test.transaction; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.transaction.Status; import javax.transaction.TransactionManager; import org.hibernate.Session; import org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl; import org.hibernate.internal.SessionImpl; import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.jta.TestingJtaBootstrap; import org.hibernate.testing.jta.TestingJtaPlatformImpl; import org.junit.After; import org.junit.Test; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** * @author Andrea Boriero */ public class CloseEntityManagerWithActiveTransactionTest extends BaseEntityManagerFunctionalTestCase { @Override protected void addConfigOptions(Map options) { super.addConfigOptions( options ); TestingJtaBootstrap.prepare( options ); options.put( AvailableSettings.TRANSACTION_TYPE, "JTA" ); } @Override public Class[] getAnnotatedClasses() { return new Class[] { Book.class, Container.class, Box.class, Muffin.class, SmallBox.class }; } @After public void tearDown() throws Exception { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); EntityManager em = getOrCreateEntityManager(); try { em.createQuery( "delete from Muffin" ).executeUpdate(); em.createQuery( "delete from Box" ).executeUpdate(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); } catch (Exception e) { final TransactionManager transactionManager = TestingJtaPlatformImpl.INSTANCE.getTransactionManager(); if ( transactionManager.getTransaction() != null && transactionManager.getTransaction() .getStatus() == Status.STATUS_ACTIVE ) { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().rollback(); } throw e; } finally { if ( em.isOpen() ) { em.close(); } } } @Test @TestForIssue(jiraKey = "HHH-10942") public void testPersistThenCloseWithAnActiveTransaction() throws Exception { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); EntityManager em = getOrCreateEntityManager(); try { Box box = new Box(); box.setColor( "red-and-white" ); em.persist( box ); em.close(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); } catch (Exception e) { final TransactionManager transactionManager = TestingJtaPlatformImpl.INSTANCE.getTransactionManager(); if ( transactionManager.getTransaction() != null && transactionManager.getTransaction() .getStatus() == Status.STATUS_ACTIVE ) { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().rollback(); } throw e; } finally { if ( em.isOpen() ) { em.close(); } } em = getOrCreateEntityManager(); try { final List results = em.createQuery( "from Box" ).getResultList(); assertThat( results.size(), is( 1 ) ); } finally { em.close(); } } @Test @TestForIssue( jiraKey = "HHH-11166") public void testMergeThenCloseWithAnActiveTransaction() throws Exception { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); EntityManager em = getOrCreateEntityManager(); try { Box box = new Box(); box.setColor( "red-and-white" ); em.persist( box ); em.close(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); em = getOrCreateEntityManager(); Muffin muffin = new Muffin(); muffin.setKind( "blueberry" ); box.addMuffin( muffin ); em.merge( box ); em.close(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); } catch (Exception e) { final TransactionManager transactionManager = TestingJtaPlatformImpl.INSTANCE.getTransactionManager(); if ( transactionManager.getTransaction() != null && transactionManager.getTransaction() .getStatus() == Status.STATUS_ACTIVE ) { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().rollback(); } throw e; } finally { if ( em.isOpen() ) { em.close(); } } em = getOrCreateEntityManager(); try { final List<Box> boxes = em.createQuery( "from Box" ).getResultList(); assertThat( boxes.size(), is( 1 ) ); assertThat( boxes.get( 0 ).getMuffinSet().size(), is( 1 ) ); } finally { em.close(); } } @Test @TestForIssue( jiraKey = "HHH-11269") public void testMergeWithDeletionOrphanRemovalThenCloseWithAnActiveTransaction() throws Exception { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); EntityManager em = getOrCreateEntityManager(); try { Muffin muffin = new Muffin(); muffin.setKind( "blueberry" ); SmallBox box = new SmallBox(muffin); box.setColor( "red-and-white" ); em.persist( box ); em.close(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); em = getOrCreateEntityManager(); box.emptyBox(); em.merge( box ); em.close(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); } catch (Exception e) { final TransactionManager transactionManager = TestingJtaPlatformImpl.INSTANCE.getTransactionManager(); if ( transactionManager.getTransaction() != null && transactionManager.getTransaction() .getStatus() == Status.STATUS_ACTIVE ) { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().rollback(); } throw e; } finally { if ( em.isOpen() ) { em.close(); } } em = getOrCreateEntityManager(); try { final List<SmallBox> boxes = em.createQuery( "from SmallBox" ).getResultList(); assertThat( boxes.size(), is( 1 ) ); assertTrue( boxes.get( 0 ).isEmpty()); } finally { em.close(); } } @Test @TestForIssue( jiraKey = "HHH-11166") public void testUpdateThenCloseWithAnActiveTransaction() throws Exception { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); EntityManager em = getOrCreateEntityManager(); try { Box box = new Box(); box.setColor( "red-and-white" ); em.persist( box ); em.close(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); em = getOrCreateEntityManager(); box = em.find( Box.class, box.getId() ); Muffin muffin = new Muffin(); muffin.setKind( "blueberry" ); box.addMuffin( muffin ); em.close(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); } catch (Exception e) { final TransactionManager transactionManager = TestingJtaPlatformImpl.INSTANCE.getTransactionManager(); if ( transactionManager.getTransaction() != null && transactionManager.getTransaction() .getStatus() == Status.STATUS_ACTIVE ) { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().rollback(); } throw e; } finally { if ( em.isOpen() ) { em.close(); } } em = getOrCreateEntityManager(); try { final List<Box> boxes = em.createQuery( "from Box" ).getResultList(); assertThat( boxes.size(), is( 1 ) ); assertThat( boxes.get( 0 ).getMuffinSet().size(), is( 1 ) ); } finally { em.close(); } } @Test @TestForIssue( jiraKey = "HHH-11166") public void testRemoveThenCloseWithAnActiveTransaction() throws Exception { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); EntityManager em = getOrCreateEntityManager(); try { Box box = new Box(); box.setColor( "red-and-white" ); em.persist( box ); Muffin muffin = new Muffin(); muffin.setKind( "blueberry" ); box.addMuffin( muffin ); em.close(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); em = getOrCreateEntityManager(); box = em.find( Box.class, box.getId() ); em.remove( box ); em.close(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); } catch (Exception e) { final TransactionManager transactionManager = TestingJtaPlatformImpl.INSTANCE.getTransactionManager(); if ( transactionManager.getTransaction() != null && transactionManager.getTransaction() .getStatus() == Status.STATUS_ACTIVE ) { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().rollback(); } throw e; } finally { if ( em.isOpen() ) { em.close(); } } em = getOrCreateEntityManager(); try { final List<Box> boxes = em.createQuery( "from Box" ).getResultList(); assertThat( boxes.size(), is( 0 ) ); } finally { em.close(); } } @Test @TestForIssue(jiraKey = "HHH-11099") public void testCommitReleasesLogicalConnection() throws Exception { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().begin(); EntityManager em = getOrCreateEntityManager(); try { Box box = new Box(); box.setColor( "red-and-white" ); em.persist( box ); final SessionImpl session = (SessionImpl) em.unwrap( Session.class ); final JdbcCoordinatorImpl jdbcCoordinator = (JdbcCoordinatorImpl) session.getJdbcCoordinator(); em.close(); TestingJtaPlatformImpl.INSTANCE.getTransactionManager().commit(); assertThat( "The logical connection is still open after commit", jdbcCoordinator.getLogicalConnection().isOpen(), is( false ) ); } catch (Exception e) { final TransactionManager transactionManager = TestingJtaPlatformImpl.INSTANCE.getTransactionManager(); if ( transactionManager.getTransaction() != null && transactionManager.getTransaction() .getStatus() == Status.STATUS_ACTIVE ) { TestingJtaPlatformImpl.INSTANCE.getTransactionManager().rollback(); } throw e; } finally { if ( em.isOpen() ) { em.close(); } } } @Entity(name = "Container") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) public static class Container { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String color; public Long getId() { return id; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } } @Entity(name = "Box") public static class Box extends Container { @OneToMany(mappedBy = "box", cascade = { CascadeType.MERGE, CascadeType.REMOVE, CascadeType.REFRESH, CascadeType.PERSIST }, fetch = FetchType.LAZY) private Set<Muffin> muffinSet; public Box() { } public void addMuffin(Muffin muffin) { muffin.setBox( this ); if ( muffinSet == null ) { muffinSet = new HashSet<>(); } muffinSet.add( muffin ); } public Set<Muffin> getMuffinSet() { return muffinSet; } } @Entity(name = "SmallBox") public static class SmallBox extends Container { @OneToOne(cascade = {CascadeType.MERGE, CascadeType.REMOVE, CascadeType.REFRESH, CascadeType.PERSIST }, orphanRemoval = true) private Muffin muffin; public SmallBox(){} public SmallBox(Muffin muffin) { this.muffin = muffin; } public void emptyBox(){ muffin = null; } public boolean isEmpty(){ return muffin == null; } } @Entity(name = "Muffin") public static class Muffin { @Id @GeneratedValue private Long muffinId; @ManyToOne private Box box; private String kind; public Muffin() { } public Box getBox() { return box; } public void setBox(Box box) { this.box = box; } public void setKind(String kind) { this.kind = kind; } } @FunctionalInterface public interface Action{ void execute(); } }