package biz.source_code.miniConnectionPoolManager;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.LinkedList;
import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
private ConnectionPoolDataSource dataSource;
private int maxConnections;
private long timeoutMs;
private PrintWriter logWriter;
private Semaphore semaphore;
private LinkedList<PooledConnection> recycledConnections;
private int activeConnections;
private PoolConnectionEventListener poolConnectionEventListener;
private boolean isDisposed;
private boolean doPurgeConnection;
private static final long serialVersionUID = 1;
super("Timeout while waiting for a free database connection."); }
super(msg); }}
this(dataSource, maxConnections, 60); }
this.dataSource = dataSource;
this.maxConnections = maxConnections;
this.timeoutMs = timeout * 1000L;
try {
logWriter = dataSource.getLogWriter(); }
catch (SQLException e) {}
if (maxConnections < 1) {
throw new IllegalArgumentException("Invalid maxConnections value."); }
semaphore = new Semaphore(maxConnections,true);
recycledConnections = new LinkedList<PooledConnection>();
poolConnectionEventListener = new PoolConnectionEventListener(); }
public synchronized void dispose()
throws SQLException {
if (isDisposed) {
return; }
isDisposed = true;
SQLException e = null;
while (!recycledConnections.isEmpty()) {
PooledConnection pconn = recycledConnections.remove();
try {
pconn.close(); }
catch (SQLException e2) {
if (e == null) {
e = e2; }}}
if (e != null) {
throw e; }}
return getConnection2(timeoutMs); }
private Connection
getConnection2 (
long timeoutMs)
throws SQLException {
synchronized (this) {
if (isDisposed) {
throw new IllegalStateException("Connection pool has been disposed."); }}
try {
if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
throw new TimeoutException(); }}
catch (InterruptedException e) {
throw new RuntimeException("Interrupted while waiting for a database connection.",e); }
boolean ok = false;
try {
Connection conn = getConnection3();
ok = true;
return conn; }
finally {
if (!ok) {
semaphore.release(); }}}
private synchronized Connection
getConnection3()
throws SQLException {
if (isDisposed) {
throw new IllegalStateException("Connection pool has been disposed."); }
PooledConnection pconn;
if (!recycledConnections.isEmpty()) {
pconn = recycledConnections.remove(); }
else {
pconn = dataSource.getPooledConnection();
pconn.addConnectionEventListener(poolConnectionEventListener); }
Connection conn = pconn.getConnection();
activeConnections++;
assertInnerState();
return conn; }
long time = System.currentTimeMillis();
long timeoutTime = time + timeoutMs;
int triesWithoutDelay = getInactiveConnections() + 1;
while (true) {
Connection conn = getValidConnection2(time, timeoutTime);
if (conn != null) {
return conn; }
triesWithoutDelay--;
if (triesWithoutDelay <= 0) {
triesWithoutDelay = 0;
try {
Thread.sleep(250); }
catch (InterruptedException e) {
throw new RuntimeException("Interrupted while waiting for a valid database connection.", e); }}
time = System.currentTimeMillis();
if (time >= timeoutTime) {
throw new TimeoutException("Timeout while waiting for a valid database connection."); }}}
long rtime = Math.max(1, timeoutTime - time);
Connection conn;
try {
conn = getConnection2(rtime); }
catch (SQLException e) {
return null; }
rtime = timeoutTime - System.currentTimeMillis();
int rtimeSecs = Math.max(1, (int)((rtime+999)/1000));
try {
if (conn.isValid(rtimeSecs)) {
return conn; }}
catch (SQLException e) {}
purgeConnection(conn);
return null; }
try {
doPurgeConnection = true;
conn.close(); }
catch (SQLException e) {}
finally {
doPurgeConnection = false; }}
if (isDisposed || doPurgeConnection) {
disposeConnection(pconn);
return; }
if (activeConnections <= 0) {
throw new AssertionError(); }
activeConnections--;
semaphore.release();
recycledConnections.add(pconn);
assertInnerState(); }
pconn.removeConnectionEventListener(poolConnectionEventListener);
if (!recycledConnections.remove(pconn)) {
if (activeConnections <= 0) {
throw new AssertionError(); }
activeConnections--;
semaphore.release(); }
closeConnectionAndIgnoreException(pconn);
assertInnerState(); }
try {
pconn.close(); }
catch (SQLException e) {
log("Error while closing database connection: "+e.toString()); }}
private void log (String msg) {
String s = "MiniConnectionPoolManager: "+msg;
try {
if (logWriter == null) {
System.err.println(s); }
else {
logWriter.println(s); }}
catch (Exception e) {}}
if (activeConnections < 0) {
throw new AssertionError(); }
if (activeConnections + recycledConnections.size() > maxConnections) {
throw new AssertionError(); }
if (activeConnections + semaphore.availablePermits() > maxConnections) {
throw new AssertionError(); }}
PooledConnection pconn = (PooledConnection)event.getSource();
recycleConnection(pconn); }
PooledConnection pconn = (PooledConnection)event.getSource();
disposeConnection(pconn); }}
return activeConnections; }
return recycledConnections.size(); }
}