/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.orm.jpa; import java.util.Map; import java.util.Properties; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.OptimisticLockException; import javax.persistence.PersistenceException; import javax.persistence.spi.PersistenceProvider; import javax.persistence.spi.PersistenceUnitInfo; import javax.persistence.spi.PersistenceUnitTransactionType; import javax.persistence.spi.ProviderUtil; import org.junit.Test; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.dao.DataAccessException; import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver; import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.interceptor.DefaultTransactionAttribute; import org.springframework.util.SerializationTestUtils; import static org.junit.Assert.*; import static org.mockito.BDDMockito.*; /** * @author Rod Johnson * @author Juergen Hoeller * @author Phillip Webb */ @SuppressWarnings("rawtypes") public class LocalContainerEntityManagerFactoryBeanTests extends AbstractEntityManagerFactoryBeanTests { // Static fields set by inner class DummyPersistenceProvider private static Map actualProps; private static PersistenceUnitInfo actualPui; @Test public void testValidPersistenceUnit() throws Exception { parseValidPersistenceUnit(); } @Test public void testExceptionTranslationWithNoDialect() throws Exception { LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); cefb.getObject(); assertNull("No dialect set", cefb.getJpaDialect()); RuntimeException in1 = new RuntimeException("in1"); PersistenceException in2 = new PersistenceException(); assertNull("No translation here", cefb.translateExceptionIfPossible(in1)); DataAccessException dex = cefb.translateExceptionIfPossible(in2); assertNotNull(dex); assertSame(in2, dex.getCause()); } @Test public void testEntityManagerFactoryIsProxied() throws Exception { LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); EntityManagerFactory emf = cefb.getObject(); assertSame("EntityManagerFactory reference must be cached after init", emf, cefb.getObject()); assertNotSame("EMF must be proxied", mockEmf, emf); assertTrue(emf.equals(emf)); DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); bf.setSerializationId("emf-bf"); bf.registerSingleton("emf", cefb); cefb.setBeanFactory(bf); cefb.setBeanName("emf"); assertNotNull(SerializationTestUtils.serializeAndDeserialize(emf)); } @Test public void testApplicationManagedEntityManagerWithoutTransaction() throws Exception { Object testEntity = new Object(); EntityManager mockEm = mock(EntityManager.class); given(mockEmf.createEntityManager()).willReturn(mockEm); LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); EntityManagerFactory emf = cefb.getObject(); assertSame("EntityManagerFactory reference must be cached after init", emf, cefb.getObject()); assertNotSame("EMF must be proxied", mockEmf, emf); EntityManager em = emf.createEntityManager(); assertFalse(em.contains(testEntity)); cefb.destroy(); verify(mockEmf).close(); } @Test public void testApplicationManagedEntityManagerWithTransaction() throws Exception { Object testEntity = new Object(); EntityTransaction mockTx = mock(EntityTransaction.class); // This one's for the tx (shared) EntityManager sharedEm = mock(EntityManager.class); given(sharedEm.getTransaction()).willReturn(new NoOpEntityTransaction()); // This is the application-specific one EntityManager mockEm = mock(EntityManager.class); given(mockEm.getTransaction()).willReturn(mockTx); given(mockEmf.createEntityManager()).willReturn(sharedEm, mockEm); LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); JpaTransactionManager jpatm = new JpaTransactionManager(); jpatm.setEntityManagerFactory(cefb.getObject()); TransactionStatus txStatus = jpatm.getTransaction(new DefaultTransactionAttribute()); EntityManagerFactory emf = cefb.getObject(); assertSame("EntityManagerFactory reference must be cached after init", emf, cefb.getObject()); assertNotSame("EMF must be proxied", mockEmf, emf); EntityManager em = emf.createEntityManager(); em.joinTransaction(); assertFalse(em.contains(testEntity)); jpatm.commit(txStatus); cefb.destroy(); verify(mockTx).begin(); verify(mockTx).commit(); verify(mockEm).contains(testEntity); verify(mockEmf).close(); } @Test public void testApplicationManagedEntityManagerWithTransactionAndCommitException() throws Exception { Object testEntity = new Object(); EntityTransaction mockTx = mock(EntityTransaction.class); willThrow(new OptimisticLockException()).given(mockTx).commit(); // This one's for the tx (shared) EntityManager sharedEm = mock(EntityManager.class); given(sharedEm.getTransaction()).willReturn(new NoOpEntityTransaction()); // This is the application-specific one EntityManager mockEm = mock(EntityManager.class); given(mockEm.getTransaction()).willReturn(mockTx); given(mockEmf.createEntityManager()).willReturn(sharedEm, mockEm); LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); JpaTransactionManager jpatm = new JpaTransactionManager(); jpatm.setEntityManagerFactory(cefb.getObject()); TransactionStatus txStatus = jpatm.getTransaction(new DefaultTransactionAttribute()); EntityManagerFactory emf = cefb.getObject(); assertSame("EntityManagerFactory reference must be cached after init", emf, cefb.getObject()); assertNotSame("EMF must be proxied", mockEmf, emf); EntityManager em = emf.createEntityManager(); em.joinTransaction(); assertFalse(em.contains(testEntity)); try { jpatm.commit(txStatus); fail("Should have thrown OptimisticLockingFailureException"); } catch (OptimisticLockingFailureException ex) { // expected } cefb.destroy(); verify(mockTx).begin(); verify(mockEm).contains(testEntity); verify(mockEmf).close(); } @Test public void testApplicationManagedEntityManagerWithJtaTransaction() throws Exception { Object testEntity = new Object(); // This one's for the tx (shared) EntityManager sharedEm = mock(EntityManager.class); given(sharedEm.getTransaction()).willReturn(new NoOpEntityTransaction()); // This is the application-specific one EntityManager mockEm = mock(EntityManager.class); given(mockEmf.createEntityManager()).willReturn(sharedEm, mockEm); LocalContainerEntityManagerFactoryBean cefb = parseValidPersistenceUnit(); MutablePersistenceUnitInfo pui = ((MutablePersistenceUnitInfo) cefb.getPersistenceUnitInfo()); pui.setTransactionType(PersistenceUnitTransactionType.JTA); JpaTransactionManager jpatm = new JpaTransactionManager(); jpatm.setEntityManagerFactory(cefb.getObject()); TransactionStatus txStatus = jpatm.getTransaction(new DefaultTransactionAttribute()); EntityManagerFactory emf = cefb.getObject(); assertSame("EntityManagerFactory reference must be cached after init", emf, cefb.getObject()); assertNotSame("EMF must be proxied", mockEmf, emf); EntityManager em = emf.createEntityManager(); em.joinTransaction(); assertFalse(em.contains(testEntity)); jpatm.commit(txStatus); cefb.destroy(); verify(mockEm).joinTransaction(); verify(mockEm).contains(testEntity); verify(mockEmf).close(); } public LocalContainerEntityManagerFactoryBean parseValidPersistenceUnit() throws Exception { LocalContainerEntityManagerFactoryBean emfb = createEntityManagerFactoryBean( "org/springframework/orm/jpa/domain/persistence.xml", null, "Person"); return emfb; } @Test public void testInvalidPersistenceUnitName() throws Exception { try { createEntityManagerFactoryBean("org/springframework/orm/jpa/domain/persistence.xml", null, "call me Bob"); fail("Should not create factory with this name"); } catch (IllegalArgumentException ex) { // Ok } } protected LocalContainerEntityManagerFactoryBean createEntityManagerFactoryBean( String persistenceXml, Properties props, String entityManagerName) throws Exception { // This will be set by DummyPersistenceProvider actualPui = null; actualProps = null; LocalContainerEntityManagerFactoryBean containerEmfb = new LocalContainerEntityManagerFactoryBean(); containerEmfb.setPersistenceUnitName(entityManagerName); containerEmfb.setPersistenceProviderClass(DummyContainerPersistenceProvider.class); if (props != null) { containerEmfb.setJpaProperties(props); } containerEmfb.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); containerEmfb.setPersistenceXmlLocation(persistenceXml); containerEmfb.afterPropertiesSet(); assertEquals(entityManagerName, actualPui.getPersistenceUnitName()); if (props != null) { assertEquals(props, actualProps); } //checkInvariants(containerEmfb); return containerEmfb; //containerEmfb.destroy(); //emfMc.verify(); } @Test public void testRejectsMissingPersistenceUnitInfo() throws Exception { LocalContainerEntityManagerFactoryBean containerEmfb = new LocalContainerEntityManagerFactoryBean(); String entityManagerName = "call me Bob"; containerEmfb.setPersistenceUnitName(entityManagerName); containerEmfb.setPersistenceProviderClass(DummyContainerPersistenceProvider.class); try { containerEmfb.afterPropertiesSet(); fail(); } catch (IllegalArgumentException ex) { // Ok } } private static class DummyContainerPersistenceProvider implements PersistenceProvider { @Override public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo pui, Map map) { actualPui = pui; actualProps = map; return mockEmf; } @Override public EntityManagerFactory createEntityManagerFactory(String emfName, Map properties) { throw new UnsupportedOperationException(); } @Override public ProviderUtil getProviderUtil() { throw new UnsupportedOperationException(); } // JPA 2.1 method public void generateSchema(PersistenceUnitInfo persistenceUnitInfo, Map map) { throw new UnsupportedOperationException(); } // JPA 2.1 method public boolean generateSchema(String persistenceUnitName, Map map) { throw new UnsupportedOperationException(); } } private static class NoOpEntityTransaction implements EntityTransaction { @Override public void begin() { } @Override public void commit() { } @Override public void rollback() { } @Override public void setRollbackOnly() { throw new UnsupportedOperationException(); } @Override public boolean getRollbackOnly() { return false; } @Override public boolean isActive() { return false; } } }