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

com.arjuna.ats.internal.jdbc.recovery.JDBCXARecovery Maven / Gradle / Ivy

There is a newer version: 7.1.0.Final
Show newest version
/*
   Copyright The Narayana Authors
   SPDX-License-Identifier: Apache-2.0
 */



package com.arjuna.ats.internal.jdbc.recovery;

import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener;
import javax.sql.XAConnection;
import javax.sql.XADataSource;
import javax.transaction.xa.XAResource;

import com.arjuna.ats.jdbc.common.jdbcPropertyManager;
import com.arjuna.ats.jdbc.logging.jdbcLogger;
import com.arjuna.ats.jta.recovery.XAResourceRecovery;
import com.arjuna.common.util.propertyservice.PropertiesFactory;

/**
 * This provides recovery for compliant JDBC drivers. It is not meant to be
 * implementation specific.
 *
 * Users are responsible for deploying an appropriate XADataSource into JNDI and
 * then providing the relevant JNDI lookup information in a property file to an
 * instance of this class. Username and password values may also be provided in
 * the same property file.
 */

public class JDBCXARecovery implements XAResourceRecovery
{
    public static final String DATABASE_JNDI_NAME = "DatabaseJNDIName";
    public static final String USER_NAME          = "UserName";
    public static final String PASSWORD           = "Password";

    /*
     * Some XAResourceRecovery implementations will do their startup work here,
     * and then do little or nothing in setDetails. Since this one needs to know
     * dynamic class name, the constructor does nothing.
     */

    public JDBCXARecovery()
        throws SQLException
    {
        if (jdbcLogger.logger.isDebugEnabled())
            jdbcLogger.logger.debug("JDBCXARecovery()");

        _props                   = null;
        _hasMoreResources        = false;
        _connectionEventListener = new LocalConnectionEventListener();
    }

    /**
     * The recovery module will have chopped off this class name already. The
     * parameter should specify a property file from which the jndi name, user name,
     * password can be read.
     */

    public boolean initialise(String parameter)
        throws SQLException
    {
        if (jdbcLogger.logger.isDebugEnabled())
            jdbcLogger.logger.debug("JDBCXARecovery.initialise(" + parameter + ")");

        if (parameter == null)
            return false;

        try
        {
            _props = PropertiesFactory.getPropertiesFromFile(parameter, JDBCXARecovery.class.getClassLoader());

            _dbName   = _props.getProperty(DATABASE_JNDI_NAME);
            _user     = _props.getProperty(USER_NAME);
            _password = _props.getProperty(PASSWORD);
        }
        catch (Exception e)
        {
            jdbcLogger.i18NLogger.warn_recovery_xa_initexp(e);

            return false;
        }

        return true;
    }

    public synchronized XAResource getXAResource()
        throws SQLException
    {
        createConnection();

        return _connection.getXAResource();
    }

    public boolean hasMoreResources()
    {
        if (_dataSource == null)
            try
            {
                createDataSource();
            }
            catch (SQLException sqlException)
            {
                return false;
            }

        if (_dataSource != null)
        {
            _hasMoreResources = ! _hasMoreResources;

            return _hasMoreResources;
        }
        else
            return false;
    }

    /**
     * Lookup the XADataSource in JNDI. We got the relevant information from the
     * property file provided at input to this instance.
     */

    private final void createDataSource() throws SQLException {
        try
        {
            if (_dataSource == null)
            {
                Hashtable env = jdbcPropertyManager.getJDBCEnvironmentBean().getJndiProperties();
                Context context = new InitialContext(env);
                _dataSource = (XADataSource) context.lookup(_dbName);

                if (_dataSource == null)
                    throw new SQLException(jdbcLogger.i18NLogger.get_cant_resolve_ds_jndi_lookup(_dbName, env));
            }
        }
        catch (SQLException ex)
        {
            jdbcLogger.i18NLogger.error_cannot_create_datasource(_dbName, ex);

            throw ex;
        }
        catch (Exception e)
        {
            jdbcLogger.i18NLogger.error_cannot_create_datasource(_dbName, e);

            SQLException sqlException = new SQLException(e.toString());
            sqlException.initCause(e);
            throw sqlException;
        }
    }

    /**
     * Create the XAConnection from the XADataSource.
     */

    private final void createConnection() throws SQLException
    {
        if (_dataSource == null)
            createDataSource();

        try
        {

            if (_connection == null)
            {
                if ((_user == null) && (_password == null))
                    _connection = _dataSource.getXAConnection();
                else
                    _connection = _dataSource.getXAConnection(_user, _password);

                _connection.addConnectionEventListener(_connectionEventListener);
            }
        }
        catch (SQLException ex)
        {
            jdbcLogger.i18NLogger.error_cannot_create_connection(_dataSource, _user, _password, ex);

            throw ex;
        }
        catch (Exception e)
        {
            jdbcLogger.i18NLogger.error_cannot_create_connection(_dataSource, _user, _password, e);

            SQLException sqlException = new SQLException(e.toString());
            sqlException.initCause(e);
            throw sqlException;
        }
    }

    private class LocalConnectionEventListener implements ConnectionEventListener
    {
        public void connectionErrorOccurred(ConnectionEvent connectionEvent)
        {
            _connection.removeConnectionEventListener(_connectionEventListener);
            _connection = null;
        }

        public void connectionClosed(ConnectionEvent connectionEvent)
        {
            _connection.removeConnectionEventListener(_connectionEventListener);
            _connection = null;
        }
    }

    private XAConnection                 _connection;
    private XADataSource                 _dataSource;
    private LocalConnectionEventListener _connectionEventListener;
    private Properties                   _props;
    private String                       _dbName;
    private String                       _user;
    private String                       _password;
    private boolean                      _hasMoreResources;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy