org.freebxml.omar.server.persistence.rdb.ConnectionPool.java Source code

Java tutorial

Introduction

Here is the source code for org.freebxml.omar.server.persistence.rdb.ConnectionPool.java

Source

/*
 * ====================================================================
 *
 * This code is subject to the freebxml License, Version 1.1
 *
 * Copyright (c) 2001 - 2003 freebxml.org.  All rights reserved.
 *
 * $Header: /cvsroot/ebxmlrr/omar/src/java/org/freebxml/omar/server/persistence/rdb/ConnectionPool.java,v 1.16 2005/12/14 18:25:35 farrukh_najmi Exp $
 * ====================================================================
 */
package org.freebxml.omar.server.persistence.rdb;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.freebxml.omar.server.util.ServerResourceBundle;

/*
 * $Header: /cvsroot/ebxmlrr/omar/src/java/org/freebxml/omar/server/persistence/rdb/ConnectionPool.java,v 1.16 2005/12/14 18:25:35 farrukh_najmi Exp $
 *
*/
class ConnectionPool {
    private Log log = LogFactory.getLog(this.getClass());
    private String name;
    private String URL;
    private String user;
    private String password;
    private int transactionIsolation;
    private int initConns;
    private int maxConns;
    private int timeOut;
    private HashMap checkedOutConnections = new HashMap();
    private ArrayList freeConnections = new ArrayList();

    /**
    @param timeOut is the time in seconds after this has been elasped but the
    connection cannot be returned, getConnection() will return SQLException
    */
    public ConnectionPool(String name, String URL, String user, String password, int maxConns, int initConns,
            int timeOut, int transactionIsolation) {
        this.name = name;
        this.URL = URL;
        this.user = user;
        this.password = password;
        this.initConns = initConns;
        this.maxConns = maxConns;
        this.timeOut = (timeOut > 0) ? timeOut : 5;
        this.transactionIsolation = transactionIsolation;

        // initialise the pool
        for (int i = 0; i < initConns; i++) {
            try {
                Connection pc = newConnection();
                freeConnections.add(pc);
            } catch (SQLException e) {
                throw new java.lang.reflect.UndeclaredThrowableException(e,
                        ServerResourceBundle.getInstance().getString("message.noConnectionAvailable",
                                new Object[] { new Integer(freeConnections.size()), new Integer(initConns) }));
            }
        }

        if (log.isInfoEnabled()) {
            log.info(ServerResourceBundle.getInstance().getString("message.DatabaseConnectionPoolingEnabled"));
            log.info(getStats());
        }
    }

    public Connection getConnection(String contextId) throws SQLException {
        try {
            //System.err.println("**********getConnection: contextId=" + contextId + " " + getStats());
            if ((maxConns < initConns) || (maxConns <= 0)) {
                throw new SQLException(
                        ServerResourceBundle.getInstance().getString("message.invalidSizeOfConnectionPool"));
            }

            if ((freeConnections.size() == 0) && (initConns != 0)) {
                // for some reasons the pool cannot be initialised
                throw new SQLException(ServerResourceBundle.getInstance().getString("message.noConnectionAvailable",
                        new Object[] { new Integer(freeConnections.size()), new Integer(initConns) }));
            }

            Connection conn = getConnection(contextId, timeOut * 1000);

            return conn;
        } catch (SQLException e) {
            log.trace(getStats());
            throw e;
        }
    }

    private synchronized Connection getConnection(String contextId, long timeout) throws SQLException {
        // Get a pooled Connection from the cache or a new one.
        // Wait if all are checked out and the max limit has
        // been reached.
        long startTime = System.currentTimeMillis();
        long remaining = timeout;
        Connection conn = null;

        while ((conn = getPooledConnection(contextId)) == null) {
            try {
                wait(remaining);
            } catch (InterruptedException e) {
            }

            remaining = timeout - (System.currentTimeMillis() - startTime);

            if (remaining <= 0) {
                // Timeout has expired
                throw new SQLException(
                        ServerResourceBundle.getInstance().getString("message.databaseConnectionTimedOut"));
            }
        }

        // Check if the Connection is still OK
        if (!isConnectionOK(conn)) {
            // It was bad. Try again with the remaining timeout
            return getConnection(contextId, remaining);
        }

        //Got a good connection
        checkedOutConnections.put(conn, contextId);

        return conn;
    }

    private boolean isConnectionOK(Connection connection) {
        Statement testStmt = null;

        try {
            if (!connection.isClosed()) {
                // Try to createStatement to see if it's really alive
                testStmt = connection.createStatement();
                testStmt.close();
            } else {
                return false;
            }
        } catch (SQLException e) {
            if (testStmt != null) {
                try {
                    testStmt.close();
                } catch (SQLException se) {
                }
            }

            return false;
        }

        return true;
    }

    private Connection getPooledConnection(String contextId) throws SQLException {
        Connection conn = null;

        if (freeConnections.size() > 0) {
            // Pick the first Connection in the Vector
            // to get round-robin usage
            conn = (Connection) freeConnections.remove(0);
        } else if (checkedOutConnections.size() < maxConns) {
            conn = newConnection();
        }

        return conn;
    }

    private Connection newConnection() throws SQLException {
        Connection conn = null;

        if ((user == null) || (user.length() == 0)) {
            conn = DriverManager.getConnection(URL);
        } else {
            conn = DriverManager.getConnection(URL, user, password);
        }

        // Set Transaction Isolation and AutoComit
        // WARNING: till present Oracle dirvers (9.2.0.5) do not accept
        // setTransactionIsolation being called after setAutoCommit(false)
        conn.setTransactionIsolation(transactionIsolation);
        conn.setAutoCommit(false);

        return conn;
    }

    public synchronized void freeConnection(Connection conn) throws SQLException {

        String contextId = (String) checkedOutConnections.get(conn);
        checkedOutConnections.remove(conn);
        //System.err.println("    **********freeConnection: contextId=" + contextId + " " + getStats());

        // Put the connection at the end of the Vector
        freeConnections.add(conn);
        notifyAll();
    }

    private String getStats() {
        return "Total connections: " + (freeConnections.size() + checkedOutConnections.size()) + " Available: "
                + freeConnections.size() + " Checked-out: " + checkedOutConnections.size() + " "
                + checkedOutConnections.values().toString();
    }
}