org.firebirdsql.pool.AbstractConnectionPool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaybird Show documentation
Show all versions of jaybird Show documentation
JDBC Driver for the Firebird RDBMS
/*
* Firebird Open Source J2ee connector - jdbc driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* LGPL License for more details.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a CVS history command.
*
* All rights reserved.
*/
package org.firebirdsql.pool;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.firebirdsql.logging.Logger;
/**
* Abstract class for creating connection pools. Subclasses must implement
* factory method to produce physical connections to the database (method
* {@link #getConnectionManager()} and few utility methods ({@link #getLogger()}
* and {@link #getPoolName}).
*
* @author Roman Rokytskyy
*/
public abstract class AbstractConnectionPool implements PooledObjectListener {
/**
* Structure class to store user name and password.
*/
protected static class UserPasswordPair {
private String userName;
private String password;
public UserPasswordPair() {
this(null, null);
}
public String getUserName() {
return userName;
}
public String getPassword() {
return password;
}
public UserPasswordPair(String userName, String password) {
this.userName = userName;
this.password = password;
}
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null) return false;
if (!(obj instanceof UserPasswordPair)) return false;
UserPasswordPair that = (UserPasswordPair)obj;
boolean equal = true;
equal &= userName != null ?
userName.equals(that.userName) : that.userName == null;
equal &= password != null ?
password.equals(that.password) : that.password == null;
return equal;
}
public int hashCode() {
int result = 3;
result ^= userName != null ? userName.hashCode() : 0;
result ^= password != null ? password.hashCode() : 0;
return result;
}
}
/**
* This constant controls behavior of this class in case of
* severe error situation. Usually, if value of this constant
* is true
, such error condition will result in
* raising either runtime exception or error.
*/
private static final boolean PARANOID_MODE = true;
/**
* This map contains mapping between key and pooled connection queue.
*/
private HashMap connectionQueues = new HashMap();
/**
* This map contains mapping between connection and queue, so we
* easily know to which queue connection should be returned to.
*/
private HashMap connectionToQueueMap = new HashMap();
/**
* Get logger for this instance. By default all log messages belong to
* this class. Subclasses can override this behavior.
*
* @return instance of {@link Logger}.
*/
protected abstract Logger getLogger();
/**
* Create instance of this class.
*/
protected AbstractConnectionPool(){
// empty
}
/**
* Shutdown pool if object is garbage collected.
*
* @throws Throwable if something bad happened.
*/
protected void finalize() throws Throwable {
shutdown();
}
/**
* Restart this JDBC pool. This method restarts all JDBC connections.
*/
public void restart()
{
Iterator iter = connectionQueues.entrySet().iterator();
while(iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
PooledConnectionQueue queue =
(PooledConnectionQueue)entry.getValue();
queue.restart();
}
if (getLogger() != null)
getLogger().info(
"Pool restarted. Pool name was "
+ getPoolName()
+ ".");
}
/**
* Shutdown this JDBC pool. This method closes all JDBC connections
* and marks pool as shut down.
*/
public void shutdown() {
Iterator iter = connectionQueues.entrySet().iterator();
while(iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
PooledConnectionQueue queue =
(PooledConnectionQueue)entry.getValue();
queue.shutdown();
}
if (getLogger() != null)
getLogger().info(
"Pool shutted down. Pool name was "
+ getPoolName()
+ ".");
}
/**
* Get queue for the specified user name and password.
*
* @param key key identifying pool.
*
* @return instance of {@link PooledConnectionQueue}.
*
* @throws SQLException if something went wrong.
*/
public PooledConnectionQueue getQueue(Object key)
throws SQLException
{
synchronized(connectionQueues) {
PooledConnectionQueue queue =
(PooledConnectionQueue)connectionQueues.get(key);
if (queue == null) {
queue = new PooledConnectionQueue(
getConnectionManager(),
getLogger(),
getConfiguration(),
getPoolName(),
key);
queue.start();
connectionQueues.put(key, queue);
}
return queue;
}
}
/**
* Get pooled connection. This method will block until there will be
* free connection to return.
*
* @param queue instance of {@link PooledConnectionQueue} where connection
* will be obtained.
*
* @return instance of {@link PooledObject}.
*
* @throws SQLException if pooled connection cannot be obtained.
*/
protected synchronized PooledObject getPooledConnection(
PooledConnectionQueue queue) throws SQLException
{
PooledObject result;
result = queue.take();
if (result instanceof XPingableConnection) {
boolean isValid = false;
while (!isValid) {
XPingableConnection pingableConnection = (XPingableConnection)result;
long lastPingTime = pingableConnection.getLastPingTime();
long pingInterval = System.currentTimeMillis() - lastPingTime;
isValid = true;
if (getConfiguration().getPingInterval() > 0)
isValid &= pingInterval < getConfiguration().getPingInterval();
if (!isValid && !pingableConnection.ping()) {
if (getLogger() != null)
getLogger().warn(
"Connection " + result
+ " was not valid, trying to get another one.");
// notify queue that invalid connection was destroyed
queue.destroyConnection(result);
// take another one
result = (PooledObject)queue.take();
}
}
}
// save the queue to which this connection belongs to
connectionToQueueMap.put(result, queue);
return result;
}
/**
* Notify about new available connection. This method is called by
* {@link javax.sql.PooledConnection} when its wrapped connection being closed.
*
* @param event instance of {@link PooledObjectEvent} containing
* information about closed connection.
*/
public void pooledObjectReleased(PooledObjectEvent event) {
try {
PooledObject connection =
(PooledObject) event.getSource();
PooledConnectionQueue queue =
(PooledConnectionQueue)connectionToQueueMap.get(connection);
if (queue == null) {
if (getLogger() != null)
getLogger().warn("Connection " + connection +
" does not have corresponding queue");
connectionToQueueMap.remove(connection);
if (PARANOID_MODE)
throw new IllegalStateException(
"Connection " + connection +
" does not have corresponding queue");
else
connection.deallocate();
} else {
if (event.isDeallocated()) {
connectionToQueueMap.remove(connection);
queue.physicalConnectionDeallocated(connection);
} else
queue.put(connection);
}
} catch (SQLException ex) {
if (getLogger() != null)
getLogger().warn("Error releasing connection.", ex);
}
}
/**
* Notify about the deallocation of the physical connection (for example,
* when connection is removed by the idle remover thread).
*
* @param event instance of {@link PooledObjectEvent}.
*/
protected void physicalConnectionDeallocated(PooledObjectEvent event) {
PooledObject connection = (PooledObject) event.getSource();
connectionToQueueMap.remove(connection);
}
/**
* Get configuration of this data source.
*
* @return instance of {@link ConnectionPoolConfiguration} describing
* this data source.
*/
public abstract ConnectionPoolConfiguration getConfiguration();
/**
* Get instance of {@link PooledConnectionManager} responsible for
* instantiating pooled connections.
*
* @return instance of {@link PooledConnectionManager}
*
* @throws SQLException if connection manager cannot be obtained.
*/
protected abstract PooledConnectionManager getConnectionManager()
throws SQLException;
/**
* Get name of the pool. This name will be displayed in log when pool
* is started.
*
* @return name of the connection queue.
*/
protected abstract String getPoolName();
/**
* Get number of free connections in this pool. This method returns the
* number of free open connections to the specified database. It might
* return 0, but this does not mean that next request will block. This
* will happen only if
* getMaxSize() != 0 && getMaxSize() == getWorkingSize()
,
* meaning that we have allocated maximum number of connections and all
* of them are in use.
*
* @return number of free connections left.
*/
public abstract int getFreeSize() throws SQLException;
/**
* Get total size of physical connections opened to the database.
*
* @return total number of opened connections to the database.
*/
public abstract int getTotalSize() throws SQLException;
/**
* Get number of connections that are in use.
*
* @return number of working connections.
*/
public abstract int getWorkingSize() throws SQLException ;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy