// *** This version of MiniConnectionPoolManager has been modified by Daniel Jurado *** // // Copyright 2007 Christian d'Heureuse, www.source-code.biz // // This module is multi-licensed and may be used under the terms // of any of the following licenses: // // EPL, Eclipse Public License, http://www.eclipse.org/legal // LGPL, GNU Lesser General Public License, http://www.gnu.org/licenses/lgpl.html // MPL, Mozilla Public License 1.1, http://www.mozilla.org/MPL // // This module is provided "as is", without warranties of any kind. package br.com.gennex.connectionpool; import java.security.InvalidParameterException; import java.sql.Connection; import java.sql.SQLException; import java.util.Calendar; import java.util.EmptyStackException; import java.util.Iterator; import java.util.PriorityQueue; import java.util.Queue; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import javax.sql.ConnectionEvent; import javax.sql.ConnectionEventListener; import javax.sql.ConnectionPoolDataSource; import javax.sql.PooledConnection; import org.apache.log4j.Logger; /** * A simple standalone JDBC connection pool manager. *
* The public methods of this class are thread-safe. *
* Author: Christian d'Heureuse (www.source-code.biz)
* Multi-licensed: EPL/LGPL/MPL.
*
* 2007-06-21: Constructor with a timeout parameter added.
* 2008-05-03: Additional licenses added (EPL/MPL).
* 2009-06-24 Daniel Jurado: Changed from a Stack to a Queue so it is possible do recycle more
* efficiently.
* 2009-06-25 Daniel Jurado: Timeout to handle and idle connection.
* 2009-12-07 Carlos Vizcaino: Shutting timer on dispose, timer was preventing
* Tomcat from shutting down within 60 secs.
* 2010-06-12 Christian d'Heureuse (thanks to Tal Liron):
* Timer task changed to use Iterator.remove() instead of
* LinkedList.remove() to prevent ConcurrentModificationException.
*/
public class MiniConnectionPoolManager {
/**
* Object to hold the Connection under the queue, with a TimeStamp.
*
* @author Daniel Jurado
*/
private class PCTS implements Comparabletimeout
seconds.
*/
public static class TimeoutException extends RuntimeException {
private static final long serialVersionUID = 1;
public TimeoutException() {
super("Timeout while waiting for a free database connection.");
}
}
private ConnectionPoolDataSource dataSource;
private int maxConnections;
private int maxIdleConnectionLife;
private int timeout;
private Semaphore semaphore;
private QueueConnection
objects that have been issued by
* {@link #getConnection()} for which Connection.close()
has
* not yet been called.
*
* @return the number of active connections.
**/
public synchronized int getActiveConnections() {
return activeConnections;
}
/**
* Retrieves a connection from the connection pool. If
* maxConnections
connections are already in use, the method
* waits until a connection becomes available or timeout
* seconds elapsed. When the application is finished using the connection,
* it must close it in order to return it to the pool.
*
* @return a new Connection object.
* @throws TimeoutException
* when no connection becomes available within
* timeout
seconds.
*/
public Connection getConnection() throws SQLException {
// This routine is unsynchronized, because semaphore.tryAcquire() may
// block.
synchronized (this) {
if (isDisposed)
throw new IllegalStateException(
"Connection pool has been disposed.");
}
try {
if (!semaphore.tryAcquire(timeout, TimeUnit.SECONDS))
throw new TimeoutException();
} catch (InterruptedException e) {
throw new RuntimeException(
"Interrupted while waiting for a database connection.", e);
}
boolean ok = false;
try {
Connection conn = getConnection2();
ok = true;
return conn;
} finally {
if (!ok)
semaphore.release();
}
}
private synchronized Connection getConnection2() throws SQLException {
if (isDisposed)
throw new IllegalStateException(
"Connection pool has been disposed."); // test again with
// lock
PooledConnection pconn;
if (recycledConnections.size() > 0) {
PCTS pcts = recycledConnections.poll();
if (pcts == null)
throw new EmptyStackException();
pconn = pcts.getPConn();
} else {
pconn = dataSource.getPooledConnection();
}
Connection conn = pconn.getConnection();
activeConnections++;
pconn.addConnectionEventListener(poolConnectionEventListener);
assertInnerState();
return conn;
}
private void log(String msg) {
Logger.getLogger(getClass()).error(msg);
}
private synchronized void recycleConnection(PooledConnection pconn) {
if (isDisposed) {
disposeConnection(pconn);
return;
}
if (activeConnections <= 0)
throw new AssertionError();
activeConnections--;
semaphore.release();
recycledConnections.add(new PCTS(pconn));
assertInnerState();
}
}