/*
* $Id: ConnectionAccessQueue.java,v 1.7 2002/09/16 08:05:03 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.database;
import java.util.ArrayList;
/**
* <code>ConnectionAccessQueue</code> is used by <code>ConnectionManager</code>
* when acquiring connections from the pool. Queue handles the situations when connections
* are not immediately available by letting threads to wait
* for certain (limited) amount of time. Queue implements
* <code>ConnectionObserver</code> through which the notifications
* of available are made by the pool.
*
* @see ConnectionManager
* @see ConnectionManager#acquire(String)
* @see ConnectionPool
* @see ConnectionPool#acquire
* @see ConnectionObserver
* @see PooledConnection
* @version $Revision: 1.7 $
* @author Jani Lehtimki
*/
public class ConnectionAccessQueue implements ConnectionObserver
{
/**
* Maximum time to wait for connections, in milliseconds.
*/
private int acquireTimeout;
/**
* ConnectionPool.
*/
private ConnectionPool pool;
/**
* Vector of waiting threads.
*/
private ArrayList queue = new ArrayList();
/**
* System still running?
*/
private boolean running = true;
/**
* Constructs the queue.
*
* @param pool Connection pool
* @param timeout Acquire timeout
*/
public ConnectionAccessQueue(ConnectionPool pool)
{
this.pool = pool;
this.acquireTimeout = pool.getConnectionAcquireTimeout();
pool.setObserver(this);
}
/**
* Gets the connection pool of this queue.
*
* @return Connection pool
*/
public ConnectionPool getPool()
{
return pool;
}
/**
* Acquire the connection from the pool, waiting for only specified
* amount of time.
*
* @param timeout Timeout override (if > 0)
* @return Connection
* @throws CannotReturnPooledConnectionException If acquire timed out
*/
public PooledConnection acquire(int timeout)
throws CannotReturnPooledConnectionException
{
PooledConnection conn = null;
Thread currentThread = Thread.currentThread();
long started = System.currentTimeMillis();
long bailout = acquireTimeout;
Exception lastException = null;
while (running) {
/*
* Thread need to be added to queue first before ConnectionPool.acquire()
* in order to ensure that connectionsAvailable() notifications
* aren't missed at any point.
*/
synchronized (queue) {
if (queue.contains(currentThread) == false) {
queue.add(currentThread);
}
}
/*
* Try to acquire connection and break from the loop
* if we got one.
*/
try {
conn = pool.acquire(timeout);
} catch (Exception e) {
lastException = e;
}
if (conn != null) {
break;
}
/*
* Do we still have time left?
*/
bailout = bailout - (System.currentTimeMillis() - started);
if (bailout <= 0) {
break;
}
/*
* Wait for connectionsAvailable() notification
*/
try {
currentThread.sleep(bailout);
} catch (InterruptedException exception) {}
}
/*
* Clear the interrupted status of thread in case Thread.sleep()
* was missed.
*/
currentThread.interrupted();
synchronized (queue) {
queue.remove(currentThread);
}
/*
* Are we shutting down? Pool will take care about
* the connection we possibly just received.
*/
if (running == false) {
throw new CannotReturnPooledConnectionException("System is shutting down");
}
/*
* Do we have timeout?
*/
long duration = System.currentTimeMillis() - started;
if (conn == null) {
pool.connectionAcquireTimedout(pool, duration);
if (lastException == null) {
throw new CannotReturnPooledConnectionException("Acquire timed out");
} else {
throw new CannotReturnPooledConnectionException(
"Acquire timed out: "+lastException.getMessage());
}
}
pool.connectionReserved(conn, duration);
return conn;
}
/**
* Notification from connection observer interface. Interrupt the first
* thread waiting in queue.
*/
public void connectionsAvailable()
{
synchronized(queue) {
if (queue.size()>0) {
Thread sleepingThread = (Thread)queue.remove(0);
sleepingThread.interrupt();
}
}
}
/**
* Shuts down the queue, delegating the request to connection pool and
* interrupting all threads waiting for connection.
*/
void stop()
{
running = false;
pool.stop();
synchronized(queue) {
int n = queue.size();
for (int i = 0; i < n; i++) {
Thread sleepingThread = (Thread)queue.get(i);
sleepingThread.interrupt();
}
queue.clear();
}
}
}
|