/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.compass.core.transaction;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.compass.core.CompassException;
import org.compass.core.CompassSession;
import org.compass.core.config.CompassEnvironment;
import org.compass.core.spi.InternalCompassSession;
/**
* @author kimchy
*/
public abstract class AbstractJTATransaction extends AbstractTransaction {
private static final Log log = LogFactory.getLog(AbstractJTATransaction.class);
private UserTransaction ut;
/**
* Did we start the JTA transaction
*/
private boolean newTransaction;
/**
* Is this the up most level controlling the Compass transaction
*/
private boolean controllingNewTransaction = false;
private boolean commitFailed;
private InternalCompassSession session;
public AbstractJTATransaction(UserTransaction ut, TransactionFactory transactionFactory) {
super(transactionFactory);
this.ut = ut;
}
public void begin(InternalCompassSession session, TransactionManager transactionManager) throws CompassException {
try {
this.session = session;
controllingNewTransaction = true;
newTransaction = ut.getStatus() == Status.STATUS_NO_TRANSACTION;
if (newTransaction) {
if (log.isDebugEnabled()) {
log.debug("Beginning new JTA transaction, and a new compass transaction on thread ["
+ Thread.currentThread().getName() + "]");
}
session.getSearchEngine().begin();
int timeout = session.getSettings().getSettingAsInt(CompassEnvironment.Transaction.TRANSACTION_TIMEOUT, -1);
if (timeout != -1) {
ut.setTransactionTimeout(timeout);
}
ut.begin();
} else {
// joining an exisiting transaction
session.getSearchEngine().begin();
if (log.isDebugEnabled()) {
log.debug("Joining an existing JTA transaction, starting a new compass transaction on thread ["
+ Thread.currentThread().getName() + "] with status [" + ut.getStatus() + "]");
}
}
javax.transaction.Transaction tx = transactionManager.getTransaction();
doBindToTransaction(tx, session, newTransaction);
} catch (Exception e) {
throw new TransactionException("Begin failed with exception", e);
}
setBegun(true);
}
protected abstract void doBindToTransaction(javax.transaction.Transaction tx, InternalCompassSession session,
boolean newTransaction) throws Exception;
/**
* Called by the factory when joining an already running compass transaction
*/
public void join(InternalCompassSession session) throws CompassException {
this.session = session;
controllingNewTransaction = false;
if (log.isDebugEnabled()) {
log.debug("Joining an existing compass transcation on thread [" + Thread.currentThread().getName() + "]");
}
}
protected void doCommit() throws CompassException {
if (!controllingNewTransaction) {
if (log.isDebugEnabled()) {
log.debug("Not committing JTA transaction since compass does not control it on thread ["
+ Thread.currentThread().getName() + "]");
}
return;
}
if (newTransaction) {
if (log.isDebugEnabled()) {
log.debug("Committing JTA transaction controlled by compass on thread ["
+ Thread.currentThread().getName() + "]");
}
try {
ut.commit();
} catch (Exception e) {
commitFailed = true;
// so the transaction is already rolled back, by JTA spec
throw new TransactionException("Commit failed", e);
}
} else {
if (log.isDebugEnabled()) {
log.debug("Commit called, let JTA synchronization commit the transaciton on thread ["
+ Thread.currentThread().getName() + "]");
}
}
}
protected void doRollback() throws CompassException {
try {
if (newTransaction) {
if (log.isDebugEnabled()) {
log.debug("Rolling back JTA transaction controlled by compass on thread [" + Thread.currentThread().getName() + "]");
}
if (!commitFailed)
ut.rollback();
} else {
if (log.isDebugEnabled()) {
log.debug("Marking JTA transaction as rolled back since compass controlls it on thread [" +
Thread.currentThread().getName() + "]");
}
ut.setRollbackOnly();
}
} catch (Exception e) {
throw new TransactionException("Rollback failed with exception", e);
}
}
public boolean wasRolledBack() throws TransactionException {
if (!isBegun())
return false;
if (commitFailed)
return true;
final int status;
try {
status = ut.getStatus();
} catch (SystemException 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_MARKED_ROLLBACK || status == Status.STATUS_ROLLING_BACK
|| status == Status.STATUS_ROLLEDBACK;
}
}
public boolean wasCommitted() throws TransactionException {
if (!isBegun() || commitFailed)
return false;
final int status;
try {
status = ut.getStatus();
} catch (SystemException 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;
}
}
public CompassSession getSession() {
return this.session;
}
}