org.bytesoft.bytetcc.CompensableTransactionImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.bytesoft.bytetcc.CompensableTransactionImpl.java

Source

/**
 * 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 java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import org.apache.commons.lang3.StringUtils;
import org.bytesoft.bytejta.supports.jdbc.RecoveredResource;
import org.bytesoft.bytejta.supports.resource.RemoteResourceDescriptor;
import org.bytesoft.bytetcc.supports.resource.LocalResourceCleaner;
import org.bytesoft.common.utils.ByteUtils;
import org.bytesoft.common.utils.CommonUtils;
import org.bytesoft.compensable.CompensableBeanFactory;
import org.bytesoft.compensable.CompensableInvocation;
import org.bytesoft.compensable.CompensableTransaction;
import org.bytesoft.compensable.ContainerContext;
import org.bytesoft.compensable.archive.CompensableArchive;
import org.bytesoft.compensable.archive.TransactionArchive;
import org.bytesoft.compensable.logging.CompensableLogger;
import org.bytesoft.transaction.CommitRequiredException;
import org.bytesoft.transaction.RollbackRequiredException;
import org.bytesoft.transaction.Transaction;
import org.bytesoft.transaction.TransactionContext;
import org.bytesoft.transaction.TransactionRepository;
import org.bytesoft.transaction.archive.XAResourceArchive;
import org.bytesoft.transaction.supports.TransactionListener;
import org.bytesoft.transaction.supports.TransactionListenerAdapter;
import org.bytesoft.transaction.supports.TransactionResourceListener;
import org.bytesoft.transaction.supports.resource.XAResourceDescriptor;
import org.bytesoft.transaction.supports.serialize.XAResourceDeserializer;
import org.bytesoft.transaction.xa.TransactionXid;
import org.bytesoft.transaction.xa.XidFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CompensableTransactionImpl extends TransactionListenerAdapter implements CompensableTransaction {
    static final Logger logger = LoggerFactory.getLogger(CompensableTransactionImpl.class);

    private final TransactionContext transactionContext;
    private final List<CompensableArchive> archiveList = new ArrayList<CompensableArchive>();
    private final List<XAResourceArchive> resourceList = new ArrayList<XAResourceArchive>();
    private Transaction transaction;
    private CompensableBeanFactory beanFactory;

    private int transactionVote;
    private int transactionStatus = Status.STATUS_ACTIVE;
    /* current comensable-decision in confirm/cancel phase. */
    private transient Boolean positive;
    /* current compense-archive in confirm/cancel phase. */
    private transient CompensableArchive archive;

    /* current compensable-archive list in try phase. */
    private final transient List<CompensableArchive> transientArchiveList = new ArrayList<CompensableArchive>();

    private boolean participantStickyRequired;

    private Map<String, Serializable> variables = new HashMap<String, Serializable>();

    public CompensableTransactionImpl(TransactionContext txContext) {
        this.transactionContext = txContext;
    }

    public TransactionArchive getTransactionArchive() {
        TransactionArchive transactionArchive = new TransactionArchive();
        transactionArchive.setVariables(this.variables);
        transactionArchive.setCoordinator(this.transactionContext.isCoordinator());
        transactionArchive.setCompensable(this.transactionContext.isCompensable());
        transactionArchive.setCompensableStatus(this.transactionStatus);
        transactionArchive.setVote(this.transactionVote);
        transactionArchive.setXid(this.transactionContext.getXid());
        transactionArchive.getRemoteResources().addAll(this.resourceList);
        transactionArchive.getCompensableResourceList().addAll(this.archiveList);
        return transactionArchive;
    }

    public synchronized void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
            SecurityException, IllegalStateException, SystemException {

        CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();

        this.transactionContext.setCompensating(true);
        this.transactionStatus = Status.STATUS_COMMITTING;
        compensableLogger.updateTransaction(this.getTransactionArchive());

        SystemException systemEx = null;
        try {
            this.fireNativeParticipantConfirm();
        } catch (SystemException ex) {
            systemEx = ex;

            logger.info("{}| confirm native branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
        } catch (RuntimeException ex) {
            systemEx = new SystemException(ex.getMessage());

            logger.info("{}| confirm native branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
        }

        try {
            this.fireRemoteParticipantConfirm();
        } catch (HeuristicMixedException ex) {
            logger.info("{}| confirm remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw ex;
        } catch (HeuristicRollbackException ex) {
            logger.info("{}| confirm remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw ex;
        } catch (SystemException ex) {
            logger.info("{}| confirm remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw ex;
        } catch (RuntimeException ex) {
            logger.info("{}| confirm remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw ex;
        }

        if (systemEx != null) {
            throw systemEx;
        } else {
            this.transactionStatus = Status.STATUS_COMMITTED;
            compensableLogger.updateTransaction(this.getTransactionArchive());
            logger.info("{}| compensable transaction committed!",
                    ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()));
        }

    }

    private synchronized void fireNativeParticipantConfirm() throws SystemException {
        boolean errorExists = false;

        ContainerContext container = this.beanFactory.getContainerContext();
        for (int i = this.archiveList.size() - 1; i >= 0; i--) {
            CompensableArchive current = this.archiveList.get(i);
            if (current.isConfirmed()) {
                continue;
            }

            try {
                this.positive = true;
                this.archive = current;
                CompensableInvocation invocation = current.getCompensable();
                if (invocation == null) {
                    errorExists = true;
                    logger.error(
                            "{}| error occurred while confirming service: {}, please check whether the params of method(compensable-service) supports serialization.",
                            ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                            ByteUtils.byteArrayToString(current.getIdentifier().getGlobalTransactionId()));
                } else if (StringUtils.isNotBlank(invocation.getConfirmableKey())) {
                    container.confirm(invocation);
                } else {
                    current.setConfirmed(true);
                    logger.info("{}| confirm: identifier= {}, resourceKey= {}, resourceXid= {}.",
                            ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()),
                            ByteUtils.byteArrayToString(current.getIdentifier().getGlobalTransactionId()),
                            current.getCompensableResourceKey(), current.getCompensableXid());
                }
            } catch (RuntimeException rex) {
                errorExists = true;
                logger.error("{}| error occurred while confirming service: {}",
                        ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                        this.archive, rex);
            } finally {
                this.archive = null;
                this.positive = null;
            }
        }

        if (errorExists) {
            throw new SystemException();
        }

    }

    private synchronized void fireRemoteParticipantConfirm()
            throws HeuristicMixedException, HeuristicRollbackException, SystemException {
        boolean commitExists = false;
        boolean rollbackExists = false;
        boolean errorExists = false;

        for (int i = 0; i < this.resourceList.size(); i++) {
            XAResourceArchive current = this.resourceList.get(i);
            if (current.isCommitted()) {
                commitExists = true;
                continue;
            }

            CompensableLogger transactionLogger = this.beanFactory.getCompensableLogger();
            XidFactory xidFactory = this.beanFactory.getCompensableXidFactory();
            TransactionXid branchXid = (TransactionXid) current.getXid();
            TransactionXid globalXid = xidFactory.createGlobalXid(branchXid.getGlobalTransactionId());
            try {
                current.commit(globalXid, true);
                commitExists = true;

                current.setCommitted(true);
                current.setCompleted(true);
                transactionLogger.updateCoordinator(current);

                logger.info("{}| confirm remote branch: {}",
                        ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()),
                        current.getDescriptor().getIdentifier());
            } catch (XAException ex) {
                switch (ex.errorCode) {
                case XAException.XAER_NOTA:
                    logger.warn("{}| error occurred while confirming remote branch: {}, transaction is not exists!",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()),
                            current.getDescriptor().getIdentifier());
                    break;
                case XAException.XA_HEURCOM:
                    commitExists = true;

                    current.setCommitted(true);
                    current.setHeuristic(false);
                    current.setCompleted(true);
                    transactionLogger.updateCoordinator(current);

                    logger.info("{}| confirm remote branch: {}",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()),
                            current.getDescriptor().getIdentifier());
                    break;
                case XAException.XA_HEURRB:
                    rollbackExists = true;

                    current.setRolledback(true);
                    current.setHeuristic(false);
                    current.setCompleted(true);
                    transactionLogger.updateCoordinator(current);

                    logger.error("{}| error occurred while confirming remote branch: {}",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), this.archive, ex);
                    break;
                case XAException.XA_HEURMIX:
                    // should never happen
                    commitExists = true;
                    rollbackExists = true;

                    current.setHeuristic(true);
                    // current.setCommitted(true);
                    // current.setRolledback(true);
                    // current.setCompleted(true);
                    transactionLogger.updateCoordinator(current);

                    logger.error("{}| error occurred while confirming remote branch: {}",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), this.archive, ex);
                    break;
                default:
                    errorExists = false;
                    logger.error("{}| error occurred while confirming remote branch: {}",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), this.archive, ex);
                }

            } catch (RuntimeException rex) {
                errorExists = false;
                logger.error("{}| error occurred while confirming branch: {}",
                        ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), this.archive, rex);
            }
        }

        if (commitExists && rollbackExists) {
            throw new HeuristicMixedException();
        } else if (rollbackExists) {
            throw new HeuristicRollbackException();
        } else if (errorExists) {
            throw new SystemException();
        }

    }

    public void participantPrepare() throws RollbackRequiredException, CommitRequiredException {
        throw new RuntimeException("Not supported!");
    }

    public void participantCommit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
            SecurityException, IllegalStateException, CommitRequiredException, SystemException {
        throw new SystemException("Not supported!");
    }

    public synchronized void rollback() throws IllegalStateException, SystemException {
        CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();

        this.transactionStatus = Status.STATUS_ROLLING_BACK;
        this.transactionContext.setCompensating(true);

        compensableLogger.updateTransaction(this.getTransactionArchive());

        boolean coordinator = this.transactionContext.isCoordinator();
        boolean coordinatorTried = false;
        for (int i = 0; coordinator && i < this.archiveList.size(); i++) {
            CompensableArchive compensableArchive = this.archiveList.get(i);
            coordinatorTried = compensableArchive.isTried() ? true : coordinatorTried;
        }

        SystemException systemEx = null;
        if (coordinator == false || coordinatorTried) {
            try {
                this.fireNativeParticipantCancel();
            } catch (SystemException ex) {
                systemEx = ex;

                logger.info("{}| cancel native branchs failed!",
                        ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            } catch (RuntimeException ex) {
                systemEx = new SystemException(ex.getMessage());

                logger.info("{}| cancel native branchs failed!",
                        ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            }
        }

        try {
            this.fireRemoteParticipantCancel();
        } catch (SystemException ex) {
            logger.info("{}| cancel remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw ex;
        } catch (RuntimeException ex) {
            logger.info("{}| cancel remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw new SystemException(ex.getMessage());
        }

        if (systemEx != null) {
            throw systemEx;
        } else {
            this.transactionStatus = Status.STATUS_ROLLEDBACK;
            compensableLogger.updateTransaction(this.getTransactionArchive());
            logger.info("{}| compensable transaction rolled back!",
                    ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()));
        }

    }

    private synchronized void fireNativeParticipantCancel() throws SystemException {
        boolean errorExists = false;

        ContainerContext container = this.beanFactory.getContainerContext();
        for (int i = this.archiveList.size() - 1; i >= 0; i--) {
            CompensableArchive current = this.archiveList.get(i);
            if (current.isCancelled()) {
                continue;
            }

            try {
                this.positive = false;
                this.archive = current;
                CompensableInvocation invocation = current.getCompensable();
                if (current.isTried() == false) {
                    logger.info(
                            "{}| The operation in try phase is rolled back, so the cancel operation is ignored, compensable service: {}.",
                            ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()),
                            ByteUtils.byteArrayToString(current.getIdentifier().getGlobalTransactionId()));
                } else if (invocation == null) {
                    errorExists = true;
                    logger.error(
                            "{}| error occurred while cancelling service: {}, please check whether the params of method(compensable-service) supports serialization.",
                            ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                            ByteUtils.byteArrayToString(current.getIdentifier().getGlobalTransactionId()));
                } else if (StringUtils.isNotBlank(invocation.getCancellableKey())) {
                    container.cancel(invocation);
                } else {
                    this.archive.setCancelled(true);
                    logger.info("{}| cancel: identifier= {}, resourceKey= {}, resourceXid= {}.",
                            ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                            ByteUtils.byteArrayToString(current.getIdentifier().getGlobalTransactionId()),
                            current.getCompensableResourceKey(), current.getCompensableXid());
                }
            } catch (RuntimeException rex) {
                errorExists = true;
                logger.error("{}| error occurred while cancelling service: {}",
                        ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                        this.archive, rex);
            } finally {
                this.archive = null;
                this.positive = null;
            }
        }

        if (errorExists) {
            throw new SystemException();
        }

    }

    private synchronized void fireRemoteParticipantCancel() throws SystemException {
        boolean errorExists = false;

        for (int i = 0; i < this.resourceList.size(); i++) {
            XAResourceArchive current = this.resourceList.get(i);
            if (current.isRolledback()) {
                continue;
            }

            CompensableLogger transactionLogger = this.beanFactory.getCompensableLogger();
            XidFactory xidFactory = this.beanFactory.getCompensableXidFactory();
            TransactionXid branchXid = (TransactionXid) current.getXid();
            TransactionXid globalXid = xidFactory.createGlobalXid(branchXid.getGlobalTransactionId());
            try {
                current.rollback(globalXid);

                current.setRolledback(true);
                current.setCompleted(true);
                transactionLogger.updateCoordinator(current);

                logger.info("{}| cancel remote branch: {}",
                        ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()),
                        current.getDescriptor().getIdentifier());
            } catch (XAException ex) {
                switch (ex.errorCode) {
                case XAException.XAER_NOTA:
                    logger.warn("{}| error occurred while cancelling remote branch: {}, transaction is not exists!",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()),
                            current.getDescriptor().getIdentifier());
                    break;
                default:
                    errorExists = true;
                    logger.error("{}| error occurred while cancelling remote branch: {}",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), current, ex);
                }

            } catch (RuntimeException rex) {
                errorExists = true;
                logger.error("{}| error occurred while cancelling remote branch: {}",
                        ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), current, rex);
            }
        }

        if (errorExists) {
            throw new SystemException();
        }

    }

    public boolean enlistResource(XAResource xaRes)
            throws RollbackException, IllegalStateException, SystemException {
        CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();
        if (RemoteResourceDescriptor.class.isInstance(xaRes) == false) {
            throw new SystemException("Invalid resource!");
        }
        XAResourceArchive resourceArchive = null;
        RemoteResourceDescriptor descriptor = (RemoteResourceDescriptor) xaRes;
        String identifier = descriptor.getIdentifier();
        for (int i = 0; i < this.resourceList.size(); i++) {
            XAResourceArchive resource = this.resourceList.get(i);
            String resourceKey = resource.getDescriptor().getIdentifier();
            if (CommonUtils.equals(identifier, resourceKey)) {
                resourceArchive = resource;
                break;
            }
        }
        if (resourceArchive == null) {
            XidFactory xidFactory = this.beanFactory.getCompensableXidFactory();
            TransactionXid globalXid = this.transactionContext.getXid();
            TransactionXid branchXid = xidFactory.createBranchXid(globalXid);
            resourceArchive = new XAResourceArchive();
            resourceArchive.setXid(branchXid);
            resourceArchive.setDescriptor(descriptor);
            this.resourceList.add(resourceArchive);

            compensableLogger.createCoordinator(resourceArchive);

            logger.info("{}| enlist remote resource: {}.",
                    ByteUtils.byteArrayToString(globalXid.getGlobalTransactionId()), identifier);
        }

        return true;
    }

    public boolean delistResource(XAResource xaRes, int flag) throws IllegalStateException, SystemException {
        return true;
    }

    public void resume() throws SystemException {
        throw new SystemException();
    }

    public void suspend() throws SystemException {
        throw new SystemException();
    }

    public void registerCompensable(CompensableInvocation invocation) {
        XidFactory xidFactory = this.beanFactory.getTransactionXidFactory();

        CompensableArchive archive = new CompensableArchive();
        TransactionXid globalXid = xidFactory
                .createGlobalXid(this.transactionContext.getXid().getGlobalTransactionId());
        TransactionXid branchXid = xidFactory.createBranchXid(globalXid);
        archive.setIdentifier(branchXid);

        archive.setCompensable(invocation);

        this.archiveList.add(archive);
        this.transientArchiveList.add(archive);

        logger.info("{}| register compensable service: {}.",
                ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                ByteUtils.byteArrayToString(archive.getIdentifier().getGlobalTransactionId()));
    }

    public void registerSynchronization(Synchronization sync)
            throws RollbackException, IllegalStateException, SystemException {
    }

    public void registerTransactionListener(TransactionListener listener) {
    }

    public void registerTransactionResourceListener(TransactionResourceListener listener) {
    }

    public void onEnlistResource(Xid xid, XAResource xares) {
    }

    public void onDelistResource(Xid xid, XAResource xares) {
        String resourceKey = null;
        if (XAResourceDescriptor.class.isInstance(xares)) {
            XAResourceDescriptor descriptor = (XAResourceDescriptor) xares;
            resourceKey = descriptor.getIdentifier();
        } else if (XAResourceArchive.class.isInstance(xares)) {
            XAResourceArchive resourceArchive = (XAResourceArchive) xares;
            XAResourceDescriptor descriptor = resourceArchive.getDescriptor();
            resourceKey = descriptor == null ? null : descriptor.getIdentifier();
        }

        CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();
        if (this.transactionContext.isCompensating()) {
            this.archive.setCompensableXid(xid);
            this.archive.setCompensableResourceKey(resourceKey);
            compensableLogger.updateCompensable(this.archive);
        } else {
            for (int i = 0; i < this.transientArchiveList.size(); i++) {
                CompensableArchive compensableArchive = this.transientArchiveList.get(i);
                compensableArchive.setTransactionXid(xid);
                compensableArchive.setTransactionResourceKey(resourceKey);

                compensableLogger.createCompensable(compensableArchive);
            }
        }

    }

    public void onCommitSuccess(TransactionXid xid) {
        CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();

        if (this.transactionContext.isCompensating()) {
            if (this.positive == null) {
                // ignore
            } else if (this.positive) {
                this.archive.setConfirmed(true);

                logger.info("{}| confirm: identifier= {}, resourceKey= {}, resourceXid= {}.",
                        ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()),
                        ByteUtils.byteArrayToString(this.archive.getIdentifier().getGlobalTransactionId()),
                        this.archive.getCompensableResourceKey(), this.archive.getCompensableXid());
            } else {
                this.archive.setCancelled(true);

                logger.info("{}| cancel: identifier= {}, resourceKey= {}, resourceXid= {}.",
                        ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()),
                        ByteUtils.byteArrayToString(this.archive.getIdentifier().getGlobalTransactionId()),
                        this.archive.getCompensableResourceKey(), this.archive.getCompensableXid());
            }
            compensableLogger.updateCompensable(this.archive);
        } else if (this.transactionContext.isCoordinator()) {
            for (Iterator<CompensableArchive> itr = this.transientArchiveList.iterator(); itr.hasNext();) {
                CompensableArchive compensableArchive = itr.next();
                itr.remove(); // remove

                compensableArchive.setTried(true);
                // compensableLogger.updateCompensable(compensableArchive);

                logger.info("{}| try: identifier= {}, resourceKey= {}, resourceXid= {}.",
                        ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()),
                        ByteUtils.byteArrayToString(compensableArchive.getIdentifier().getGlobalTransactionId()),
                        compensableArchive.getTransactionResourceKey(), compensableArchive.getTransactionXid());
            }

            TransactionArchive transactionArchive = this.getTransactionArchive();
            transactionArchive.setCompensableStatus(Status.STATUS_COMMITTING);
            compensableLogger.updateTransaction(transactionArchive);

            logger.info("{}| try completed.",
                    ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()));
        } else {
            for (Iterator<CompensableArchive> itr = this.transientArchiveList.iterator(); itr.hasNext();) {
                CompensableArchive compensableArchive = itr.next();
                itr.remove(); // remove
                compensableArchive.setTried(true);
                compensableLogger.updateCompensable(compensableArchive);

                logger.info("{}| try: identifier= {}, resourceKey= {}, resourceXid= {}.",
                        ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()),
                        ByteUtils.byteArrayToString(compensableArchive.getIdentifier().getGlobalTransactionId()),
                        compensableArchive.getTransactionResourceKey(), compensableArchive.getTransactionXid());
            }
        }

    }

    public synchronized void recoveryCommit() throws CommitRequiredException, SystemException {
        CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();

        this.transactionContext.setCompensating(true);
        this.transactionStatus = Status.STATUS_COMMITTING;
        compensableLogger.updateTransaction(this.getTransactionArchive());

        SystemException systemEx = null;
        try {
            this.fireNativeParticipantRecoveryConfirm();
        } catch (SystemException ex) {
            systemEx = ex;

            logger.info("{}| recovery-confirm native branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
        } catch (RuntimeException ex) {
            systemEx = new SystemException(ex.getMessage());

            logger.info("{}| recovery-confirm native branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
        }

        try {
            this.fireRemoteParticipantRecoveryConfirm();
        } catch (HeuristicMixedException ex) {
            logger.info("{}| recovery-confirm remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw new SystemException(ex.getMessage());
        } catch (HeuristicRollbackException ex) {
            logger.info("{}| recovery-confirm remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw new SystemException(ex.getMessage());
        } catch (SystemException ex) {
            logger.info("{}| recovery-confirm remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw ex;
        } catch (RuntimeException ex) {
            logger.info("{}| recovery-confirm remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw new SystemException(ex.getMessage());
        }

        if (systemEx != null) {
            throw systemEx;
        } else {
            this.transactionStatus = Status.STATUS_COMMITTED;
            compensableLogger.updateTransaction(this.getTransactionArchive());
            logger.info("{}| compensable transaction recovery committed!",
                    ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()));
        }

    }

    private synchronized void fireNativeParticipantRecoveryConfirm() throws SystemException {
        if (this.transactionContext.isRecoveried()) {
            this.fireNativeParticipantRecoveryConfirmForRecoveredTransaction();
        } else {
            this.fireNativeParticipantConfirm();
        }
    }

    private synchronized void fireNativeParticipantRecoveryConfirmForRecoveredTransaction() throws SystemException {
        boolean errorExists = false;

        ContainerContext container = this.beanFactory.getContainerContext();
        XAResourceDeserializer resourceDeserializer = this.beanFactory.getResourceDeserializer();
        CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();

        boolean previouConfirmed = false;
        for (int i = this.archiveList.size() - 1; i >= 0; i--) {
            CompensableArchive current = this.archiveList.get(i);
            boolean currentConfirmed = current.isConfirmed();

            if (currentConfirmed) {
                continue;
            }

            TransactionXid compensableXid = (TransactionXid) current.getCompensableXid();
            try {
                this.positive = true;
                this.archive = current;

                String identifier = current.getCompensableResourceKey();
                if (StringUtils.isBlank(identifier)) {
                    if (previouConfirmed) {
                        logger.warn(
                                "There is no valid resource participated in the current branch transaction, the status of the current branch transaction is unknown!");
                    } else {
                        logger.debug("There is no valid resource participated in the current branch transaction!");
                    }
                } else {
                    XAResource xares = resourceDeserializer.deserialize(identifier);
                    if (RecoveredResource.class.isInstance(xares)) {
                        RecoveredResource resource = (RecoveredResource) xares;
                        try {
                            resource.recoverable(compensableXid);
                            current.setConfirmed(true);
                            compensableLogger.updateCompensable(current);
                            continue;
                        } catch (XAException xaex) {
                            switch (xaex.errorCode) {
                            case XAException.XAER_NOTA:
                                break;
                            case XAException.XAER_RMERR:
                                logger.warn(
                                        "The database table 'bytejta' cannot found, the status of the current branch transaction is unknown!");
                                break;
                            case XAException.XAER_RMFAIL:
                                errorExists = true;
                                logger.error(
                                        "{}| error occurred while recovering the branch transaction service: {}",
                                        ByteUtils.byteArrayToString(
                                                this.transactionContext.getXid().getGlobalTransactionId()),
                                        ByteUtils.byteArrayToString(
                                                current.getIdentifier().getGlobalTransactionId()),
                                        xaex);
                                break;
                            default:
                                logger.error(
                                        "Illegal state, the status of the current branch transaction is unknown!");
                            }
                        }
                    } else {
                        logger.error("Illegal resources, the status of the current branch transaction is unknown!");
                    }
                }

                CompensableInvocation invocation = current.getCompensable();
                if (invocation == null) {
                    errorExists = true;
                    logger.error(
                            "{}| error occurred while confirming service: {}, please check whether the params of method(compensable-service) supports serialization.",
                            ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                            ByteUtils.byteArrayToString(current.getIdentifier().getGlobalTransactionId()));
                } else if (StringUtils.isNotBlank(invocation.getConfirmableKey())) {
                    container.confirm(invocation);
                } else {
                    current.setConfirmed(true);
                    logger.info("{}| confirm: identifier= {}, resourceKey= {}, resourceXid= {}.",
                            ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                            ByteUtils.byteArrayToString(current.getIdentifier().getGlobalTransactionId()),
                            current.getCompensableResourceKey(), current.getCompensableXid());
                }
            } catch (RuntimeException rex) {
                errorExists = true;

                TransactionXid transactionXid = this.transactionContext.getXid();
                logger.error("{}| error occurred while confirming service: {}",
                        ByteUtils.byteArrayToString(transactionXid.getGlobalTransactionId()), this.archive, rex);
            } finally {
                this.archive = null;
                this.positive = null;

                previouConfirmed = currentConfirmed;
            }

        }

        if (errorExists) {
            throw new SystemException();
        }

    }

    private synchronized void fireRemoteParticipantRecoveryConfirm()
            throws HeuristicMixedException, HeuristicRollbackException, SystemException {
        boolean commitExists = false;
        boolean rollbackExists = false;
        boolean errorExists = false;

        for (int i = 0; i < this.resourceList.size(); i++) {
            XAResourceArchive current = this.resourceList.get(i);
            if (current.isCommitted()) {
                commitExists = true;
                continue;
            }

            CompensableLogger transactionLogger = this.beanFactory.getCompensableLogger();
            XidFactory xidFactory = this.beanFactory.getCompensableXidFactory();
            TransactionXid branchXid = (TransactionXid) current.getXid();
            TransactionXid globalXid = xidFactory.createGlobalXid(branchXid.getGlobalTransactionId());
            try {
                current.recoveryCommit(globalXid);
                commitExists = true;

                current.setCommitted(true);
                current.setCompleted(true);
                transactionLogger.updateCoordinator(current);

                logger.info("{}| recovery-confirm remote branch: {}",
                        ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()),
                        current.getDescriptor().getIdentifier());
            } catch (XAException ex) {
                switch (ex.errorCode) {
                case XAException.XAER_NOTA:
                    logger.warn("{}| error occurred while confirming remote branch: {}, transaction is not exists!",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()),
                            current.getDescriptor().getIdentifier());
                    break;
                case XAException.XA_HEURCOM:
                    current.setCommitted(true);
                    current.setHeuristic(false);
                    current.setCompleted(true);
                    transactionLogger.updateCoordinator(current);

                    logger.info("{}| recovery-confirm remote branch: {}",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()),
                            current.getDescriptor().getIdentifier());
                    break;
                case XAException.XA_HEURRB:
                    rollbackExists = true;

                    current.setRolledback(true);
                    current.setHeuristic(false);
                    current.setCompleted(true);
                    transactionLogger.updateCoordinator(current);

                    logger.error("{}| error occurred while confirming remote branch: {}",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), current, ex);
                    break;
                case XAException.XA_HEURMIX:
                    commitExists = true;
                    rollbackExists = true;

                    current.setHeuristic(true);
                    // current.setCommitted(true);
                    // current.setRolledback(true);
                    // current.setCompleted(true);
                    transactionLogger.updateCoordinator(current);

                    logger.error("{}| error occurred while confirming remote branch: {}",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), current, ex);
                    break;
                default:
                    errorExists = false;
                    logger.error("{}| error occurred while confirming remote branch: {}",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), current, ex);
                }

            } catch (RuntimeException rex) {
                errorExists = false;
                logger.error("{}| error occurred while confirming remote branch: {}",
                        ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), current, rex);
            }
        }

        if (commitExists && rollbackExists) {
            throw new HeuristicMixedException();
        } else if (rollbackExists) {
            throw new HeuristicRollbackException();
        } else if (errorExists) {
            throw new SystemException();
        }

    }

    public synchronized void recoveryRollback() throws RollbackRequiredException, SystemException {
        CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();

        this.transactionStatus = Status.STATUS_ROLLING_BACK;
        this.transactionContext.setCompensating(true);
        compensableLogger.updateTransaction(this.getTransactionArchive());

        SystemException systemEx = null;
        try {
            this.fireNativeParticipantRecoveryCancel();
        } catch (SystemException ex) {
            systemEx = ex;

            logger.info("{}| recovery-cancel native branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
        } catch (RuntimeException ex) {
            systemEx = new SystemException(ex.getMessage());

            logger.info("{}| recovery-cancel native branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
        }

        try {
            this.fireRemoteParticipantRecoveryCancel();
        } catch (SystemException ex) {
            logger.info("{}| recovery-cancel remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw ex;
        } catch (RuntimeException ex) {
            logger.info("{}| recovery-cancel remote branchs failed!",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()), ex);
            throw new SystemException(ex.getMessage());
        }

        if (systemEx != null) {
            throw systemEx;
        } else {
            this.transactionStatus = Status.STATUS_ROLLEDBACK;
            compensableLogger.updateTransaction(this.getTransactionArchive());
            logger.info("{}| compensable transaction recovery rolled back!",
                    ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()));
        }

    }

    private synchronized void fireNativeParticipantRecoveryCancel() throws SystemException {
        if (this.transactionContext.isRecoveried()) {
            this.fireNativeParticipantRecoveryCancelForRecoveredTransaction();
        } else {
            this.fireNativeParticipantCancel();
        }
    }

    private synchronized void fireNativeParticipantRecoveryCancelForRecoveredTransaction() throws SystemException {
        boolean errorExists = false;

        ContainerContext container = this.beanFactory.getContainerContext();
        XAResourceDeserializer resourceDeserializer = this.beanFactory.getResourceDeserializer();
        CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();

        boolean previouCancelled = false;
        for (int i = this.archiveList.size() - 1; i >= 0; i--) {
            CompensableArchive current = this.archiveList.get(i);
            boolean currentCancelled = current.isCancelled();

            if (currentCancelled) {
                continue;
            }

            if (current.isTried() == false) /* this.transactionContext.isCoordinator() == false && */ {
                String identifier = current.getTransactionResourceKey();
                if (StringUtils.isBlank(identifier)) {
                    logger.warn(
                            "There is no valid resource participated in the trying branch transaction, the status of the branch transaction is unknown!");
                } else {
                    XAResource xares = resourceDeserializer.deserialize(identifier);
                    if (RecoveredResource.class.isInstance(xares)) {
                        RecoveredResource resource = (RecoveredResource) xares;
                        try {
                            resource.recoverable(current.getTransactionXid());
                            current.setTried(true);
                            compensableLogger.updateCompensable(current);
                        } catch (XAException xaex) {
                            switch (xaex.errorCode) {
                            case XAException.XAER_NOTA:
                                current.setTried(false);
                                continue;
                            case XAException.XAER_RMERR:
                                logger.warn(
                                        "The database table 'bytejta' cannot found, the status of the trying branch transaction is unknown!");
                                break;
                            case XAException.XAER_RMFAIL:
                                errorExists = true;

                                Xid xid = current.getTransactionXid();
                                logger.error("Error occurred while recovering the branch transaction service: {}",
                                        ByteUtils.byteArrayToString(xid.getGlobalTransactionId()), xaex);
                                break;
                            default:
                                logger.error(
                                        "Illegal state, the status of the trying branch transaction is unknown!");
                            }
                        }
                    } else {
                        logger.error("Illegal resources, the status of the trying branch transaction is unknown!");
                    }
                }
            }

            TransactionXid compensableXid = (TransactionXid) current.getCompensableXid();
            try {
                this.positive = false;
                this.archive = current;

                String identifier = current.getCompensableResourceKey();
                if (StringUtils.isBlank(identifier)) {
                    if (previouCancelled) {
                        logger.warn(
                                "There is no valid resource participated in the current branch transaction, the status of the current branch transaction is unknown!");
                    } else {
                        logger.debug("There is no valid resource participated in the current branch transaction!");
                    }
                } else {
                    XAResource xares = resourceDeserializer.deserialize(identifier);
                    if (RecoveredResource.class.isInstance(xares)) {
                        RecoveredResource resource = (RecoveredResource) xares;
                        try {
                            resource.recoverable(compensableXid);
                            current.setCancelled(true);
                            compensableLogger.updateCompensable(current);
                            continue;
                        } catch (XAException xaex) {
                            switch (xaex.errorCode) {
                            case XAException.XAER_NOTA:
                                break;
                            case XAException.XAER_RMERR:
                                logger.warn(
                                        "The database table 'bytejta' cannot found, the status of the current branch transaction is unknown!");
                                break;
                            case XAException.XAER_RMFAIL:
                                errorExists = true;
                                logger.error(
                                        "{}| error occurred while recovering the branch transaction service: {}",
                                        ByteUtils.byteArrayToString(
                                                this.transactionContext.getXid().getGlobalTransactionId()),
                                        ByteUtils.byteArrayToString(
                                                current.getIdentifier().getGlobalTransactionId()),
                                        xaex);
                                break;
                            default:
                                logger.error(
                                        "Illegal state, the status of the current branch transaction is unknown!");
                            }
                        }
                    } else {
                        logger.error("Illegal resources, the status of the current branch transaction is unknown!");
                    }
                }

                CompensableInvocation invocation = current.getCompensable();
                if (current.isTried() == false) {
                    logger.info(
                            "{}| the operation in try phase is rolled back, so the cancel operation is ignored, compensable service: {}.",
                            ByteUtils.byteArrayToString(transactionContext.getXid().getGlobalTransactionId()),
                            ByteUtils.byteArrayToString(current.getIdentifier().getGlobalTransactionId()));
                } else if (invocation == null) {
                    errorExists = true;
                    logger.error(
                            "{}| error occurred while cancelling service: {}, please check whether the params of method(compensable-service) supports serialization.",
                            ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                            ByteUtils.byteArrayToString(current.getIdentifier().getGlobalTransactionId()));
                } else if (StringUtils.isNotBlank(invocation.getCancellableKey())) {
                    container.cancel(invocation);
                } else {
                    this.archive.setCancelled(true);
                    logger.info("{}| cancel: identifier= {}, resourceKey= {}, resourceXid= {}.",
                            ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                            ByteUtils.byteArrayToString(current.getIdentifier().getGlobalTransactionId()),
                            current.getCompensableResourceKey(), current.getCompensableXid());
                }
            } catch (RuntimeException rex) {
                errorExists = true;
                logger.error("{}| error occurred while cancelling service: {}",
                        ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()),
                        this.archive, rex);
            } finally {
                this.archive = null;
                this.positive = null;

                previouCancelled = currentCancelled;
            }
        }

        if (errorExists) {
            throw new SystemException();
        }

    }

    private synchronized void fireRemoteParticipantRecoveryCancel() throws SystemException {
        boolean errorExists = false;

        for (int i = 0; i < this.resourceList.size(); i++) {
            XAResourceArchive current = this.resourceList.get(i);
            if (current.isRolledback()) {
                continue;
            }

            CompensableLogger transactionLogger = this.beanFactory.getCompensableLogger();
            XidFactory xidFactory = this.beanFactory.getCompensableXidFactory();
            TransactionXid branchXid = (TransactionXid) current.getXid();
            TransactionXid globalXid = xidFactory.createGlobalXid(branchXid.getGlobalTransactionId());
            try {
                current.recoveryRollback(globalXid);
                current.setRolledback(true);
                current.setCompleted(true);
                transactionLogger.updateCoordinator(current);

                logger.info("{}| recovery-cancel remote branch: {}",
                        ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()),
                        current.getDescriptor().getIdentifier());
            } catch (XAException ex) {
                switch (ex.errorCode) {
                case XAException.XAER_NOTA:
                    logger.warn(
                            "{}| error occurred while recovery-cancelling remote branch: {}, transaction is not exists!",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()),
                            current.getDescriptor().getIdentifier());
                    break;
                default:
                    errorExists = true;
                    logger.error("{}| error occurred while recovery-cancelling remote branch: {}",
                            ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), current, ex);
                }
            } catch (RuntimeException rex) {
                errorExists = true;
                logger.error("{}| error occurred while recovery-cancelling remote branch: {}",
                        ByteUtils.byteArrayToString(branchXid.getGlobalTransactionId()), current, rex);
            }
        }

        if (errorExists) {
            throw new SystemException();
        }

    }

    public synchronized void forget() throws SystemException {
        LocalResourceCleaner resourceCleaner = this.beanFactory.getLocalResourceCleaner();
        boolean success = true;

        Map<Xid, String> xidMap = new HashMap<Xid, String>();
        for (int i = 0; i < this.archiveList.size(); i++) {
            CompensableArchive current = this.archiveList.get(i);
            Xid transactionXid = current.getTransactionXid();
            Xid compensableXid = current.getCompensableXid();
            if (transactionXid != null) {
                xidMap.put(transactionXid, current.getTransactionResourceKey());
            }
            if (compensableXid != null) {
                xidMap.put(compensableXid, current.getCompensableResourceKey());
            }
        }

        for (Iterator<Map.Entry<Xid, String>> itr = xidMap.entrySet().iterator(); itr.hasNext();) {
            Map.Entry<Xid, String> entry = itr.next();
            Xid xid = entry.getKey();
            String resource = entry.getValue();
            try {
                resourceCleaner.forget(xid, resource);
            } catch (RuntimeException rex) {
                success = false;
                logger.error("forget-transaction: error occurred while forgetting xid: {}", xid, rex);
            }
        }

        for (int i = 0; i < this.resourceList.size(); i++) {
            XAResourceArchive current = this.resourceList.get(i);

            XidFactory xidFactory = this.beanFactory.getCompensableXidFactory();
            TransactionXid branchXid = (TransactionXid) current.getXid();
            TransactionXid globalXid = xidFactory.createGlobalXid(branchXid.getGlobalTransactionId());
            try {
                current.forget(globalXid);
            } catch (XAException ex) {
                switch (ex.errorCode) {
                case XAException.XAER_NOTA:
                    break;
                default:
                    success = false;
                    logger.error("forget-transaction: error occurred while forgetting branch: {}", branchXid, ex);
                }
            } catch (RuntimeException rex) {
                success = false;
                logger.error("forget-transaction: error occurred while forgetting branch: {}", branchXid, rex);
            }
        }

        if (success) {
            CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();
            TransactionRepository compensableRepository = this.beanFactory.getCompensableRepository();

            compensableLogger.deleteTransaction(this.getTransactionArchive());

            compensableRepository.removeErrorTransaction(this.transactionContext.getXid());
            compensableRepository.removeTransaction(this.transactionContext.getXid());

            logger.info("{}| forget transaction.",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()));
        } else {
            throw new SystemException();
        }

    }

    public synchronized void recoveryForget() throws SystemException {
        LocalResourceCleaner resourceCleaner = this.beanFactory.getLocalResourceCleaner();

        boolean success = true;
        for (int i = 0; i < this.archiveList.size(); i++) {
            CompensableArchive current = this.archiveList.get(i);

            String transactionResourceKey = current.getTransactionResourceKey();
            String compensableResourceKey = current.getCompensableResourceKey();
            if (StringUtils.isNotBlank(transactionResourceKey)) {
                Xid branchXid = current.getTransactionXid();
                try {
                    resourceCleaner.forget(branchXid, transactionResourceKey);
                } catch (RuntimeException rex) {
                    success = false;
                    logger.error("forget-transaction: error occurred while forgetting branch: {}", branchXid, rex);
                }
            }

            if (StringUtils.isNotBlank(compensableResourceKey)) {
                Xid branchXid = current.getCompensableXid();
                try {
                    resourceCleaner.forget(branchXid, compensableResourceKey);
                } catch (RuntimeException rex) {
                    success = false;
                    logger.error("forget-transaction: error occurred while forgetting branch: {}", branchXid, rex);
                }
            }

        }

        for (int i = 0; i < this.resourceList.size(); i++) {
            XAResourceArchive current = this.resourceList.get(i);

            XidFactory xidFactory = this.beanFactory.getCompensableXidFactory();
            TransactionXid branchXid = (TransactionXid) current.getXid();
            TransactionXid globalXid = xidFactory.createGlobalXid(branchXid.getGlobalTransactionId());
            try {
                current.recoveryForget(globalXid);
            } catch (XAException ex) {
                switch (ex.errorCode) {
                case XAException.XAER_NOTA:
                    break;
                default:
                    success = false;
                    logger.error("forget-transaction: error occurred while forgetting branch: {}", branchXid, ex);
                }
            } catch (RuntimeException rex) {
                success = false;
                logger.error("forget-transaction: error occurred while forgetting branch: {}", branchXid, rex);
            }
        }

        if (success) {
            CompensableLogger compensableLogger = this.beanFactory.getCompensableLogger();
            TransactionRepository compensableRepository = this.beanFactory.getCompensableRepository();

            compensableLogger.deleteTransaction(this.getTransactionArchive());

            compensableRepository.removeErrorTransaction(this.transactionContext.getXid());
            compensableRepository.removeTransaction(this.transactionContext.getXid());

            logger.info("{}| forget transaction.",
                    ByteUtils.byteArrayToString(this.transactionContext.getXid().getGlobalTransactionId()));
        } else {
            throw new SystemException();
        }

    }

    public CompensableArchive getCompensableArchive() {
        return this.archive;
    }

    /**
     * only for recovery.
     */
    public List<CompensableArchive> getCompensableArchiveList() {
        return this.archiveList;
    }

    /**
     * only for recovery.
     */
    public List<XAResourceArchive> getParticipantArchiveList() {
        return this.resourceList;
    }

    public void setRollbackOnly() throws IllegalStateException, SystemException {
        throw new IllegalStateException();
    }

    public void setRollbackOnlyQuietly() {
        throw new IllegalStateException();
    }

    public boolean isLocalTransaction() {
        throw new IllegalStateException();
    }

    public int getStatus() throws SystemException {
        return this.transactionStatus;
    }

    public int getTransactionStatus() {
        return this.transactionStatus;
    }

    public void setTransactionStatus(int status) {
        this.transactionStatus = status;
    }

    public boolean isTiming() {
        throw new IllegalStateException();
    }

    public void setTransactionTimeout(int seconds) {
        throw new IllegalStateException();
    }

    public TransactionContext getTransactionContext() {
        return this.transactionContext;
    }

    public void setBeanFactory(CompensableBeanFactory tbf) {
        this.beanFactory = tbf;
    }

    public Serializable getVariable(String key) {
        return this.variables.get(key);
    }

    public boolean isCurrentCompensableServiceTried() {
        return this.archive.isTried();
    }

    public void setVariable(String key, Serializable variable) {
        this.variables.put(key, variable);
    }

    public boolean isParticipantStickyRequired() {
        return participantStickyRequired;
    }

    public void setParticipantStickyRequired(boolean participantStickyRequired) {
        this.participantStickyRequired = participantStickyRequired;
    }

    public Object getTransactionalExtra() {
        return transaction;
    }

    public void setTransactionalExtra(Object transactionalExtra) {
        this.transaction = (Transaction) transactionalExtra;
    }

    public Transaction getTransaction() {
        return (Transaction) this.getTransactionalExtra();
    }

    public int getTransactionVote() {
        return transactionVote;
    }

    public void setTransactionVote(int transactionVote) {
        this.transactionVote = transactionVote;
    }

    public Map<String, Serializable> getVariables() {
        return variables;
    }

    public void setVariables(Map<String, Serializable> variables) {
        this.variables = variables;
    }

}