Author: adamw
Date: 2010-07-10 08:48:19 -0400 (Sat, 10 Jul 2010)
New Revision: 19928
Added:
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/jta/
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/jta/JtaExceptionListener.java
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/jta/JtaTransaction.java
Modified:
core/trunk/envers/pom.xml
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java
core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java
core/trunk/envers/src/test/resources/hibernate.test.cfg.xml
core/trunk/envers/src/test/resources/testng.xml
Log:
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
Modified: core/trunk/envers/pom.xml
===================================================================
--- core/trunk/envers/pom.xml 2010-07-09 18:03:11 UTC (rev 19927)
+++ core/trunk/envers/pom.xml 2010-07-10 12:48:19 UTC (rev 19928)
@@ -118,6 +118,12 @@
<artifactId>javassist</artifactId>
<scope>test</scope>
</dependency>
+ <!-- For JTA tests -->
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-testing</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<dependencyManagement>
@@ -139,6 +145,11 @@
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
+ <artifactId>hibernate-testing</artifactId>
+ <version>${version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
<artifactId>hibernate-tools</artifactId>
<version>3.2.0.ga</version>
</dependency>
Modified:
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java
===================================================================
---
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java 2010-07-09
18:03:11 UTC (rev 19927)
+++
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcess.java 2010-07-10
12:48:19 UTC (rev 19928)
@@ -37,11 +37,14 @@
import org.hibernate.FlushMode;
import org.hibernate.Session;
+import javax.transaction.Synchronization;
+
/**
* @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 SessionImplementor session;
private final LinkedList<AuditWorkUnit> workUnits;
private final Queue<AuditWorkUnit> undoQueue;
@@ -49,8 +52,9 @@
private Object revisionData;
- public AuditProcess(RevisionInfoGenerator revisionInfoGenerator) {
+ public AuditProcess(RevisionInfoGenerator revisionInfoGenerator, SessionImplementor
session) {
this.revisionInfoGenerator = revisionInfoGenerator;
+ this.session = session;
workUnits = new LinkedList<AuditWorkUnit>();
undoQueue = new LinkedList<AuditWorkUnit>();
@@ -153,4 +157,12 @@
session.flush();
}
}
+
+ // Synchronization methods
+
+ public void beforeCompletion() {
+ doBeforeTransactionCompletion(session);
+ }
+
+ public void afterCompletion(int status) { }
}
Modified:
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java
===================================================================
---
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java 2010-07-09
18:03:11 UTC (rev 19927)
+++
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/AuditProcessManager.java 2010-07-10
12:48:19 UTC (rev 19928)
@@ -52,10 +52,22 @@
AuditProcess auditProcess = auditProcesses.get(transaction);
if (auditProcess == null) {
// 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);
+ /*
+ * 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.getTransaction().registerSynchronization(auditProcess);
+
session.getActionQueue().registerProcess(new
AfterTransactionCompletionProcess() {
public void doAfterTransactionCompletion(boolean success,
SessionImplementor session) {
auditProcesses.remove(transaction);
Modified:
core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java
===================================================================
---
core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java 2010-07-09
18:03:11 UTC (rev 19927)
+++
core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java 2010-07-10
12:48:19 UTC (rev 19928)
@@ -27,9 +27,13 @@
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
+import org.hibernate.cfg.Environment;
+import org.hibernate.ejb.AvailableSettings;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.hibernate.envers.event.AuditEventListener;
+import org.hibernate.testing.tm.ConnectionProviderImpl;
+import org.hibernate.testing.tm.TransactionManagerLookupImpl;
import org.testng.annotations.*;
import org.hibernate.ejb.Ejb3Configuration;
@@ -89,11 +93,15 @@
initListeners();
}
+ cfg.configure("hibernate.test.cfg.xml");
+
if (auditStrategy != null && !"".equals(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);
emf = cfg.buildEntityManagerFactory();
@@ -117,4 +125,10 @@
public Ejb3Configuration getCfg() {
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");
+ }
}
Added:
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/jta/JtaExceptionListener.java
===================================================================
---
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/jta/JtaExceptionListener.java
(rev 0)
+++
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/jta/JtaExceptionListener.java 2010-07-10
12:48:19 UTC (rev 19928)
@@ -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();
+ }
+}
Added:
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/jta/JtaTransaction.java
===================================================================
---
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/jta/JtaTransaction.java
(rev 0)
+++
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/jta/JtaTransaction.java 2010-07-10
12:48:19 UTC (rev 19928)
@@ -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);
+ }
+}
Modified: core/trunk/envers/src/test/resources/hibernate.test.cfg.xml
===================================================================
--- core/trunk/envers/src/test/resources/hibernate.test.cfg.xml 2010-07-09 18:03:11 UTC
(rev 19927)
+++ core/trunk/envers/src/test/resources/hibernate.test.cfg.xml 2010-07-10 12:48:19 UTC
(rev 19928)
@@ -12,10 +12,10 @@
<property name="format_sql">true</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.username">sa</property>
<property name="connection.password"></property>
+ <!-- The connection URL is set in AbstractEntityTest -->
<!--<property
name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>-->
<!--<property
name="connection.url">jdbc:mysql:///hibernate_tests?useUnicode=true&characterEncoding=UTF-8</property>-->
@@ -46,4 +46,4 @@
<listener class="org.hibernate.envers.event.AuditEventListener"
/>
</event>-->
</session-factory>
-</hibernate-configuration>
\ No newline at end of file
+</hibernate-configuration>
Modified: core/trunk/envers/src/test/resources/testng.xml
===================================================================
--- core/trunk/envers/src/test/resources/testng.xml 2010-07-09 18:03:11 UTC (rev 19927)
+++ core/trunk/envers/src/test/resources/testng.xml 2010-07-10 12:48:19 UTC (rev 19928)
@@ -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.joined"
/>
<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.biowned" />
<package
name="org.hibernate.envers.test.integration.manytomany.inverseToSuperclass"
/>