package com.softwaremill.common.cdi.persistence;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.proxy.HibernateProxy;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.softwaremill.common.arquillian.ManifestUtil;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertNull;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class EntityWriterTest extends AbstractHibernateTest {
@Override
protected void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(SimpleEntity.class);
cfg.addAnnotatedClass(EntityWithLazySubentity.class);
// Setting isolation to TRANSACTION_READ_UNCOMMITTED as JTA is not available and using two EMs causes otherwise
// deadlocks.
cfg.setProperty("hibernate.connection.isolation", "1");
}
@Deployment
public static JavaArchive createTestArchive() {
JavaArchive ar = ShrinkWrap.create(JavaArchive.class, "test.jar")
.addClass(EntityWriter.class)
.addClass(MockEntityManagerProducers.class);
ar = ManifestUtil.addEmptyBeansXml(ar);
return ar;
}
@Inject
private EntityWriter entityWriter;
@Inject @ReadOnly
private EntityManagerDelegator readOnlyEntityManagerDelegator;
@Inject @Writeable
private EntityManagerDelegator writeableEntityManagerDelegator;
@Test
public void testPersistWrite() {
// Creating and setting the entity managers
EntityManager readOnlyEm = newReadOnlyEntityManager();
EntityManager writeableEm = newEntityManager();
readOnlyEntityManagerDelegator.setDelegate(readOnlyEm);
writeableEntityManagerDelegator.setDelegate(writeableEm);
// Writing an entity
writeableEm.getTransaction().begin();
readOnlyEm.joinTransaction();
SimpleEntity se = new SimpleEntity("A");
se = entityWriter.write(se);
Assert.assertEquals(se.getData(), "A");
Assert.assertNotNull(se.getId());
// Trying to read the entity
Assert.assertEquals(readOnlyEm.find(SimpleEntity.class, se.getId()), se);
writeableEm.getTransaction().commit();
// Reading the entity using a different EM
EntityManager readOnlyEm2 = newReadOnlyEntityManager();
SimpleEntity se2 = readOnlyEm2.find(SimpleEntity.class, se.getId());
Assert.assertEquals(se, se2);
// Closing
readOnlyEm.close();
readOnlyEm2.close();
writeableEm.close();
}
@Test
public void testUpdateDetachedWhichIsInReadOnlyEM() {
// Creating and setting the entity managers
EntityManager readOnlyEm = newReadOnlyEntityManager();
EntityManager writeableEm = newEntityManager();
readOnlyEntityManagerDelegator.setDelegate(readOnlyEm);
writeableEntityManagerDelegator.setDelegate(writeableEm);
// Writing an entity
writeableEm.getTransaction().begin();
readOnlyEm.joinTransaction();
SimpleEntity se = new SimpleEntity("A");
se = entityWriter.write(se);
writeableEm.getTransaction().commit();
// Simulating a new request - new entity managers
readOnlyEm.close();
writeableEm.close();
EntityManager readOnlyEm2 = newReadOnlyEntityManager();
EntityManager writeableEm2 = newEntityManager();
readOnlyEntityManagerDelegator.setDelegate(readOnlyEm2);
writeableEntityManagerDelegator.setDelegate(writeableEm2);
// Loading the entity into the new RO EM
Assert.assertEquals(readOnlyEm2.find(SimpleEntity.class, se.getId()), se);
// Writing the (now detached, as the old EMs are closed) modified entity
writeableEm2.getTransaction().begin();
se.setData("B");
se = entityWriter.write(se);
Assert.assertEquals(se.getData(), "B");
writeableEm2.getTransaction().commit();
// Closing
readOnlyEm2.close();
writeableEm2.close();
}
@Test
public void testPersistDelete() {
// Creating and setting the entity managers
EntityManager readOnlyEm = newReadOnlyEntityManager();
EntityManager writeableEm = newEntityManager();
readOnlyEntityManagerDelegator.setDelegate(readOnlyEm);
writeableEntityManagerDelegator.setDelegate(writeableEm);
// Writing an entity
writeableEm.getTransaction().begin();
readOnlyEm.joinTransaction();
SimpleEntity se = new SimpleEntity("C");
se = entityWriter.write(se);
Assert.assertEquals(se.getData(), "C");
Assert.assertNotNull(se.getId());
// Trying to read the entity
Assert.assertEquals(readOnlyEm.find(SimpleEntity.class, se.getId()), se);
writeableEm.getTransaction().commit();
// Writing an entity
writeableEm.getTransaction().begin();
readOnlyEm.joinTransaction();
// now delete the entity
entityWriter.delete(se);
writeableEm.getTransaction().commit();
// check it's not accessible by the read only manager
assertNull(readOnlyEm.find(SimpleEntity.class, se.getId()));
// Closing
readOnlyEm.close();
writeableEm.close();
}
@Test
public void shouldPersistEntityProxyEvenIfNotInWritableEmContext() {
// Creating and setting the entity managers
EntityManager readOnlyEm = newReadOnlyEntityManager();
EntityManager writeableEm = newEntityManager();
readOnlyEntityManagerDelegator.setDelegate(readOnlyEm);
writeableEntityManagerDelegator.setDelegate(writeableEm);
// Write an entity with proxy
EntityWithLazySubentity entityWithLazy = new EntityWithLazySubentity();
entityWithLazy.setSubentity(new SimpleEntity());
// Write to the DB
writeableEm.getTransaction().begin();
readOnlyEm.joinTransaction();
// Write entity with proxy
EntityWithLazySubentity writtenEntity = entityWriter.write(entityWithLazy);
writeableEm.getTransaction().commit();
readOnlyEm.clear();
writeableEm.clear();
// Write to the DB
writeableEm.getTransaction().begin();
readOnlyEm.joinTransaction();
// Get proxy
writtenEntity = readOnlyEm.find(EntityWithLazySubentity.class, writtenEntity.getId());
assertThat(writtenEntity).isNotNull();
SimpleEntity proxy = writtenEntity.getSubentity();
assertThat(proxy).isNotNull();
// Try to write the proxy
SimpleEntity writeResult = entityWriter.write(proxy);
assertThat(writeResult).isNotNull();
assertThat(writeResult instanceof HibernateProxy).isFalse();
}
}