/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.transaction;
import static java.lang.System.identityHashCode;
import org.mule.runtime.core.api.MuleContext;
import org.mule.runtime.core.api.transaction.Transaction;
import org.mule.runtime.api.tx.TransactionException;
import org.mule.runtime.core.config.i18n.CoreMessages;
import org.mule.runtime.core.context.notification.TransactionNotification;
import org.mule.runtime.core.util.UUID;
import java.text.MessageFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This base class provides low level features for transactions.
*/
public abstract class AbstractTransaction implements Transaction {
protected final transient Logger logger = LoggerFactory.getLogger(getClass());
protected String id = UUID.getUUID();
protected int timeout;
protected MuleContext muleContext;
protected AbstractTransaction(MuleContext muleContext) {
this.muleContext = muleContext;
}
public boolean isRollbackOnly() throws TransactionException {
int status = getStatus();
return status == STATUS_MARKED_ROLLBACK || status == STATUS_ROLLEDBACK || status == STATUS_ROLLING_BACK;
}
public boolean isBegun() throws TransactionException {
int status = getStatus();
return status != STATUS_NO_TRANSACTION && status != STATUS_UNKNOWN;
}
public boolean isRolledBack() throws TransactionException {
return getStatus() == STATUS_ROLLEDBACK;
}
public boolean isCommitted() throws TransactionException {
return getStatus() == STATUS_COMMITTED;
}
public void begin() throws TransactionException {
logger.debug("Beginning transaction " + identityHashCode(this));
doBegin();
TransactionCoordination.getInstance().bindTransaction(this);
fireNotification(new TransactionNotification(this, TransactionNotification.TRANSACTION_BEGAN, getApplicationName()));
}
public void commit() throws TransactionException {
try {
logger.debug("Committing transaction " + identityHashCode(this));
if (isRollbackOnly()) {
throw new IllegalTransactionStateException(CoreMessages.transactionMarkedForRollback());
}
doCommit();
fireNotification(new TransactionNotification(this, TransactionNotification.TRANSACTION_COMMITTED, getApplicationName()));
} finally {
TransactionCoordination.getInstance().unbindTransaction(this);
}
}
public void rollback() throws TransactionException {
try {
logger.debug("Rolling back transaction " + identityHashCode(this));
setRollbackOnly();
doRollback();
fireNotification(new TransactionNotification(this, TransactionNotification.TRANSACTION_ROLLEDBACK, getApplicationName()));
} finally {
unbindTransaction();
}
}
/**
* Unbind this transaction when complete
*/
protected void unbindTransaction() throws TransactionException {
TransactionCoordination.getInstance().unbindTransaction(this);
}
/**
* Really begin the transaction. Note that resources are enlisted yet.
*
* @throws TransactionException
*/
protected abstract void doBegin() throws TransactionException;
/**
* Commit the transaction on the underlying resource
*
* @throws TransactionException
*/
protected abstract void doCommit() throws TransactionException;
/**
* Rollback the transaction on the underlying resource
*
* @throws TransactionException
*/
protected abstract void doRollback() throws TransactionException;
/**
* Fires a server notification to all registered
* {@link org.mule.runtime.core.api.context.notification.TransactionNotificationListener}s.
*
*/
protected void fireNotification(TransactionNotification notification) {
// TODO profile this piece of code
muleContext.fireNotification(notification);
}
public boolean isXA() {
return false;
}
public void resume() throws TransactionException {
throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(this));
}
public javax.transaction.Transaction suspend() throws TransactionException {
throw new IllegalTransactionStateException(CoreMessages.notMuleXaTransaction(this));
}
public String getId() {
return id;
}
@Override
public String toString() {
int status;
try {
status = getStatus();
} catch (TransactionException e) {
status = -1;
}
return MessageFormat.format("{0}[id={1} , status={2}]", getClass().getName(), id, status);
}
private String getApplicationName() {
return muleContext.getConfiguration().getId();
}
@Override
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
}