Author: epbernard
Date: 2010-10-11 14:18:15 -0400 (Mon, 11 Oct 2010)
New Revision: 20803
Added:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/engine/TransactionSynchronizationTest.java
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/EventSourceTransactionContext.java
Log:
HSEARCH-606 Do not register for tx synchronization on local tx
When the transaction is local (ie the TransactionManager is null - not great but I
don't have a better approach atm), avoid registering the Synchronization event to the
transaction and exclusively use the actionQueue.registerProcess.
Modified:
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/EventSourceTransactionContext.java
===================================================================
---
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/EventSourceTransactionContext.java 2010-10-11
15:00:05 UTC (rev 20802)
+++
search/trunk/hibernate-search/src/main/java/org/hibernate/search/backend/impl/EventSourceTransactionContext.java 2010-10-11
18:18:15 UTC (rev 20803)
@@ -27,6 +27,7 @@
import java.io.Serializable;
import javax.transaction.Status;
import javax.transaction.Synchronization;
+import javax.transaction.TransactionManager;
import org.slf4j.Logger;
@@ -92,12 +93,19 @@
* 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.
*/
-
final ActionQueue actionQueue = eventSource.getActionQueue();
- actionQueue.registerProcess( new DelegateToSynchronizationOnBeforeTx( synchronization
) );
- eventSource.getTransaction().registerSynchronization(
- new BeforeCommitSynchronizationDelegator( synchronization )
- );
+ boolean isLocal = isLocalTransaction();
+ if ( isLocal ) {
+ //if local tx never use Synchronization
+ actionQueue.registerProcess( new DelegateToSynchronizationOnBeforeTx( synchronization
) );
+ }
+ else {
+ //TODO could we remove the action queue registration in this case?
+ actionQueue.registerProcess( new DelegateToSynchronizationOnBeforeTx( synchronization
) );
+ eventSource.getTransaction().registerSynchronization(
+ new BeforeCommitSynchronizationDelegator( synchronization )
+ );
+ }
//executed in all environments
actionQueue.registerProcess( new DelegateToSynchronizationOnAfterTx( synchronization )
);
@@ -116,7 +124,13 @@
}
}
}
-
+
+ private boolean isLocalTransaction() {
+ //TODO make it better but I don't know how we can optimize it.
+ final TransactionManager transactionManager =
eventSource.getFactory().getTransactionManager();
+ return transactionManager == null;
+ }
+
private FullTextIndexEventListener getIndexWorkFlushEventListener() {
if ( this.flushListener != null) {
//for the "transient" case: might have been nullified.
Added:
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/engine/TransactionSynchronizationTest.java
===================================================================
---
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/engine/TransactionSynchronizationTest.java
(rev 0)
+++
search/trunk/hibernate-search/src/test/java/org/hibernate/search/test/engine/TransactionSynchronizationTest.java 2010-10-11
18:18:15 UTC (rev 20803)
@@ -0,0 +1,67 @@
+package org.hibernate.search.test.engine;
+
+import org.hibernate.Transaction;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.FieldBridge;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.bridge.builtin.ClassBridge;
+import org.hibernate.search.test.SearchTestCase;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class TransactionSynchronizationTest extends SearchTestCase {
+
+ public void testProperExceptionPropagation() throws Exception {
+ /**
+ * This test relies on the fact that a bridge accepting an incompatible type raise
+ * an exception when used.
+ */
+ FullTextSession fts = Search.getFullTextSession( openSession() );
+ boolean raised = false;
+ final Transaction transaction = fts.beginTransaction();
+ try {
+ Test test = new Test();
+ test.setIncorrectType("not a class");
+ fts.persist(test);
+ transaction.commit();
+ fail("An exception should have been raised");
+ }
+ catch (Exception e) {
+ //good
+ raised = true;
+ transaction.rollback();
+ }
+ assertTrue("An exception should have been raised", raised);
+ fts.close();
+ }
+
+ @Override
+ protected Class<?>[] getAnnotatedClasses() {
+ return new Class<?>[] {
+ Test.class
+ };
+ }
+
+ @Entity
+ @Indexed
+ @Table(name="Test007")
+ public static class Test {
+ @Id @GeneratedValue
+ public Integer getId() { return id; }
+ public void setId(Integer id) { this.id = id; }
+ private Integer id;
+
+ @Field(bridge = @FieldBridge(impl = ClassBridge.class))
+ public String getIncorrectType() { return incorrectType; }
+ public void setIncorrectType(String incorrectType) { this.incorrectType =
incorrectType; }
+ private String incorrectType;
+ }
+}
Show replies by date