/**
* Copyright 2014-2016 yangming.liu<bytefox@126.com>.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
package org.bytesoft.bytetcc;
import java.io.Serializable;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import org.bytesoft.bytejta.supports.wire.RemoteCoordinator;
import org.bytesoft.compensable.CompensableBeanFactory;
import org.bytesoft.compensable.CompensableManager;
import org.bytesoft.compensable.CompensableTransaction;
import org.bytesoft.compensable.TransactionContext;
import org.bytesoft.compensable.UserCompensable;
import org.bytesoft.compensable.aware.CompensableBeanFactoryAware;
import org.bytesoft.transaction.TransactionManager;
import org.bytesoft.transaction.TransactionRepository;
import org.bytesoft.transaction.xa.TransactionXid;
import org.bytesoft.transaction.xa.XidFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UserCompensableImpl implements UserCompensable, Referenceable, Serializable, CompensableBeanFactoryAware {
private static final long serialVersionUID = 1L;
static final Logger logger = LoggerFactory.getLogger(UserCompensableImpl.class);
private CompensableBeanFactory beanFactory;
private TransactionManager transactionManager;
public TransactionXid compensableBegin() throws NotSupportedException, SystemException {
RemoteCoordinator compensableCoordinator = this.beanFactory.getCompensableCoordinator();
CompensableManager tompensableManager = this.beanFactory.getCompensableManager();
XidFactory compensableXidFactory = this.beanFactory.getCompensableXidFactory();
TransactionContext compensableContext = new TransactionContext();
CompensableTransactionImpl compensable = (CompensableTransactionImpl) tompensableManager
.getCompensableTransactionQuietly();
if (compensable != null) {
throw new NotSupportedException();
}
TransactionXid compensableXid = compensableXidFactory.createGlobalXid();
compensableContext.setCoordinator(true);
compensableContext.setPropagated(true);
compensableContext.setCompensable(true);
compensableContext.setXid(compensableXid);
compensableContext.setPropagatedBy(compensableCoordinator.getIdentifier());
compensable = new CompensableTransactionImpl(compensableContext);
compensable.setBeanFactory(this.beanFactory);
try {
compensableCoordinator.start(compensableContext, XAResource.TMNOFLAGS);
} catch (XAException ex) {
logger.error("Error occurred while beginning an compensable transaction!", ex);
throw new SystemException(ex.getMessage());
}
return compensableXid;
}
public void begin() throws NotSupportedException, SystemException {
this.transactionManager.begin();
}
public void commit() throws HeuristicMixedException, HeuristicRollbackException, IllegalStateException, RollbackException,
SecurityException, SystemException {
this.transactionManager.commit();
}
public void compensableRecoveryBegin(Xid xid) throws NotSupportedException, SystemException {
CompensableManager compensableManager = this.beanFactory.getCompensableManager();
TransactionRepository transactionRepository = this.beanFactory.getCompensableRepository();
RemoteCoordinator compensableCoordinator = this.beanFactory.getCompensableCoordinator();
if (xid == null) {
throw new IllegalStateException();
} else if (TransactionXid.class.isInstance(xid) == false) {
throw new IllegalStateException();
} else if (xid.getFormatId() != XidFactory.TCC_FORMAT_ID) {
throw new IllegalStateException();
}
TransactionXid compensableXid = (TransactionXid) xid;
CompensableTransaction transaction = (CompensableTransaction) transactionRepository.getTransaction(compensableXid);
if (transaction == null) {
throw new IllegalStateException();
} else if (CompensableTransaction.class.isInstance(transaction) == false) {
throw new IllegalStateException();
}
CompensableTransaction compensable = compensableManager.getCompensableTransactionQuietly();
TransactionContext transactionContext = transaction.getTransactionContext();
if (transactionContext.isCoordinator() == false) {
throw new IllegalStateException();
} else if (transactionContext.isRecoveried()) {
try {
compensableCoordinator.start(transactionContext, XAResource.TMNOFLAGS);
} catch (XAException ex) {
logger.error("Error occurred while beginning an compensable transaction!", ex);
throw new SystemException(ex.getMessage());
}
} else if (compensable == null) {
throw new IllegalStateException();
} else if (compensable.equals(transaction) == false) {
throw new IllegalStateException();
}
}
public void compensableRecoveryCommit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
SecurityException, IllegalStateException, SystemException {
CompensableManager compensableManager = this.beanFactory.getCompensableManager();
CompensableTransaction compensable = compensableManager.getCompensableTransactionQuietly();
if (compensable == null) {
throw new IllegalStateException();
}
TransactionContext transactionContext = compensable.getTransactionContext();
if (transactionContext.isCoordinator() == false) {
throw new IllegalStateException();
}
this.invokeCompensableCommit(compensable);
}
public void compensableCommit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
SecurityException, IllegalStateException, SystemException {
CompensableManager tompensableManager = this.beanFactory.getCompensableManager();
CompensableTransaction compensable = (CompensableTransaction) tompensableManager.getCompensableTransactionQuietly();
if (compensable == null) {
throw new IllegalStateException();
}
TransactionContext transactionContext = compensable.getTransactionContext();
if (transactionContext.isCoordinator() == false) {
throw new IllegalStateException();
}
this.invokeCompensableCommit(compensable);
}
private void invokeCompensableCommit(CompensableTransaction compensable) throws RollbackException, HeuristicMixedException,
HeuristicRollbackException, SecurityException, IllegalStateException, SystemException {
RemoteCoordinator compensableCoordinator = this.beanFactory.getCompensableCoordinator();
TransactionContext compensableContext = compensable.getTransactionContext();
try {
compensableCoordinator.end(compensableContext, XAResource.TMSUCCESS);
} catch (XAException ex) {
logger.error("Error occurred while beginning an compensable transaction!", ex);
throw new SystemException(ex.getMessage());
}
boolean success = false;
try {
compensableCoordinator.commit(compensableContext.getXid(), true);
success = true;
} catch (XAException xaex) {
switch (xaex.errorCode) {
case XAException.XAER_NOTA:
throw new IllegalStateException();
case XAException.XA_HEURRB:
throw new HeuristicRollbackException();
case XAException.XA_HEURMIX:
throw new HeuristicMixedException();
case XAException.XAER_INVAL:
throw new IllegalStateException();
case XAException.XAER_RMERR:
case XAException.XAER_RMFAIL:
default:
throw new SystemException();
}
} finally {
if (success) {
try {
compensableCoordinator.forget(compensableContext.getXid());
} catch (XAException ex) {
switch (ex.errorCode) {
case XAException.XAER_INVAL:
throw new IllegalStateException();
case XAException.XAER_NOTA:
throw new IllegalStateException();
case XAException.XAER_RMERR:
default:
throw new SystemException();
}
}
} // end-if (success)
}
}
public void rollback() throws IllegalStateException, SecurityException, SystemException {
this.transactionManager.rollback();
}
public void compensableRecoveryRollback() throws IllegalStateException, SecurityException, SystemException {
CompensableManager compensableManager = this.beanFactory.getCompensableManager();
CompensableTransaction compensable = compensableManager.getCompensableTransactionQuietly();
if (compensable == null) {
throw new IllegalStateException();
}
TransactionContext transactionContext = compensable.getTransactionContext();
if (transactionContext.isCoordinator() == false) {
throw new IllegalStateException();
}
this.invokeCompensableRollback(compensable);
}
public void compensableRollback() throws IllegalStateException, SecurityException, SystemException {
CompensableManager tompensableManager = this.beanFactory.getCompensableManager();
CompensableTransaction compensable = (CompensableTransaction) tompensableManager.getCompensableTransactionQuietly();
if (compensable == null) {
throw new IllegalStateException();
}
TransactionContext transactionContext = compensable.getTransactionContext();
if (transactionContext.isCoordinator() == false) {
throw new IllegalStateException();
}
this.invokeCompensableRollback(compensable);
}
private void invokeCompensableRollback(CompensableTransaction compensable)
throws IllegalStateException, SecurityException, SystemException {
RemoteCoordinator compensableCoordinator = this.beanFactory.getCompensableCoordinator();
TransactionContext compensableContext = compensable.getTransactionContext();
try {
compensableCoordinator.end(compensableContext, XAResource.TMSUCCESS);
} catch (XAException ex) {
logger.error("Error occurred while beginning an compensable transaction!", ex);
throw new SystemException(ex.getMessage());
}
boolean success = false;
try {
compensableCoordinator.rollback(compensableContext.getXid());
success = true;
} catch (XAException xaex) {
switch (xaex.errorCode) {
case XAException.XAER_NOTA:
throw new IllegalStateException();
case XAException.XAER_INVAL:
throw new IllegalStateException();
case XAException.XAER_RMERR:
case XAException.XAER_RMFAIL:
default:
throw new SystemException();
}
} finally {
if (success) {
try {
compensableCoordinator.forget(compensableContext.getXid());
} catch (XAException ex) {
switch (ex.errorCode) {
case XAException.XAER_INVAL:
throw new IllegalStateException();
case XAException.XAER_NOTA:
throw new IllegalStateException();
case XAException.XAER_RMERR:
default:
throw new SystemException();
}
}
} // end-if (success)
}
}
public int getStatus() throws SystemException {
return this.transactionManager.getStatus();
}
public void setRollbackOnly() throws IllegalStateException, SystemException {
this.transactionManager.setRollbackOnly();
}
public void setTransactionTimeout(int timeout) throws SystemException {
this.transactionManager.setTimeoutSeconds(timeout);
}
public Reference getReference() throws NamingException {
throw new NamingException("Not supported yet!");
}
public void setBeanFactory(CompensableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public TransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(TransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
}