org.bytesoft.bytejta.supports.jdbc.RecoveredResource.java Source code

Java tutorial

Introduction

Here is the source code for org.bytesoft.bytejta.supports.jdbc.RecoveredResource.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.bytejta.supports.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import org.apache.commons.lang3.StringUtils;
import org.bytesoft.common.utils.ByteUtils;
import org.bytesoft.transaction.xa.TransactionXid;
import org.bytesoft.transaction.xa.XidFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RecoveredResource extends LocalXAResource implements XAResource {
    static final Logger logger = LoggerFactory.getLogger(RecoveredResource.class);

    private DataSource dataSource;

    public void recoverable(Xid xid) throws XAException {
        byte[] globalTransactionId = xid.getGlobalTransactionId();
        byte[] branchQualifier = xid.getBranchQualifier();

        String identifier = this.getIdentifier(globalTransactionId, branchQualifier);

        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = this.dataSource.getConnection();
            stmt = conn.prepareStatement("select gxid, bxid from bytejta where xid = ?");
            stmt.setString(1, identifier);
            rs = stmt.executeQuery();
            if (rs.next() == false) {
                throw new XAException(XAException.XAER_NOTA);
            }
        } catch (SQLException ex) {
            try {
                this.isTableExists(conn);
            } catch (SQLException sqlEx) {
                logger.warn("Error occurred while recovering local-xa-resource.", ex);
                throw new XAException(XAException.XAER_RMFAIL);
            } catch (RuntimeException rex) {
                logger.warn("Error occurred while recovering local-xa-resource.", ex);
                throw new XAException(XAException.XAER_RMFAIL);
            }

            throw new XAException(XAException.XAER_RMERR);
        } catch (RuntimeException ex) {
            logger.warn("Error occurred while recovering local-xa-resource.", ex);
            throw new XAException(XAException.XAER_RMERR);
        } finally {
            this.closeQuietly(rs);
            this.closeQuietly(stmt);
            this.closeQuietly(conn);
        }
    }

    public Xid[] recover(int flags) throws XAException {
        List<Xid> xidList = new ArrayList<Xid>();

        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = this.dataSource.getConnection();
            stmt = conn.prepareStatement("select gxid, bxid from bytejta");
            rs = stmt.executeQuery();
            while (rs.next()) {
                String gxid = rs.getString(1);
                String bxid = rs.getString(2);
                byte[] globalTransactionId = ByteUtils.stringToByteArray(gxid);
                byte[] branchQualifier = ByteUtils.stringToByteArray(bxid);
                TransactionXid xid = null;
                if (StringUtils.equals(gxid, bxid)) {
                    xid = new TransactionXid(XidFactory.JTA_FORMAT_ID, globalTransactionId);
                } else {
                    xid = new TransactionXid(XidFactory.JTA_FORMAT_ID, globalTransactionId, branchQualifier);
                }
                xidList.add(xid);
            }
        } catch (Exception ex) {
            boolean tableExists = false;
            try {
                tableExists = this.isTableExists(conn);
            } catch (Exception sqlEx) {
                logger.warn("Error occurred while recovering local-xa-resource.", ex);
                throw new XAException(XAException.XAER_RMFAIL);
            }

            if (tableExists) {
                throw new XAException(XAException.XAER_RMERR);
            }
        } finally {
            this.closeQuietly(rs);
            this.closeQuietly(stmt);
            this.closeQuietly(conn);
        }

        Xid[] xidArray = new Xid[xidList.size()];
        xidList.toArray(xidArray);

        return xidArray;
    }

    public void forgetQuietly(Xid xid) {
        try {
            this.forget(xid);
        } catch (XAException ex) {
            logger.warn("Error occurred while forgeting local-xa-resource.", xid);
        }
    }

    public synchronized void forget(Xid[] xids) throws XAException {
        if (xids == null || xids.length == 0) {
            return;
        }

        String[] xidArray = new String[xids.length];

        for (int i = 0; i < xids.length; i++) {
            Xid xid = xids[i];

            byte[] globalTransactionId = xid.getGlobalTransactionId();
            byte[] branchQualifier = xid.getBranchQualifier();
            xidArray[i] = this.getIdentifier(globalTransactionId, branchQualifier);
        }

        Connection conn = null;
        PreparedStatement stmt = null;
        Boolean autoCommit = null;
        try {
            conn = this.dataSource.getConnection();
            autoCommit = conn.getAutoCommit();
            conn.setAutoCommit(false);
            stmt = conn.prepareStatement("delete from bytejta where xid = ?");
            for (int i = 0; i < xids.length; i++) {
                stmt.setString(1, xidArray[i]);
                stmt.addBatch();
            }
            stmt.executeBatch();
            conn.commit();
        } catch (Exception ex) {
            logger.error("Error occurred while forgetting resources.");

            try {
                conn.rollback();
            } catch (Exception sqlEx) {
                logger.error("Error occurred while rolling back local resources.", sqlEx);
            }

            boolean tableExists = false;
            try {
                tableExists = this.isTableExists(conn);
            } catch (Exception sqlEx) {
                logger.warn("Error occurred while forgeting local resources.", ex);
                throw new XAException(XAException.XAER_RMFAIL);
            }

            if (tableExists) {
                throw new XAException(XAException.XAER_RMERR);
            }
        } finally {
            if (autoCommit != null) {
                try {
                    conn.setAutoCommit(autoCommit);
                } catch (SQLException sqlEx) {
                    logger.error("Error occurred while configuring attribute 'autoCommit'.", sqlEx);
                }
            }

            this.closeQuietly(stmt);
            this.closeQuietly(conn);
        }
    }

    public synchronized void forget(Xid xid) throws XAException {
        if (xid == null) {
            logger.warn("Error occurred while forgeting local-xa-resource: invalid xid.");
            return;
        }

        byte[] globalTransactionId = xid.getGlobalTransactionId();
        byte[] branchQualifier = xid.getBranchQualifier();

        String identifier = this.getIdentifier(globalTransactionId, branchQualifier);

        Connection conn = null;
        PreparedStatement stmt = null;
        try {
            conn = this.dataSource.getConnection();
            stmt = conn.prepareStatement("delete from bytejta where xid = ?");
            stmt.setString(1, identifier);
            stmt.executeUpdate();
        } catch (Exception ex) {
            boolean tableExists = false;
            try {
                tableExists = this.isTableExists(conn);
            } catch (Exception sqlEx) {
                logger.warn("Error occurred while forgeting local-xa-resource.", ex);
                throw new XAException(XAException.XAER_RMFAIL);
            }

            if (tableExists) {
                throw new XAException(XAException.XAER_RMERR);
            }
        } finally {
            this.closeQuietly(stmt);
            this.closeQuietly(conn);
        }
    }

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

}