org.eclipse.osee.jdbc.internal.PooledDataSourceFetcher.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.osee.jdbc.internal.PooledDataSourceFetcher.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Boeing.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Boeing - initial API and implementation
 *******************************************************************************/
package org.eclipse.osee.jdbc.internal;

import static org.eclipse.osee.jdbc.JdbcException.newJdbcException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.Callable;
import javax.sql.DataSource;
import org.apache.commons.dbcp.AbandonedConfig;
import org.apache.commons.dbcp.AbandonedObjectPool;
import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.dbcp.PoolingDriver;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.eclipse.osee.framework.jdk.core.type.LazyObject;
import org.eclipse.osee.jdbc.JdbcPoolConfig;
import org.eclipse.osee.jdbc.internal.JdbcConnectionFactoryManager.MetaData;

/**
 * @author Roberto E. Escobar
 */
public class PooledDataSourceFetcher implements Callable<DataSource> {

    private final JdbcConnectionFactoryManager manager;
    private final LazyObject<? extends PoolingDriver> poolingDriver;
    private final JdbcPoolConfig poolConfig;
    private final JdbcConnectionInfo dbInfo;

    public PooledDataSourceFetcher(JdbcConnectionFactoryManager manager,
            LazyObject<? extends PoolingDriver> poolingDriver, JdbcPoolConfig poolConfig,
            JdbcConnectionInfo dbInfo) {
        this.manager = manager;
        this.poolConfig = poolConfig;
        this.poolingDriver = poolingDriver;
        this.dbInfo = dbInfo;
    }

