2
* Hibernate, Relational Persistence for Idiomatic Java
4
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5
* indicated by the @author tags or express copyright attribution
6
* statements applied by the authors. All third-party contributions are
7
* distributed under license by Red Hat Middleware LLC.
9
* This copyrighted material is made available to anyone wishing to use, modify,
10
* copy, or redistribute it subject to the terms and conditions of the GNU
11
* Lesser General Public License, as published by the Free Software Foundation.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
18
* You should have received a copy of the GNU Lesser General Public License
19
* along with this distribution; if not, write to:
20
* Free Software Foundation, Inc.
21
* 51 Franklin Street, Fifth Floor
22
* Boston, MA 02110-1301 USA
25
package org.hibernate.transaction;
27
import javax.transaction.Status;
28
import javax.transaction.Synchronization;
29
import javax.transaction.SystemException;
30
import javax.transaction.TransactionManager;
31
import javax.transaction.UserTransaction;
33
import org.slf4j.Logger;
34
import org.slf4j.LoggerFactory;
36
import org.hibernate.HibernateException;
37
import org.hibernate.Transaction;
38
import org.hibernate.TransactionException;
39
import org.hibernate.jdbc.JDBCContext;
40
import org.hibernate.util.JTAHelper;
43
* {@link Transaction} implementation based on transaction management through
44
* a JTA {@link UserTransaction}. Similar to {@link CMTTransaction}, except
45
* here we are actually managing the transactions through the Hibernate
46
* transaction mechanism.
49
* @author Steve Ebersole
50
* @author Les Hazlewood
52
public class JTATransaction implements Transaction {
54
private static final Logger log = LoggerFactory.getLogger( JTATransaction.class );
56
private final JDBCContext jdbcContext;
57
private final TransactionFactory.Context transactionContext;
59
private UserTransaction userTransaction;
60
private boolean newTransaction;
61
private boolean begun;
62
private boolean commitFailed;
63
private boolean commitSucceeded;
64
private boolean callback;
66
public JTATransaction(
67
UserTransaction userTransaction,
68
JDBCContext jdbcContext,
69
TransactionFactory.Context transactionContext) {
70
this.jdbcContext = jdbcContext;
71
this.transactionContext = transactionContext;
72
this.userTransaction = userTransaction;
78
public void begin() throws HibernateException {
83
throw new TransactionException( "cannot re-start transaction after failed commit" );
89
newTransaction = userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION;
90
if ( newTransaction ) {
91
userTransaction.begin();
92
log.debug( "Began a new JTA transaction" );
95
catch ( Exception e ) {
96
log.error( "JTA transaction begin failed", e );
97
throw new TransactionException( "JTA transaction begin failed", e );
100
/*if (newTransaction) {
101
// don't need a synchronization since we are committing
102
// or rolling back the transaction ourselves - assuming
103
// that we do no work in beforeTransactionCompletion()
104
synchronization = false;
107
boolean synchronization = jdbcContext.registerSynchronizationIfPossible();
109
if ( !newTransaction && !synchronization ) {
110
log.warn( "You should set hibernate.transaction.manager_lookup_class if cache is enabled" );
113
if ( !synchronization ) {
114
//if we could not register a synchronization,
115
//do the before/after completion callbacks
116
//ourself (but we need to let jdbcContext
117
//know that this is what we are going to
118
//do, so it doesn't keep trying to register
120
callback = jdbcContext.registerCallbackIfNecessary();
124
commitSucceeded = false;
126
jdbcContext.afterTransactionBegin( this );
132
public void commit() throws HibernateException {
134
throw new TransactionException( "Transaction not successfully started" );
137
log.debug( "commit" );
139
boolean flush = !transactionContext.isFlushModeNever()
140
&& ( callback || !transactionContext.isFlushBeforeCompletionEnabled() );
143
transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
146
if ( callback && newTransaction ) {
147
jdbcContext.beforeTransactionCompletion( this );
152
if ( newTransaction ) {
154
userTransaction.commit();
155
commitSucceeded = true;
156
log.debug( "Committed JTA UserTransaction" );
158
catch ( Exception e ) {
159
commitFailed = true; // so the transaction is already rolled back, by JTA spec
160
log.error( "JTA commit failed", e );
161
throw new TransactionException( "JTA commit failed: ", e );
164
afterCommitRollback();
168
// this one only really needed for badly-behaved applications!
169
// (if the TransactionManager has a Sychronization registered,
171
// (actually we do need it for downgrading locks)
172
afterCommitRollback();
180
public void rollback() throws HibernateException {
181
if ( !begun && !commitFailed ) {
182
throw new TransactionException( "Transaction not successfully started" );
185
log.debug( "rollback" );
190
catch ( Exception e ) {
191
// swallow it, and continue to roll back JTA transaction
192
log.error( "could not close session during rollback", e );
196
if ( newTransaction ) {
197
if ( !commitFailed ) {
198
userTransaction.rollback();
199
log.debug( "Rolled back JTA UserTransaction" );
203
userTransaction.setRollbackOnly();
204
log.debug( "set JTA UserTransaction to rollback only" );
207
catch ( Exception e ) {
208
log.error( "JTA rollback failed", e );
209
throw new TransactionException( "JTA rollback failed", e );
212
afterCommitRollback();
216
private static final int NULL = Integer.MIN_VALUE;
218
private void afterCommitRollback() throws TransactionException {
221
// this method is a noop if there is a Synchronization!
223
if ( !newTransaction ) {
224
log.warn( "You should set hibernate.transaction.manager_lookup_class if cache is enabled" );
228
status = userTransaction.getStatus();
230
catch ( Exception e ) {
231
log.error( "Could not determine transaction status after commit", e );
232
throw new TransactionException( "Could not determine transaction status after commit", e );
235
jdbcContext.afterTransactionCompletion( status == Status.STATUS_COMMITTED, this );
243
public boolean wasRolledBack() throws TransactionException {
246
status = userTransaction.getStatus();
248
catch ( SystemException se ) {
249
log.error( "Could not determine transaction status", se );
250
throw new TransactionException( "Could not determine transaction status", se );
252
if ( status == Status.STATUS_UNKNOWN ) {
253
throw new TransactionException( "Could not determine transaction status" );
256
return JTAHelper.isRollback( status );
263
public boolean wasCommitted() throws TransactionException {
266
status = userTransaction.getStatus();
268
catch ( SystemException se ) {
269
log.error( "Could not determine transaction status", se );
270
throw new TransactionException( "Could not determine transaction status: ", se );
272
if ( status == Status.STATUS_UNKNOWN ) {
273
throw new TransactionException( "Could not determine transaction status" );
276
return status == Status.STATUS_COMMITTED;
283
public boolean isActive() throws TransactionException {
284
if ( !begun || commitFailed || commitSucceeded ) {
290
status = userTransaction.getStatus();
292
catch ( SystemException se ) {
293
log.error( "Could not determine transaction status", se );
294
throw new TransactionException( "Could not determine transaction status: ", se );
296
if ( status == Status.STATUS_UNKNOWN ) {
297
throw new TransactionException( "Could not determine transaction status" );
300
return status == Status.STATUS_ACTIVE;
307
public void registerSynchronization(Synchronization sync) throws HibernateException {
308
if ( getTransactionManager() == null ) {
309
throw new IllegalStateException( "JTA TransactionManager not available" );
313
getTransactionManager().getTransaction().registerSynchronization( sync );
315
catch ( Exception e ) {
316
throw new TransactionException( "could not register synchronization", e );
322
* Getter for property 'transactionManager'.
324
* @return Value for property 'transactionManager'.
326
private TransactionManager getTransactionManager() {
327
return transactionContext.getFactory().getTransactionManager();
330
private void closeIfRequired() throws HibernateException {
331
boolean close = callback &&
332
transactionContext.shouldAutoClose() &&
333
!transactionContext.isClosed();
335
transactionContext.managedClose();
342
public void setTimeout(int seconds) {
344
userTransaction.setTransactionTimeout( seconds );
346
catch ( SystemException se ) {
347
throw new TransactionException( "could not set transaction timeout", se );
352
* Getter for property 'userTransaction'.
354
* @return Value for property 'userTransaction'.
356
protected UserTransaction getUserTransaction() {
357
return userTransaction;