All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.transaction.JTATransaction Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * 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.transaction;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.Transaction;
import org.hibernate.TransactionException;
import org.hibernate.jdbc.JDBCContext;
import org.hibernate.util.JTAHelper;

/**
 * {@link Transaction} implementation based on transaction management through
 * a JTA {@link UserTransaction}.  Similar to {@link CMTTransaction}, except
 * here we are actually managing the transactions through the Hibernate
 * transaction mechanism.
 * 

* Instances check to see if there is an existing JTA transaction. If none * exists, a new transaction is started; if one exists, all work is done in the * existing context. The following properties are used to locate the underlying * {@link UserTransaction}:

    *
  • hibernate.jndi.url : JNDI initial context URL
  • *
  • hibernate.jndi.class : JNDI provider class
  • *
  • jta.UserTransaction : JNDI namespace
  • *
* * @author Gavin King */ public class JTATransaction implements Transaction { private static final Logger log = LoggerFactory.getLogger(JTATransaction.class); private final JDBCContext jdbcContext; private final TransactionFactory.Context transactionContext; private UserTransaction ut; private boolean newTransaction; private boolean begun; private boolean commitFailed; private boolean commitSucceeded; private boolean callback; public JTATransaction( InitialContext context, String utName, JDBCContext jdbcContext, TransactionFactory.Context transactionContext ) { this.jdbcContext = jdbcContext; this.transactionContext = transactionContext; log.debug("Looking for UserTransaction under: " + utName); try { ut = (UserTransaction) context.lookup(utName); } catch (NamingException ne) { log.error("Could not find UserTransaction in JNDI", ne); throw new TransactionException("Could not find UserTransaction in JNDI: ", ne); } if (ut==null) { throw new AssertionFailure("A naming service lookup returned null"); } log.debug("Obtained UserTransaction"); } /** * {@inheritDoc} */ public void begin() throws HibernateException { if (begun) { return; } if (commitFailed) { throw new TransactionException("cannot re-start transaction after failed commit"); } log.debug("begin"); try { newTransaction = ut.getStatus() == Status.STATUS_NO_TRANSACTION; if (newTransaction) { ut.begin(); log.debug("Began a new JTA transaction"); } } catch (Exception e) { log.error("JTA transaction begin failed", e); throw new TransactionException("JTA transaction begin failed", e); } /*if (newTransaction) { // don't need a synchronization since we are committing // or rolling back the transaction ourselves - assuming // that we do no work in beforeTransactionCompletion() synchronization = false; }*/ boolean synchronization = jdbcContext.registerSynchronizationIfPossible(); if ( !newTransaction && !synchronization ) { log.warn("You should set hibernate.transaction.manager_lookup_class if cache is enabled"); } if (!synchronization) { //if we could not register a synchronization, //do the before/after completion callbacks //ourself (but we need to let jdbcContext //know that this is what we are going to //do, so it doesn't keep trying to register //synchronizations) callback = jdbcContext.registerCallbackIfNecessary(); } begun = true; commitSucceeded = false; jdbcContext.afterTransactionBegin(this); } /** * {@inheritDoc} */ public void commit() throws HibernateException { if (!begun) { throw new TransactionException("Transaction not successfully started"); } log.debug("commit"); boolean flush = !transactionContext.isFlushModeNever() && ( callback || !transactionContext.isFlushBeforeCompletionEnabled() ); if (flush) { transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback() } if (callback && newTransaction) { jdbcContext.beforeTransactionCompletion(this); } closeIfRequired(); if (newTransaction) { try { ut.commit(); commitSucceeded = true; log.debug("Committed JTA UserTransaction"); } catch (Exception e) { commitFailed = true; // so the transaction is already rolled back, by JTA spec log.error("JTA commit failed", e); throw new TransactionException("JTA commit failed: ", e); } finally { afterCommitRollback(); } } else { // this one only really needed for badly-behaved applications! // (if the TransactionManager has a Sychronization registered, // its a noop) // (actually we do need it for downgrading locks) afterCommitRollback(); } } /** * {@inheritDoc} */ public void rollback() throws HibernateException { if (!begun && !commitFailed) { throw new TransactionException("Transaction not successfully started"); } log.debug("rollback"); /*if (!synchronization && newTransaction && !commitFailed) { jdbcContext.beforeTransactionCompletion(this); }*/ try { closeIfRequired(); } catch (Exception e) { log.error("could not close session during rollback", e); //swallow it, and continue to roll back JTA transaction } try { if (newTransaction) { if (!commitFailed) { ut.rollback(); log.debug("Rolled back JTA UserTransaction"); } } else { ut.setRollbackOnly(); log.debug("set JTA UserTransaction to rollback only"); } } catch (Exception e) { log.error("JTA rollback failed", e); throw new TransactionException("JTA rollback failed", e); } finally { afterCommitRollback(); } } private static final int NULL = Integer.MIN_VALUE; private void afterCommitRollback() throws TransactionException { begun = false; if (callback) { // this method is a noop if there is a Synchronization! if (!newTransaction) { log.warn("You should set hibernate.transaction.manager_lookup_class if cache is enabled"); } int status=NULL; try { status = ut.getStatus(); } catch (Exception e) { log.error("Could not determine transaction status after commit", e); throw new TransactionException("Could not determine transaction status after commit", e); } finally { /*if (status!=Status.STATUS_COMMITTED && status!=Status.STATUS_ROLLEDBACK) { log.warn("Transaction not complete - you should set hibernate.transaction.manager_lookup_class if cache is enabled"); //throw exception?? }*/ jdbcContext.afterTransactionCompletion(status==Status.STATUS_COMMITTED, this); } } } /** * {@inheritDoc} */ public boolean wasRolledBack() throws TransactionException { //if (!begun) return false; //if (commitFailed) return true; final int status; try { status = ut.getStatus(); } catch (SystemException se) { log.error("Could not determine transaction status", se); throw new TransactionException("Could not determine transaction status", se); } if (status==Status.STATUS_UNKNOWN) { throw new TransactionException("Could not determine transaction status"); } else { return JTAHelper.isRollback(status); } } /** * {@inheritDoc} */ public boolean wasCommitted() throws TransactionException { //if (!begun || commitFailed) return false; final int status; try { status = ut.getStatus(); } catch (SystemException se) { log.error("Could not determine transaction status", se); throw new TransactionException("Could not determine transaction status: ", se); } if (status==Status.STATUS_UNKNOWN) { throw new TransactionException("Could not determine transaction status"); } else { return status==Status.STATUS_COMMITTED; } } /** * {@inheritDoc} */ public boolean isActive() throws TransactionException { if (!begun || commitFailed || commitSucceeded) return false; final int status; try { status = ut.getStatus(); } catch (SystemException se) { log.error("Could not determine transaction status", se); throw new TransactionException("Could not determine transaction status: ", se); } if (status==Status.STATUS_UNKNOWN) { throw new TransactionException("Could not determine transaction status"); } else { return status==Status.STATUS_ACTIVE; } } /** * {@inheritDoc} */ public void registerSynchronization(Synchronization sync) throws HibernateException { if (getTransactionManager()==null) { throw new IllegalStateException("JTA TransactionManager not available"); } else { try { getTransactionManager().getTransaction().registerSynchronization(sync); } catch (Exception e) { throw new TransactionException("could not register synchronization", e); } } } /** * Getter for property 'transactionManager'. * * @return Value for property 'transactionManager'. */ private TransactionManager getTransactionManager() { return transactionContext.getFactory().getTransactionManager(); } private void closeIfRequired() throws HibernateException { boolean close = callback && transactionContext.shouldAutoClose() && !transactionContext.isClosed(); if ( close ) { transactionContext.managedClose(); } } /** * {@inheritDoc} */ public void setTimeout(int seconds) { try { ut.setTransactionTimeout(seconds); } catch (SystemException se) { throw new TransactionException("could not set transaction timeout", se); } } /** * Getter for property 'userTransaction'. * * @return Value for property 'userTransaction'. */ protected UserTransaction getUserTransaction() { return ut; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy