001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.krad.data.jpa.eclipselink;
017
018import static org.junit.Assert.assertEquals;
019import static org.junit.Assert.assertFalse;
020import static org.junit.Assert.assertNotNull;
021import static org.junit.Assert.assertTrue;
022
023import java.util.HashSet;
024import java.util.Map;
025import java.util.Set;
026
027import javax.persistence.Entity;
028import javax.persistence.EntityManager;
029import javax.persistence.EntityManagerFactory;
030import javax.persistence.FetchType;
031import javax.persistence.Id;
032import javax.persistence.ManyToOne;
033import javax.persistence.metamodel.EntityType;
034import javax.persistence.spi.PersistenceUnitInfo;
035import javax.persistence.spi.PersistenceUnitTransactionType;
036import javax.transaction.TransactionManager;
037
038import org.apache.commons.dbcp.BasicDataSource;
039import org.eclipse.persistence.internal.jpa.EntityManagerFactoryDelegate;
040import org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl;
041import org.eclipse.persistence.jpa.JpaEntityManager;
042import org.junit.After;
043import org.junit.Before;
044import org.junit.Test;
045import org.junit.runner.RunWith;
046import org.kuali.rice.core.api.config.property.ConfigContext;
047import org.kuali.rice.core.framework.config.property.SimpleConfig;
048import org.kuali.rice.core.framework.persistence.jta.Jta;
049import org.kuali.rice.krad.data.jpa.KradEntityManagerFactoryBean;
050import org.kuali.rice.krad.data.jpa.eclipselink.testentities.TestEntity;
051import org.mockito.Mock;
052import org.mockito.runners.MockitoJUnitRunner;
053import org.springframework.context.support.ClassPathXmlApplicationContext;
054import org.springframework.instrument.classloading.SimpleInstrumentableClassLoader;
055import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
056import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
057
058/**
059 * Tests the {@link KradEclipseLinkEntityManagerFactoryBean}.
060 *
061 * @author Kuali Rice Team (rice.collab@kuali.org)
062 */
063@RunWith(MockitoJUnitRunner.class)
064public class KradEclipseLinkEntityManagerFactoryBeanTest {
065
066    @Mock TransactionManager transactionManager;
067    @Mock javax.transaction.UserTransaction userTransaction;
068
069    private ClassPathXmlApplicationContext context;
070    private EntityManagerFactory entityManagerFactory;
071
072    @Before
073    public void setUp() throws Exception {
074        initializeConfig();
075    }
076
077    @After
078    public void tearDown() throws Exception {
079        if (context != null) {
080            context.destroy();
081        }
082        ConfigContext.destroy();
083    }
084
085    private void initializeConfig() {
086        SimpleConfig config = new SimpleConfig();
087        config.putProperty("rice.krad.jpa.global.randomProperty", "randomValue");
088        config.putProperty("rice.krad.jpa.global.eclipselink.weaving", "false");
089        ConfigContext.init(config);
090    }
091
092    private void loadContext(String springXmlFile) throws Exception {
093        this.context = new ClassPathXmlApplicationContext(springXmlFile, getClass());
094        Map<String, EntityManagerFactory> factories =  context.getBeansOfType(EntityManagerFactory.class);
095        assertEquals(1, factories.size());
096        this.entityManagerFactory = factories.values().iterator().next();
097    }
098
099    @Test
100    public void testMinimal() throws Exception {
101        loadContext(getClass().getSimpleName() +  "_Minimal.xml");
102
103        Set<EntityType<?>> minimalEntities = entityManagerFactory.getMetamodel().getEntities();
104        // there should be only the ConverterHolder which is loaded by default
105        assertEquals(0, minimalEntities.size());
106
107        // create the entity manager to verify that it works
108        EntityManager entityManager = entityManagerFactory.createEntityManager();
109                // assertFalse(entityManager.contains(new ConverterHolder()));
110        entityManager.close();
111
112        assertFalse(isJtaEnabled());
113    }
114
115    @Test
116    public void testFull() throws Exception {
117        loadContext(getClass().getSimpleName() +  "_Full.xml");
118
119        Set<EntityType<?>> fullEntities = entityManagerFactory.getMetamodel().getEntities();
120        assertEquals(5, fullEntities.size());
121        Set<Class<?>> entityClasses = new HashSet<Class<?>>();
122        for (EntityType<?> entityType : fullEntities) {
123            entityClasses.add(entityType.getJavaType());
124        }
125
126        assertTrue(entityClasses.contains(TestEntity.class));
127        assertTrue(entityClasses.contains(TestEntity1.class));
128        assertTrue(entityClasses.contains(TestEntity2.class));
129        assertTrue(entityClasses.contains(TestEntity3.class));
130        assertTrue(entityClasses.contains(TestEntity4.class));
131
132        assertFalse(isJtaEnabled());
133    }
134
135    @Test
136    public void testJta() throws Exception {
137        Jta.configure(transactionManager, userTransaction);
138        try {
139            loadContext(getClass().getSimpleName() + "_Jta.xml");
140            assertTrue("JTA should be enabled.", isJtaEnabled());
141        } finally {
142            Jta.reset();
143        }
144    }
145
146    @Test
147    public void testLoadTimeWeaving() throws Exception {
148        loadContext(getClass().getSimpleName() +  "_LoadTimeWeaving.xml");
149        EntityManagerFactoryDelegate delegate =
150                entityManagerFactory.unwrap(EntityManagerFactoryDelegate.class);
151        PersistenceUnitInfo info = delegate.getSetupImpl().getPersistenceUnitInfo();
152        assertTrue(info.getClassLoader() instanceof SimpleInstrumentableClassLoader);
153    }
154
155    /**
156     * Verifies that it's not permitted to configure with both a JTA and Non-JTA datasource.
157     */
158    @Test(expected = IllegalStateException.class)
159    public void testInvalidDataSourceConfiguration() throws Exception {
160        // kind of a random addition to throw the superclass in here, but allows me to get some
161        // coverage on some of the other methods from the superclass without having to write a separate test
162        KradEntityManagerFactoryBean factoryBean =
163                new KradEntityManagerFactoryBean();
164        factoryBean.setDataSource(new BasicDataSource());
165        factoryBean.setJtaDataSource(new BasicDataSource());
166        factoryBean.afterPropertiesSet();
167    }
168
169    @Test
170    public void testGetDataSource() throws Exception {
171        KradEclipseLinkEntityManagerFactoryBean factoryBean =
172                new KradEclipseLinkEntityManagerFactoryBean();
173
174        BasicDataSource dataSourceNonJta = new BasicDataSource();
175        factoryBean.setDataSource(dataSourceNonJta);
176        assertEquals(dataSourceNonJta, factoryBean.getDataSource());
177
178        BasicDataSource dataSourceJta = new BasicDataSource();
179        factoryBean.setJtaDataSource(dataSourceJta);
180        assertEquals(dataSourceJta, factoryBean.getDataSource());
181    }
182
183    /**
184     * Just tests some of the getters to ensure they are delegating down to the internal factory bean and the
185     * PersistenceUnitManager appropriately.
186     */
187    @Test
188    public void testVariousGetters() throws Exception {
189        loadContext(getClass().getSimpleName() +  "_LoadTimeWeaving.xml");
190        KradEclipseLinkEntityManagerFactoryBean factoryBean =
191                context.getBean(KradEclipseLinkEntityManagerFactoryBean.class);
192        assertNotNull(factoryBean);
193
194        assertEquals(2, factoryBean.getPersistenceUnitPostProcessors().length);
195        EntityManagerFactory entityManagerFactory = factoryBean.getNativeEntityManagerFactory();
196        assertTrue(entityManagerFactory instanceof EntityManagerFactoryImpl);
197        assertEquals(factoryBean.getBeanClassLoader(), getClass().getClassLoader());
198        assertEquals(JpaEntityManager.class, factoryBean.getEntityManagerInterface());
199
200    }
201
202    private boolean isJtaEnabled() throws Exception {
203        EntityManagerFactoryDelegate delegate =
204                entityManagerFactory.unwrap(EntityManagerFactoryDelegate.class);
205        PersistenceUnitInfo info = delegate.getSetupImpl().getPersistenceUnitInfo();
206        return info.getJtaDataSource() != null && info.getTransactionType() == PersistenceUnitTransactionType.JTA;
207    }
208
209    public static final class TestPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
210        @Override
211        public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
212            pui.getManagedClassNames().add(TestEntity3.class.getName());
213        }
214    }
215
216    @Entity
217    public static final class TestEntity1 {
218        @Id
219        private String id;
220    }
221
222    @Entity
223    public static final class TestEntity2 {
224        @Id
225        private String id;
226    }
227
228    @Entity
229    public static final class TestEntity3 {
230        @Id
231        private String id;
232    }
233
234    public static final class TestEntity4 {
235        private String id;
236    }
237
238    @Entity
239    public static final class TestEntity5 {
240        @Id
241        private String id;
242
243        @ManyToOne(fetch = FetchType.LAZY)
244        private TestEntity3 testEntity3;
245
246    }
247
248
249}