    @Override
    public DataSource call() throws Exception {
        String driverClazz = poolConfig.getPoolConnectionDriver();
        try {
            Class.forName(driverClazz);
        } catch (Exception ex) {
            throw newJdbcException(ex, "Error loading connection pool driver [%s]", driverClazz);
        }

        String poolId = dbInfo.getId();
        ObjectPool<Connection> connectionPool = createConnectionPool();

        PoolingDriver driver = poolingDriver.get();
        driver.registerPool(poolId, connectionPool);

        return new PoolingDataSource(connectionPool);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private ObjectPool<Connection> createConnectionPool() throws Exception {
        MetaData metadata = manager.getMetaData(dbInfo);

        JdbcConnectionFactory proxiedFactory = manager.getFactory(dbInfo.getDriver());
        ConnectionFactory connectionFactory = new ConnectionFactoryProxy(proxiedFactory, dbInfo,
                metadata.isTxIsolationLevelSupported());

        AbandonedObjectPool connectionPool = new AbandonedObjectPool(null,
                getAbandonedConnectionConfig(poolConfig));
        connectionPool.setConfig(getPoolConfig(poolConfig));

        GenericKeyedObjectPoolFactory statementPool = null;
        if (poolConfig.isPoolPreparedStatementsAllowed()) {
            statementPool = new GenericKeyedObjectPoolFactory(null, getStatementPoolConfig(poolConfig));
        }
        AbandonedConfig abandoned = new AbandonedConfig();
        abandoned.setLogAbandoned(true);
        abandoned.setLogWriter(new PrintWriter(System.out));

        String validationQuery = metadata.getValidationQuery();
        int validationQueryTimeoutSecs = poolConfig.getPoolValidationQueryTimeoutSecs();
        boolean defaultReadOnly = false;
        boolean defaultAutoCommit = true;
        new PoolableConnectionFactory(connectionFactory, connectionPool, statementPool, validationQuery,
                validationQueryTimeoutSecs, defaultReadOnly, defaultAutoCommit);
        return connectionPool;
    }

    private GenericObjectPool.Config getPoolConfig(JdbcPoolConfig config) {
        GenericObjectPool.Config toReturn = new GenericObjectPool.Config();
        toReturn.maxActive = config.getPoolMaxActiveConnections();
        toReturn.maxIdle = config.getPoolMaxIdleConnections();
        toReturn.minIdle = config.getPoolMinIdleConnections();
        toReturn.maxWait = config.getPoolMaxWaitForConnection();
        toReturn.whenExhaustedAction = config.getPoolExhaustedAction().asByteValue();
        toReturn.testOnBorrow = config.isPoolTestOnBorrowEnabled();
        toReturn.testOnReturn = config.isPoolTestOnReturnEnabled();
        toReturn.testWhileIdle = config.isPoolTestWhileIdeEnabled();
        toReturn.timeBetweenEvictionRunsMillis = config.getPoolTimeBetweenEvictionCheckMillis();
        toReturn.numTestsPerEvictionRun = config.getPoolNumberTestsPerEvictionRun();
        toReturn.minEvictableIdleTimeMillis = config.getPoolMinEvictableIdleTimeMillis();
        toReturn.lifo = config.isPoolLifo();
        toReturn.softMinEvictableIdleTimeMillis = config.getPoolSoftMinEvictableTimeoutMillis();
        return toReturn;
    }

    private GenericKeyedObjectPool.Config getStatementPoolConfig(JdbcPoolConfig config) {
        GenericKeyedObjectPool.Config toReturn = new GenericKeyedObjectPool.Config();

        toReturn.maxTotal = config.getPoolMaxTotalPreparedStatements();
        toReturn.maxActive = config.getPoolMaxActivePreparedStatements();
        toReturn.maxIdle = config.getPoolMaxIdlePreparedStatements();
        toReturn.minIdle = config.getPoolMinIdlePreparedStatements();
        toReturn.maxWait = config.getPoolMaxWaitPreparedStatements();

        // Same as Connection Pool
        toReturn.whenExhaustedAction = config.getPoolExhaustedAction().asByteValue();
        toReturn.testOnBorrow = config.isPoolTestOnBorrowEnabled();
        toReturn.testOnReturn = config.isPoolTestOnReturnEnabled();
        toReturn.testWhileIdle = config.isPoolTestWhileIdeEnabled();
        toReturn.timeBetweenEvictionRunsMillis = config.getPoolTimeBetweenEvictionCheckMillis();
        toReturn.numTestsPerEvictionRun = config.getPoolNumberTestsPerEvictionRun();
        toReturn.minEvictableIdleTimeMillis = config.getPoolMinEvictableIdleTimeMillis();
        toReturn.lifo = config.isPoolLifo();
        return toReturn;
    }

    private AbandonedConfig getAbandonedConnectionConfig(JdbcPoolConfig config) {
        AbandonedConfig abandoned = new AbandonedConfig();
        abandoned.setLogAbandoned(config.isPoolAbandonedLoggingEnabled());
        abandoned.setRemoveAbandoned(config.isPoolAbandonedRemovalEnabled());
        abandoned.setRemoveAbandonedTimeout(config.getPoolAbandonedRemovalTimeout());
        return abandoned;
    }

    private static final class ConnectionFactoryProxy implements ConnectionFactory {
        private final JdbcConnectionFactory proxiedFactory;
        private final JdbcConnectionInfo dbInfo;

        private final boolean supportsIsolationLevel;

        public ConnectionFactoryProxy(JdbcConnectionFactory proxiedFactory, JdbcConnectionInfo dbInfo,
                boolean supportsIsolationLevel) {
            super();
            this.proxiedFactory = proxiedFactory;
            this.dbInfo = dbInfo;
            this.supportsIsolationLevel = supportsIsolationLevel;
        }

        @Override
        public Connection createConnection() throws SQLException {
            Connection connection = null;
            try {
                connection = proxiedFactory.getConnection(dbInfo);
                if (supportsIsolationLevel) {
                    connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
                }
            } catch (Exception ex) {
                if (connection != null) {
                    try {
                        connection.close();
                    } catch (SQLException ex1) {
                        // Do nothing on close exception;
                    }
                }
                if (ex instanceof SQLException) {
                    throw (SQLException) ex;
                } else {
                    throw new SQLException(ex);
                }
            }
            return connection;
        }
    }
}