View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.orm.jpa;
18  
19  import java.lang.reflect.Proxy;
20  import java.util.List;
21  import javax.persistence.EntityManager;
22  import javax.persistence.Query;
23  import javax.persistence.TransactionRequiredException;
24  
25  import org.springframework.orm.jpa.domain.Person;
26  import org.springframework.transaction.annotation.Propagation;
27  import org.springframework.transaction.annotation.Transactional;
28  
29  /**
30   * An application-managed entity manager can join an existing transaction,
31   * but such joining must be made programmatically, not transactionally.
32   *
33   * @author Rod Johnson
34   * @since 2.0
35   */
36  @SuppressWarnings("deprecation")
37  public class ApplicationManagedEntityManagerIntegrationTests extends AbstractEntityManagerFactoryIntegrationTests {
38  
39  	@Transactional(propagation = Propagation.NOT_SUPPORTED)
40  	public void testEntityManagerIsProxy() {
41  		assertTrue("EntityManagerFactory is proxied", Proxy.isProxyClass(entityManagerFactory.getClass()));
42  	}
43  
44  	@Transactional(readOnly=true)
45  	public void testEntityManagerProxyIsProxy() {
46  		EntityManager em = entityManagerFactory.createEntityManager();
47  		assertTrue(Proxy.isProxyClass(em.getClass()));
48  		Query q = em.createQuery("select p from Person as p");
49  		List<Person> people = q.getResultList();
50  		assertNotNull(people);
51  
52  		assertTrue("Should be open to start with", em.isOpen());
53  		em.close();
54  		assertFalse("Close should work on application managed EM", em.isOpen());
55  	}
56  
57  	public void testEntityManagerProxyAcceptsProgrammaticTxJoining() {
58  		EntityManager em = entityManagerFactory.createEntityManager();
59  		em.joinTransaction();
60  	}
61  
62  	public void testInstantiateAndSave() {
63  		EntityManager em = entityManagerFactory.createEntityManager();
64  		em.joinTransaction();
65  		doInstantiateAndSave(em);
66  	}
67  
68  	public void testCannotFlushWithoutGettingTransaction() {
69  		EntityManager em = entityManagerFactory.createEntityManager();
70  		try {
71  			doInstantiateAndSave(em);
72  			fail("Should have thrown TransactionRequiredException");
73  		}
74  		catch (TransactionRequiredException ex) {
75  			// expected
76  		}
77  
78  		// TODO following lines are a workaround for Hibernate bug
79  		// If Hibernate throws an exception due to flush(),
80  		// it actually HAS flushed, meaning that the database
81  		// was updated outside the transaction
82  		deleteAllPeopleUsingEntityManager(sharedEntityManager);
83  		setComplete();
84  	}
85  
86  	public void doInstantiateAndSave(EntityManager em) {
87  		testStateClean();
88  		Person p = new Person();
89  
90  		p.setFirstName("Tony");
91  		p.setLastName("Blair");
92  		em.persist(p);
93  
94  		em.flush();
95  		assertEquals("1 row must have been inserted", 1, countRowsInTable(em, "person"));
96  	}
97  
98  	public void testStateClean() {
99  		assertEquals("Should be no people from previous transactions", 0, countRowsInTable("person"));
100 	}
101 
102 	public void testReuseInNewTransaction() {
103 		EntityManager em = entityManagerFactory.createEntityManager();
104 		em.joinTransaction();
105 
106 		doInstantiateAndSave(em);
107 		endTransaction();
108 
109 		assertFalse(em.getTransaction().isActive());
110 
111 		startNewTransaction();
112 		// Call any method: should cause automatic tx invocation
113 		assertFalse(em.contains(new Person()));
114 
115 		assertFalse(em.getTransaction().isActive());
116 		em.joinTransaction();
117 
118 		assertTrue(em.getTransaction().isActive());
119 
120 		doInstantiateAndSave(em);
121 		setComplete();
122 		endTransaction();	// Should rollback
123 		assertEquals("Tx must have committed back", 1, countRowsInTable(em, "person"));
124 
125 		// Now clean up the database
126 		startNewTransaction();
127 		em.joinTransaction();
128 		deleteAllPeopleUsingEntityManager(em);
129 		assertEquals("People have been killed", 0, countRowsInTable(em, "person"));
130 		setComplete();
131 	}
132 
133 	public static void deleteAllPeopleUsingEntityManager(EntityManager em) {
134 		em.createQuery("delete from Person p").executeUpdate();
135 	}
136 
137 	public void testRollbackOccurs() {
138 		EntityManager em = entityManagerFactory.createEntityManager();
139 		em.joinTransaction();
140 		doInstantiateAndSave(em);
141 		endTransaction();	// Should rollback
142 		assertEquals("Tx must have been rolled back", 0, countRowsInTable(em, "person"));
143 	}
144 
145 	public void testCommitOccurs() {
146 		EntityManager em = entityManagerFactory.createEntityManager();
147 		em.joinTransaction();
148 		doInstantiateAndSave(em);
149 
150 		setComplete();
151 		endTransaction();	// Should rollback
152 		assertEquals("Tx must have committed back", 1, countRowsInTable(em, "person"));
153 
154 		// Now clean up the database
155 		deleteFromTables("person");
156 	}
157 
158 }