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

com.wizarius.orm.database.DBConnectionPool Maven / Gradle / Ivy

The newest version!
package com.wizarius.orm.database;

import org.apache.log4j.Logger;
import com.wizarius.orm.database.exceptions.DBException;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Shyshkin Vladyslav on 14.03.17.
 */
@SuppressWarnings("unchecked")
public class DBConnectionPool {
    private static final Logger log = Logger.getLogger(DBConnectionPool.class.getName());
    private final ConnectionDriver connectionDriver;
    private final int MIN_OPEN_CONNECTION = 5;
    private final int MAX_OPEN_CONNECTION = 30;
    private ArrayBlockingQueue availableOpenConnections = new ArrayBlockingQueue<>(MAX_OPEN_CONNECTION);
    private AtomicInteger amountAvailableConnections;
    private final Class dbClazz;

    public DBConnectionPool(ConnectionDriver driver, Class clazz) throws DBException {
        log.trace("initialize log to connection pool");
        this.connectionDriver = driver;
        this.dbClazz = clazz;
        this.amountAvailableConnections = new AtomicInteger(0);
        for (int i = 0; i < MIN_OPEN_CONNECTION; i++) {
            addConnection();
        }
    }

    /**
     * Get available connection
     *
     * @return Connection
     * @throws DBException
     */

    public synchronized T getConnection() throws DBException {
        T connection = availableOpenConnections.poll();
        amountAvailableConnections.decrementAndGet();
        while (connection == null) {
            if (amountAvailableConnections.get() >= MAX_OPEN_CONNECTION) {
                throw new DBException("Amount connection exceeds MAX_OPEN_CONNECTION");
            } else {
                openNextConnection();
            }
            connection = availableOpenConnections.poll();
        }
        try {
            //skip closed connection and remove it from available connections
            if (connection.getConnection().isClosed()) {
                log.info("Skip connection because connection is closed");
                return getConnection();
            }
            //в постгресе нельзя делать isValid, он ставит timeout который потом киляет другие запросы
            //https://stackoverflow.com/questions/13114101/postgresql-error-canceling-statement-due-to-user-request
            else if (!connection.checkConnection(3)) {
                log.info("Skip connection because connection isn't valid");
                return getConnection();
            }
        } catch (SQLException e) {
            throw new DBException("Unable to check if connection is closed " + e.getMessage(), e);
        }
        return connection;
    }

    /**
     * User finishes using of connection, return this connection to available array
     *
     * @param connection available connection
     */
    public void releaseConnection(T connection) {
        amountAvailableConnections.incrementAndGet();
        availableOpenConnections.add(connection);
    }

    /**
     * Open next connection if available
     *
     * @throws DBException
     */
    private void openNextConnection() throws DBException {
        int countOpen = 0;
        //open next 3 connection
        if (MAX_OPEN_CONNECTION >= amountAvailableConnections.get() + 3) {
            countOpen = 3;
        }
        //open next 2 connection
        else if (MAX_OPEN_CONNECTION >= amountAvailableConnections.get() + 2) {
            countOpen = 2;
        }
        //open next 1 connection
        else if (MAX_OPEN_CONNECTION >= amountAvailableConnections.get() + 1) {
            countOpen = 1;
        }
        for (int i = 0; i < countOpen; i++) {
            addConnection();
        }
        log.info("Opened next connection current opened connections = " + amountAvailableConnections);
    }

    /**
     * Add connections to pool
     */
    private void addConnection() throws DBException {
        try {
            T connection = dbClazz.getDeclaredConstructor(Connection.class, DBConnectionPool.class)
                    .newInstance(connectionDriver.getConnection(), this);
            try {
                boolean closed = connection.getConnection().isClosed();
                if (closed) {
                    throw new DBException("Connection is closed. Server not available! Where connection address = " + connectionDriver.getURL());
                }
                boolean valid = connection.checkConnection(5);
                if (!valid) {
                    throw new DBException("Unable to open new connection. Server opened non-valid connection. Where connection address = " + connectionDriver.getURL());
                }
                availableOpenConnections.add(
                        connection
                );
                amountAvailableConnections.incrementAndGet();
            } catch (SQLException | DBException e) {
                throw new DBException("Unable to open new connection " + e.getMessage(), e);
            }
        } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            log.error("Unable to create new instance of clazz. Server opened non-valid connection. Where connection address = " + connectionDriver.getURL() + " " + dbClazz + " . " + e.getMessage(), e);
        }
    }

    /**
     * Get amount available connections in pool
     *
     * @return amount available connection
     */
    public int getAvailableConnectionCount() {
        return availableOpenConnections.size();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy