📄 connectionpool.java
字号:
package org.jahia.services.database;import java.sql.*;import java.util.*;import org.jahia.utils.*; // JahiaConsole/** * <p>Title: ConnectionPool </p> * <p>Description: manages a connection pool to a JDBC database. This * implementation uses threads to create connection on demand, and * synchronisation to wait for the created connections</p> * <p>Basically the only interesting methods in here are the constructor, * the getConnection and the free methods. The rest will only be needed * in some status cases, etc..</p> * <p>Copyright: Copyright (c) 2002</p> * <p>Company: Jahia Inc.</p> */public class ConnectionPool implements Runnable{ private String db_driver; private String db_url; private String db_username; private String db_password; private int minConnections; private int maxConnections; private boolean waitIfBusy; // the vector of connections that are available in the pool private Vector availableConnections = new Vector(); // the vector of connections that are unavailable in the pool, // currently busy processing requests private Vector busyConnections = new Vector(); // connectionPending is true if there is a thread currently // opening a connection to the database private boolean connectionPending = false; // used to display debug messages if activated in constructor private boolean verbose = true; /** * Constructor for a connection pool object. * @param db_driver JDBC driver name to use * @param db_url JDBC URL to use to connect to the database * @param db_username JDBC username to connect to the database * @param db_password JDBC password to connect to the database * @param initialConnections number of initial connection to initialize * the pool with * @param maxConnections maximum number of database connections open * simultaneously in pool * @param waitIfBusy boolean that indicates if we should wait if all * the connections in the pool are already occupied, otherwise will * return with an exception * @param verbose boolean that activates debug messages for the * pool, helping debugging and diagnosticating database connection * problems (such as connection timeout, etc...) * @throws SQLException */ public ConnectionPool( String db_driver, String db_url, String db_username, String db_password, int initialConnections, int maxConnections, boolean waitIfBusy, boolean verbose ) throws SQLException { toConsole( "ConnectionPool", "New connection pool object in creation... " ); // sets private vars this.db_driver = db_driver; this.db_url = db_url; this.db_username = db_username; this.db_password = db_password; this.minConnections = initialConnections; this.maxConnections = maxConnections; this.waitIfBusy = waitIfBusy; this.verbose = verbose; toConsole("ConnectionPool", "verbose is " + verbose ); // nothing's foolproof... if (initialConnections > maxConnections) { initialConnections = maxConnections; } availableConnections = new Vector(initialConnections); // create initial connections for (int i=0; i < initialConnections; i++) { availableConnections.addElement( makeNewConnection() ); } } // end ConnectionPool /** * Retrieves a connection from the connection pool, creating it if * necessary * @param debugID an identifier useful for debugging retrieval and * freeing connection pool entries * @return a JDBC connection object that is an open connection to the * database * @throws SQLException */ public synchronized Connection getConnection(int debugID) throws SQLException { toConsole( "getConnection" , "Trying to serve (DEBUGID : "+debugID+"; available : " + availableConnections.size() + "; busy : " + busyConnections.size() + ")" ); // quick sanity check if (getTotalConnections() < minConnections) { toConsole("getConnection", "Warning : current number of connnections below minimum pool size !"); } // checks it there are available connections left if (!availableConnections.isEmpty()) { // if yes, grab a connection Connection existingConnection = (Connection) availableConnections.lastElement(); int lastIndex = availableConnections.size() - 1; // remove the connection we just taked availableConnections.removeElementAt( lastIndex ); // check if the connection is still open if (existingConnection.isClosed()) { toConsole( "getConnection", "Connection retrieved from available connection is already closed, waiting for a new one ..."); // if closed, notify all waiting threads that a connection can be created notifyAll(); // then retry return ( getConnection(90) ); } else { // not closed, add the connection to the busyConnections array // and return it busyConnections.addElement( existingConnection ); return existingConnection; } } else { // if no more connections available // check if we can add a connection (max not reached) if ((getTotalConnections() < maxConnections) && (!connectionPending)) { // create one connection in the background makeBackgroundConnection(); } else if (!waitIfBusy) { // can't add new connections // can't wait // => scream !! throw new SQLException( "Connection limit reached" ); } // try to grab one try { // wait that one frees up wait(); } catch (InterruptedException ie) { // then go and grab it ! } return ( getConnection(91) ); } } // end getConnection /** * Creates a database connection using a thread to initialize it. * @todo FIXME : what happens when OutOfMemoryError occurs ? */ private void makeBackgroundConnection() { toConsole( "makeBackgroundConnection" , "Creating a background Connection via a thread" ); // we're trying to create a new connection here connectionPending = true; // launch the background thread try { Thread connectionThread = new Thread( this ); connectionThread.start(); // calls the run() method } catch (OutOfMemoryError memError) { toConsole ( "makeBackGroundConnection", "Out of memory exception during background thread connnection creation"); JahiaConsole.printe("ConnectionPool.makeBackgroundConnection", memError); // scream ! } } // makeBackgrounConnection /** * Method called when the thread is created to run the creation of a * single database connection. * @todo FIXME : what happens when SQLException or OutOfMemoryError ? */ public void run() { toConsole( "run", "Starting a new ConnectionPool Thread to create a database connnection" ); try { // try to create a new connection Connection newConnection = makeNewConnection(); synchronized( this ) { // stores it in the available connection array availableConnections.addElement( newConnection ); // end of the operation -> connection is no more pending connectionPending = false; // say to all waiting threads that a new connection is ready notifyAll(); } } catch (Exception e) { JahiaConsole.printe("ConnectionPool.run", e); // SQLException or OutOfMemoryError // scream ! } } // end run /** * Creates a single database connection and returns it * @return a JDBC connection object that has been opened * @throws SQLException an exception generated in case of problems * opening the connection to the database */ private Connection makeNewConnection() throws SQLException { toConsole( "makeNewConnection", "Creating a new connection" ); try { // load database driver Class.forName( db_driver ); // establish connection Connection newConnection = DriverManager.getConnection( db_url, db_username, db_password ); return newConnection; } catch (ClassNotFoundException cnfe) { // scream !! throw new SQLException( "Can't find class to driver : " + db_driver ); } } // end run /** * Frees a connection and returns it into the pool of connections. * @param theConnection the connnection to return into the available * pool * @todo FIXME does not verify the status of the connection, maybe we * want to introduce that later for better stability ? */ public synchronized void free( Connection theConnection ) { toConsole( "free", "Trying to free a connection (available : " + availableConnections.size() + "; busy : " + busyConnections.size() + ")" ); // remove connection form busyConnections array busyConnections.removeElement( theConnection ); // add it to the availableConnecitons array availableConnections.addElement( theConnection ); // notify all waiting threads that a new connection is free notifyAll(); } // end free /** * Returns the number of connections both in the busy state and in * the available pool. Basically this returns the number of connections * to the database that are handled by this connection pool at the * current time * @return an integer representing the sum of the available pool and * the currently used connections. */ public synchronized int getTotalConnections() { return ( availableConnections.size() + busyConnections.size() ); } // end totalConnections /** * Returns the number of available connections in the pool. * @return an integer that represents the size of the available * connections. */ public int getNbFreeConnections() { return ( availableConnections.size() ); } // end totalFreeConnections /** * Returns the number of connections managed by this pool that are not * available (ie are busy handling SQL queries) * @return an integer representing the number of busy queries */ public int getBusyConnections() { return busyConnections.size(); } /** * Returns the configured minimum size of the connection pool * @return an integer representing the minimum size of the pool as * configured via the constructor */ public int getMinConnections() { return this.minConnections; } /** * Returns the configured maximum size of the connection pool * @return an integer representing the maximum size of the pool as configured * via the constructor */ public int getMaxConnections() { return this.maxConnections; } /** * This method is used mostly to destroy all the connections managed * by this pool. This should ONLY be called in extreme cases such as * a requested shutdown as it does NOT reinitialize the pool and doesn't * re-open any connections. Please use with caution. */ public synchronized void closeAllConnections() { toConsole( "closeAllConnections", "Closing all connections !" ); closeConnections( availableConnections ); availableConnections = new Vector(); closeConnections( busyConnections ); busyConnections = new Vector(); } // end closeAllConnections /** * Closes a vector of connections. * @param connections a vector of connection objects */ private void closeConnections( Vector connections ) { toConsole( "closeConnections", "Closing connection" ); try { for (int i=0; i < connections.size(); i++) { Connection theConnection = (Connection) connections.elementAt( i ); if (!theConnection.isClosed()) { theConnection.close(); } } } catch (SQLException se) { JahiaConsole.printe("ConnectionPool.closeConnections", se); // anyway... garbage collector's taking care of the dirty work } } // end closeConnections /** * Displays a message on the Jahia console. Do not use this method * to display exceptions but prefer the use of JahiaConsole.printe() * instead. * @param method name of the method for which to display this message * @param msg the message itself to display */ private void toConsole( String method, String msg ) { if (verbose) { JahiaConsole.println("ConnectionPool." + method, msg ); } } // end toConsole}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -