HHH-5315:
- work units executed both in the before tx completion process and in the synchronization - each test class has its own H2 database - tests in a JTA environment git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19928 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
8ff871941d
commit
b50d8268d5
|
@ -118,6 +118,12 @@
|
||||||
<artifactId>javassist</artifactId>
|
<artifactId>javassist</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- For JTA tests -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-testing</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
@ -137,6 +143,11 @@
|
||||||
<artifactId>hibernate-entitymanager</artifactId>
|
<artifactId>hibernate-entitymanager</artifactId>
|
||||||
<version>${version}</version>
|
<version>${version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-testing</artifactId>
|
||||||
|
<version>${version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate</groupId>
|
||||||
<artifactId>hibernate-tools</artifactId>
|
<artifactId>hibernate-tools</artifactId>
|
||||||
|
|
|
@ -37,11 +37,14 @@ import org.hibernate.envers.tools.Pair;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
|
|
||||||
|
import javax.transaction.Synchronization;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class AuditProcess implements BeforeTransactionCompletionProcess {
|
public class AuditProcess implements BeforeTransactionCompletionProcess, Synchronization {
|
||||||
private final RevisionInfoGenerator revisionInfoGenerator;
|
private final RevisionInfoGenerator revisionInfoGenerator;
|
||||||
|
private final SessionImplementor session;
|
||||||
|
|
||||||
private final LinkedList<AuditWorkUnit> workUnits;
|
private final LinkedList<AuditWorkUnit> workUnits;
|
||||||
private final Queue<AuditWorkUnit> undoQueue;
|
private final Queue<AuditWorkUnit> undoQueue;
|
||||||
|
@ -49,8 +52,9 @@ public class AuditProcess implements BeforeTransactionCompletionProcess {
|
||||||
|
|
||||||
private Object revisionData;
|
private Object revisionData;
|
||||||
|
|
||||||
public AuditProcess(RevisionInfoGenerator revisionInfoGenerator) {
|
public AuditProcess(RevisionInfoGenerator revisionInfoGenerator, SessionImplementor session) {
|
||||||
this.revisionInfoGenerator = revisionInfoGenerator;
|
this.revisionInfoGenerator = revisionInfoGenerator;
|
||||||
|
this.session = session;
|
||||||
|
|
||||||
workUnits = new LinkedList<AuditWorkUnit>();
|
workUnits = new LinkedList<AuditWorkUnit>();
|
||||||
undoQueue = new LinkedList<AuditWorkUnit>();
|
undoQueue = new LinkedList<AuditWorkUnit>();
|
||||||
|
@ -153,4 +157,12 @@ public class AuditProcess implements BeforeTransactionCompletionProcess {
|
||||||
session.flush();
|
session.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Synchronization methods
|
||||||
|
|
||||||
|
public void beforeCompletion() {
|
||||||
|
doBeforeTransactionCompletion(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterCompletion(int status) { }
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,10 +52,22 @@ public class AuditProcessManager {
|
||||||
AuditProcess auditProcess = auditProcesses.get(transaction);
|
AuditProcess auditProcess = auditProcesses.get(transaction);
|
||||||
if (auditProcess == null) {
|
if (auditProcess == null) {
|
||||||
// No worries about registering a transaction twice - a transaction is single thread
|
// No worries about registering a transaction twice - a transaction is single thread
|
||||||
auditProcess = new AuditProcess(revisionInfoGenerator);
|
auditProcess = new AuditProcess(revisionInfoGenerator, session);
|
||||||
auditProcesses.put(transaction, auditProcess);
|
auditProcesses.put(transaction, auditProcess);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HHH-5315: the process must be both a BeforeTransactionCompletionProcess and a TX Synchronization.
|
||||||
|
*
|
||||||
|
* In a resource-local tx env, the process is called after the flush, and populates the audit tables.
|
||||||
|
* Also, any exceptions that occur during that are propagated (if a Synchronization was used, the exceptions
|
||||||
|
* would be eaten).
|
||||||
|
*
|
||||||
|
* In a JTA env, the before transaction completion is called before the flush, so not all changes are yet
|
||||||
|
* written. However, Synchronization-s do propagate exceptions, so they can be safely used.
|
||||||
|
*/
|
||||||
session.getActionQueue().registerProcess(auditProcess);
|
session.getActionQueue().registerProcess(auditProcess);
|
||||||
|
session.getTransaction().registerSynchronization(auditProcess);
|
||||||
|
|
||||||
session.getActionQueue().registerProcess(new AfterTransactionCompletionProcess() {
|
session.getActionQueue().registerProcess(new AfterTransactionCompletionProcess() {
|
||||||
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
|
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
|
||||||
auditProcesses.remove(transaction);
|
auditProcesses.remove(transaction);
|
||||||
|
|
|
@ -27,9 +27,13 @@ import java.io.IOException;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.ejb.AvailableSettings;
|
||||||
import org.hibernate.envers.AuditReader;
|
import org.hibernate.envers.AuditReader;
|
||||||
import org.hibernate.envers.AuditReaderFactory;
|
import org.hibernate.envers.AuditReaderFactory;
|
||||||
import org.hibernate.envers.event.AuditEventListener;
|
import org.hibernate.envers.event.AuditEventListener;
|
||||||
|
import org.hibernate.testing.tm.ConnectionProviderImpl;
|
||||||
|
import org.hibernate.testing.tm.TransactionManagerLookupImpl;
|
||||||
import org.testng.annotations.*;
|
import org.testng.annotations.*;
|
||||||
|
|
||||||
import org.hibernate.ejb.Ejb3Configuration;
|
import org.hibernate.ejb.Ejb3Configuration;
|
||||||
|
@ -89,11 +93,15 @@ public abstract class AbstractEntityTest {
|
||||||
initListeners();
|
initListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg.configure("hibernate.test.cfg.xml");
|
||||||
|
|
||||||
if (auditStrategy != null && !"".equals(auditStrategy)) {
|
if (auditStrategy != null && !"".equals(auditStrategy)) {
|
||||||
cfg.setProperty("org.hibernate.envers.audit_strategy", auditStrategy);
|
cfg.setProperty("org.hibernate.envers.audit_strategy", auditStrategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.configure("hibernate.test.cfg.xml");
|
// Separate database for each test class
|
||||||
|
cfg.setProperty("hibernate.connection.url", "jdbc:h2:mem:" + this.getClass().getName());
|
||||||
|
|
||||||
configure(cfg);
|
configure(cfg);
|
||||||
emf = cfg.buildEntityManagerFactory();
|
emf = cfg.buildEntityManagerFactory();
|
||||||
|
|
||||||
|
@ -117,4 +125,10 @@ public abstract class AbstractEntityTest {
|
||||||
public Ejb3Configuration getCfg() {
|
public Ejb3Configuration getCfg() {
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void addJTAConfig(Ejb3Configuration cfg) {
|
||||||
|
cfg.setProperty("connection.provider_class", ConnectionProviderImpl.class.getName());
|
||||||
|
cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, TransactionManagerLookupImpl.class.getName());
|
||||||
|
cfg.setProperty(AvailableSettings.TRANSACTION_TYPE, "JTA");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Middleware LLC.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.envers.test.integration.jta;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.Ejb3Configuration;
|
||||||
|
import org.hibernate.envers.test.AbstractEntityTest;
|
||||||
|
import org.hibernate.envers.test.entities.StrTestEntity;
|
||||||
|
import org.hibernate.envers.test.integration.reventity.ExceptionListenerRevEntity;
|
||||||
|
import org.hibernate.testing.tm.SimpleJtaTransactionManagerImpl;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link org.hibernate.envers.test.integration.reventity.ExceptionListener}, but in a JTA environment.
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
public class JtaExceptionListener extends AbstractEntityTest {
|
||||||
|
public void configure(Ejb3Configuration cfg) {
|
||||||
|
cfg.addAnnotatedClass(StrTestEntity.class);
|
||||||
|
cfg.addAnnotatedClass(ExceptionListenerRevEntity.class);
|
||||||
|
|
||||||
|
addJTAConfig(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = RuntimeException.class)
|
||||||
|
public void testTransactionRollback() throws Exception {
|
||||||
|
SimpleJtaTransactionManagerImpl.getInstance().begin();
|
||||||
|
|
||||||
|
// Trying to persist an entity - however the listener should throw an exception, so the entity
|
||||||
|
// shouldn't be persisted
|
||||||
|
newEntityManager();
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
StrTestEntity te = new StrTestEntity("x");
|
||||||
|
em.persist(te);
|
||||||
|
|
||||||
|
SimpleJtaTransactionManagerImpl.getInstance().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "testTransactionRollback")
|
||||||
|
public void testDataNotPersisted() throws Exception {
|
||||||
|
SimpleJtaTransactionManagerImpl.getInstance().begin();
|
||||||
|
|
||||||
|
// Checking if the entity became persisted
|
||||||
|
newEntityManager();
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
Long count = (Long) em.createQuery("select count(s) from StrTestEntity s where s.str = 'x'").getSingleResult();
|
||||||
|
assert count == 0l;
|
||||||
|
|
||||||
|
SimpleJtaTransactionManagerImpl.getInstance().commit();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package org.hibernate.envers.test.integration.jta;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.Ejb3Configuration;
|
||||||
|
import org.hibernate.envers.test.AbstractEntityTest;
|
||||||
|
import org.hibernate.envers.test.entities.IntTestEntity;
|
||||||
|
import org.hibernate.testing.tm.SimpleJtaTransactionManagerImpl;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link org.hibernate.envers.test.integration.basic.Simple}, but in a JTA environment.
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
public class JtaTransaction extends AbstractEntityTest {
|
||||||
|
private Integer id1;
|
||||||
|
|
||||||
|
public void configure(Ejb3Configuration cfg) {
|
||||||
|
cfg.addAnnotatedClass(IntTestEntity.class);
|
||||||
|
|
||||||
|
addJTAConfig(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initData() throws Exception {
|
||||||
|
SimpleJtaTransactionManagerImpl.getInstance().begin();
|
||||||
|
|
||||||
|
newEntityManager();
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
em.joinTransaction();
|
||||||
|
IntTestEntity ite = new IntTestEntity(10);
|
||||||
|
em.persist(ite);
|
||||||
|
id1 = ite.getId();
|
||||||
|
|
||||||
|
SimpleJtaTransactionManagerImpl.getInstance().commit();
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
SimpleJtaTransactionManagerImpl.getInstance().begin();
|
||||||
|
|
||||||
|
newEntityManager();
|
||||||
|
em = getEntityManager();
|
||||||
|
ite = em.find(IntTestEntity.class, id1);
|
||||||
|
ite.setNumber(20);
|
||||||
|
|
||||||
|
SimpleJtaTransactionManagerImpl.getInstance().commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "initData")
|
||||||
|
public void testRevisionsCounts() throws Exception {
|
||||||
|
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(IntTestEntity.class, id1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dependsOnMethods = "initData")
|
||||||
|
public void testHistoryOfId1() {
|
||||||
|
IntTestEntity ver1 = new IntTestEntity(10, id1);
|
||||||
|
IntTestEntity ver2 = new IntTestEntity(20, id1);
|
||||||
|
|
||||||
|
assert getAuditReader().find(IntTestEntity.class, id1, 1).equals(ver1);
|
||||||
|
assert getAuditReader().find(IntTestEntity.class, id1, 2).equals(ver2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,10 +12,10 @@
|
||||||
<property name="format_sql">true</property>
|
<property name="format_sql">true</property>
|
||||||
|
|
||||||
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
|
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
|
||||||
<property name="connection.url">jdbc:h2:mem:envers</property>
|
|
||||||
<property name="connection.driver_class">org.h2.Driver</property>
|
<property name="connection.driver_class">org.h2.Driver</property>
|
||||||
<property name="connection.username">sa</property>
|
<property name="connection.username">sa</property>
|
||||||
<property name="connection.password"></property>
|
<property name="connection.password"></property>
|
||||||
|
<!-- The connection URL is set in AbstractEntityTest -->
|
||||||
|
|
||||||
<!--<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>-->
|
<!--<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>-->
|
||||||
<!--<property name="connection.url">jdbc:mysql:///hibernate_tests?useUnicode=true&characterEncoding=UTF-8</property>-->
|
<!--<property name="connection.url">jdbc:mysql:///hibernate_tests?useUnicode=true&characterEncoding=UTF-8</property>-->
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
<package name="org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited2.subclass" />
|
<package name="org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited2.subclass" />
|
||||||
<package name="org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited2.joined" />
|
<package name="org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited2.joined" />
|
||||||
<package name="org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited2.union" />
|
<package name="org.hibernate.envers.test.integration.interfaces.hbm.propertiesAudited2.union" />
|
||||||
|
<package name="org.hibernate.envers.test.integration.jta" />
|
||||||
<package name="org.hibernate.envers.test.integration.manytomany" />
|
<package name="org.hibernate.envers.test.integration.manytomany" />
|
||||||
<package name="org.hibernate.envers.test.integration.manytomany.biowned" />
|
<package name="org.hibernate.envers.test.integration.manytomany.biowned" />
|
||||||
<package name="org.hibernate.envers.test.integration.manytomany.inverseToSuperclass" />
|
<package name="org.hibernate.envers.test.integration.manytomany.inverseToSuperclass" />
|
||||||
|
|
Loading…
Reference in New Issue