All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.enterprise.transaction.jts.recovery.OracleXAResource Maven / Gradle / Ivy

/*
 * Copyright (c) 2021 Contributors to the Eclipse Foundation
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

//Source File Name:   OracleXAResource.java

package com.sun.enterprise.transaction.jts.recovery;

import static com.sun.logging.LogDomains.JTA_LOGGER;
import static java.util.logging.Level.FINEST;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;

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

import com.sun.enterprise.transaction.JavaEETransactionManagerSimplified;
import com.sun.enterprise.transaction.api.XAResourceWrapper;
import com.sun.enterprise.util.i18n.StringManager;
import com.sun.logging.LogDomains;

/**
 * This implements workaround for Oracle XAResource. Oracle's 8.1.7 XAResource implementation doesn't work fine while
 * recovery. This class fires sql statements to achieve same.
 *
 * @author Bala Dutt
 * @version 1.0
 */
public class OracleXAResource extends XAResourceWrapper {

    // Use superclass for Sting Manager
    private static final StringManager sm = StringManager.getManager(XAResourceWrapper.class);

    // Use JTA_LOGGER for backward compatibility, so use a class from
    // 'jta' bundle to load it.
    private static final Logger _logger = LogDomains.getLogger(JavaEETransactionManagerSimplified.class, JTA_LOGGER);

    @Override
    public XAResourceWrapper getInstance() {
        return new OracleXAResource();
    }

    /**
     * Recovers list of xids in transaction table. Recover on oracle ignores flags sent to it, this method takes care of
     * flags in addition to calling recoverList for xid list.
     *
     * @param flag an int value
     * @return a Xid[] value
     * @exception XAException if an error occurs
     */
    @Override
    public Xid[] recover(int flag) throws XAException {
        if (flag == XAResource.TMNOFLAGS) {
            return null;
        }

        return recoverList(flag);
    }

    /**
     * Fires a select statement so that transaction xids are updated and retrieve the xid list. Oracle doesn't update the
     * xid's for sometime. After this update, recover of real oracle xa resource is is used get xid list.
     *
     * @return a Xid[] value
     * @exception XAException if an error occurs
     */
    private Xid[] recoverList(int flag) throws XAException {
        Statement statement = null;
        ResultSet resultset = null;
        Connection connection = null;
        try {
            connection = (Connection) m_xacon.getConnection(subject, null);
            if (connection == null) {
                // throw new XAException("Oracle XA Resource wrapper : connection could not be got");
                throw new XAException(sm.getString("transaction.oracle_xa_wrapper_connection_failed"));
            }
            statement = connection.createStatement();
            resultset = statement.executeQuery("select pending.local_tran_id from SYS.PENDING_TRANS$ pending, SYS.DBA_2PC_NEIGHBORS");
            resultset.close();
            resultset = null;
            statement.close();
            statement = null;
            return m_xacon.getXAResource().recover(flag);
        } catch (SQLException sqlexception) {
            throw new XAException(sm.getString("transaction.oracle_sqlexception_occurred", sqlexception));
        } catch (XAException e) {
            throw e;
        } catch (Exception e) {
            throw new XAException(sm.getString("transaction.oracle_unknownexception_occurred", e));
        } finally {
            if (resultset != null) {
                try {
                    resultset.close();
                } catch (SQLException sqlexception1) {
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException sqlexception2) {
                }
            }
        }
    }

    @Override
    public void commit(Xid xid, boolean flag) throws XAException {
        doRecovery(xid, true);
    }

    @Override
    public void rollback(Xid xid) throws XAException {
        doRecovery(xid, false);
    }

    /**
     * Does actual recovery depending on boolean argument - true for commmit.
     *
     * @param xid a Xid value
     * @param isCommit a boolean value
     * @exception XAException if an error occurs
     */
    private void doRecovery(Xid xid, boolean isCommit) throws XAException {
        try {
            if (isCommit) {
                m_xacon.getXAResource().commit(xid, true);
            } else {
                m_xacon.getXAResource().rollback(xid);
            }
        } catch (XAException ex) {
            _logger.log(FINEST, " An XAException occurred while calling XAResource method ", ex);
        } catch (Exception ex) {
            _logger.log(FINEST, " An Exception occurred while calling XAResource method ", ex);
        }

        Statement statement = null;
        ResultSet resultset = null;
        Connection connection = null;
        try {
            connection = (Connection) m_xacon.getConnection(subject, null);
            if (connection == null) {
                throw new XAException(sm.getString("transaction.oracle_xa_wrapper_connection_failed"));
            }

            statement = connection.createStatement();
            resultset = statement.executeQuery(
                    "select pending.local_tran_id from SYS.PENDING_TRANS$ pending, SYS.DBA_2PC_NEIGHBORS dba where pending.global_foreign_id = '"
                            + toHexString(xid.getGlobalTransactionId())
                            + "' and pending.local_tran_id = dba.local_tran_id and dba.branch = '" + toHexString(xid.getBranchQualifier())
                            + "' and pending.state = 'prepared'");
            if (resultset.next()) {
                String s = resultset.getString(1);
                resultset.close();
                resultset = null;
                statement.executeUpdate((isCommit ? "commit force '" : "rollback force '") + s + "'");
                statement.close();
                statement = null;
            }
        } catch (SQLException sqlexception) {
            _logger.log(Level.FINE, " An SQLException during recovery ", sqlexception);
            throw new XAException(sm.getString("transaction.oracle_sqlexception_occurred", sqlexception));
        } catch (Exception e) {
            _logger.log(Level.FINE, " An Exception during recovery ", e);
            throw new XAException(sm.getString("transaction.oracle_unknownexception_occurred", e));
        } finally {
            if (resultset != null) {
                try {
                    resultset.close();
                } catch (SQLException sqlexception1) {
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException sqlexception2) {
                }
            }
        }
    }

    private static final char HEX_DIGITS[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

    /**
     * Converts Xids into string that can be used in sql statements for oracle.
     *
     * @param abyte0[] a byte value
     * @return a String value
     */
    private static String toHexString(byte abyte0[]) {
        StringBuffer stringbuffer = new StringBuffer();
        if (null != abyte0 && 0 < abyte0.length) {
            for (int i = 0; i < abyte0.length; i++) {
                stringbuffer.append(HEX_DIGITS[(abyte0[i] & 0xf0) >> 4]);
                stringbuffer.append(HEX_DIGITS[abyte0[i] & 0xf]);
            }
            return stringbuffer.toString();
        }

        return "";
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy