连接池门面类,该类使用java门面模式,统一处理连接池相关操作
package org.logicalcobwebs.proxool;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.logicalcobwebs.proxool.admin.Admin;
import org.logicalcobwebs.proxool.admin.SnapshotIF;
import org.logicalcobwebs.proxool.admin.StatisticsIF;
import org.logicalcobwebs.proxool.admin.StatisticsListenerIF;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
/**
* <p>This provides some nice-to-have features that can't be provided by the
* {@link java.sql.Driver} {@link ProxoolDriver implementation} of java.sql.Driver. Like starting up
* a pool before you need a connection. And getting statistical information.</p>
*
* <p>You need to use this class wisely. It is obviously specfic to proxool so it will
* stop you switching to another driver. Consider isolating the code that calls this
* class so that you can easily remove it if you have to.</p>
*
* @version $Revision: 1.87 $, $Date: 2007/05/15 23:00:22 $
* @author billhorsman
* @author $Author: billhorsman $ (current maintainer)
*/
public class ProxoolFacade {
private static final Log LOG = LogFactory.getLog(ProxoolFacade.class);
private static Map configurators = new HashMap();
private static CompositeProxoolListener compositeProxoolListener = new CompositeProxoolListener();
private static boolean versionLogged = false;
/**
* This is the thread that has been registered with {@link Runtime} as a
* shutdownHook. It is removed during shutdown.
*/
private static Thread shutdownHook;
/**
* If you setthis to false then it us up to you to call shutdown explicitly
* @see #shutdown(String, int)
*/
private static boolean shutdownHookEnabled = true;
/**
* Build a ConnectionPool based on this definition and then start it.
* @param url defines the delegate driver and delegate url.
* @param info the properties used to configure Proxool (and any for the delegate driver too) - optional
* @return the alias for this pool (or the full url if no alias is specified)
* @throws ProxoolException if anything goes wrong
*/
public static synchronized String registerConnectionPool(String url, Properties info) throws ProxoolException {
return registerConnectionPool(url, info, true);
}
/**
* Build a ConnectionPool based on this definition and then start it.
* @param url defines the delegate driver and delegate url.
* @param info the properties used to configure Proxool (and any for the delegate driver too) - optional
* @param explicitRegister set to true if we are registering a new pool explicitly, or false
* if it's just because we are serving a url that we haven't come across before
* @return the alias for this pool (or the full url if no alias is specified)
* @throws ProxoolException if anything goes wrong
*/
protected static synchronized String registerConnectionPool(String url, Properties info, boolean explicitRegister) throws ProxoolException {
String alias = getAlias(url);
if (!versionLogged) {
versionLogged = true;
LOG.info("Proxool " + Version.getVersion());
}
try {
Class.forName(ProxoolDriver.class.getName());
} catch (ClassNotFoundException e) {
LOG.error("Couldn't load " + ProxoolDriver.class.getName());
}
if (!ConnectionPoolManager.getInstance().isPoolExists(alias)) {
ConnectionPoolDefinition cpd = new ConnectionPoolDefinition(url, info, explicitRegister);
registerConnectionPool(cpd);
} else {
throw new ProxoolException("Attempt to register duplicate pool called '" + alias + "'");
}
return alias;
}
protected synchronized static void registerConnectionPool(ConnectionPoolDefinition connectionPoolDefinition) throws ProxoolException {
// check isPoolExists once more now we are inside synchronized block.
if (!ConnectionPoolManager.getInstance().isPoolExists(connectionPoolDefinition.getAlias())) {
Properties jndiProperties = extractJndiProperties(connectionPoolDefinition);
ConnectionPool connectionPool = ConnectionPoolManager.getInstance().createConnectionPool(connectionPoolDefinition);
connectionPool.start();
compositeProxoolListener.onRegistration(connectionPoolDefinition, connectionPoolDefinition.getCompleteInfo());
if (isConfiguredForJMX(connectionPoolDefinition.getCompleteInfo())) {
registerForJmx(connectionPoolDefinition.getAlias(), connectionPoolDefinition.getCompleteInfo());
}
if (jndiProperties != null) {
registerDataSource(connectionPoolDefinition.getAlias(), jndiProperties);
}
} else {
LOG.debug("Ignoring duplicate attempt to register " + connectionPoolDefinition.getAlias() + " pool");
}
}
/**
* With no configurator or properties (using default values)
* @see #registerConnectionPool(java.lang.String, java.util.Properties)
*/
public static void registerConnectionPool(String url) throws ProxoolException {
registerConnectionPool(url, null);
}
/**
* Extracts the pool alias from the url:
*
* proxool.alias:driver:url -> alias
* proxool.alias -> alias
*
* @return the alias defined within the url
* @throws ProxoolException if we couldn't find the alias
*/
protected static String getAlias(String url) throws ProxoolException {
String alias = null;
final String prefix = ProxoolConstants.PROXOOL + ProxoolConstants.ALIAS_DELIMITER;
// Check that the prefix is there
if (url.startsWith(prefix)) {
// Check for the alias
int endOfPrefix = url.indexOf(ProxoolConstants.URL_DELIMITER);
if (endOfPrefix > -1) {
alias = url.substring(prefix.length(), endOfPrefix);
} else {
alias = url.substring(prefix.length());
}
}
// Check we found it.
if (alias == null || alias.length() == 0) {
throw new ProxoolException("The URL '" + url + "' is not in the correct form. It should be: 'proxool.alias:driver:url'");
}
return alias;
}
/**
* Remove a connection pool. Kills all the connections. Resets everything.
* @param finalizer the name of the thread requesting shutdown (for logging)
* @param connectionPool the pool to remove
* @param delay the time to wait for connections to become inactive before killing it (milliseconds)
*/
private static void removeConnectionPool(String finalizer, ConnectionPool connectionPool, int delay) {
final String alias = connectionPool.getDefinition().getAlias();
if (connectionPool != null) {
try {
compositeProxoolListener.onShutdown(alias);
connectionPool.shutdown(delay, finalizer);
} catch (Throwable t) {
LOG.error("Problem trying to shutdown '" + alias + "' connection pool", t);
}
}
connectionPool = null;
}
/**
* Remove a connection pool. Kills all the connections. Resets everything.
* @param alias the pool to remove
* @param delay the time to wait for connections to become inactive before killing it (milliseconds)
* @throws ProxoolException if we couldn't find the pool
*/
public static void removeConnectionPool(String alias, int delay) throws ProxoolException {
removeConnectionPool(Thread.currentThread().getName(), ConnectionPoolManager.getInstance().getConnectionPool(alias), delay);
}
/**
* Removes all connection pools. Kills all the connections. Resets everything.
* @param delay the time to wait for connections to become inactive before killing it (milliseconds)
* @deprecated use the better named {@link #shutdown(int) shutdown()} instead.
*/
public static void removeAllConnectionPools(int delay) {
shutdown(Thread.currentThread().getName(), delay);
}
/**
* Removes all connection pools. Kills all the connections. Resets everything.
* Like {@link #shutdown(java.lang.String, int)} but passes the current thread name
* and a delay of zero.
*/
public static void shutdown() {
shutdown(Thread.currentThread().getName(), 0);
}
/**
* Removes all connection pools. Kills all the connections. Resets everything.
* Like {@link #shutdown(java.lang.String, int)} but passes the current thread name.
* @param delay the time to wait for connections to become inactive before killing it (milliseconds)
*/
public static void shutdown(int delay) {
shutdown(Thread.currentThread().getName(), delay);
}
/**
* Removes all connection pools. Kills all the connections. Resets everything.
* @param finalizer used to identify who is causing the pools to be removed (helps logging)
* @param delay the time to wait for connections to become inactive before killing it (milliseconds)
*/
protected static void shutdown(String finalizer, int delay) {
ConnectionPool[] cps = ConnectionPoolManager.getInstance().getConnectionPools();
for (int i = 0; i < cps.length; i++) {
removeConnectionPool(finalizer, cps[i], delay);
}
// If a shutdown hook was registered then remove it
try {
if (shutdownHook != null) {
ShutdownHook.remove(shutdownHook);
}
} catch (Throwable t) {
if (LOG.isDebugEnabled()) {
LOG.debug("Unanticipated error during removal of ShutdownHook. Ignoring it.", t);
}
}
// Stop threads
PrototyperController.shutdown();
HouseKeeperController.shutdown();
}
/**
* If you call this then you'll have to call shutdown explicitly
* @see #shutdown(String, int)
*/
public static void disableShutdownHook() {
ProxoolFacade.shutdownHookEnabled = false;
}
/**
* Call this if you change your mind about {@link #disableShutdownHook() disabling} it.
* The default behaviour is to have it enabled so unless you have disabled it then
* there's nothing to do.
*/
public static void enableShutdownHook() {
ProxoolFacade.shutdownHookEnabled = true;
}
/**
* Whether the {@link ShutdownHook} should do anything.
* @see #disableShutdownHook()
* @see #enableShutdownHook()
* @return true if the shutdown hook should clean up
*/
public static boolean isShutdownHookEnabled() {
return shutdownHookEnabled;
}
/**
* Like {@link #removeConnectionPool(java.lang.String, int)} but uses no delay. (Kills
* everything as quickly as possible).
* @param alias to identify the pool
* @throws ProxoolException if we couldn't find the pool
*/
public static void removeConnectionPool(String alias) throws ProxoolException {
removeConnectionPool(alias, 0);
}
/**
* Get real-time statistical information about how a pool is performing.
* @param alias to identify the pool
* @return the statistics
* @throws ProxoolException if we couldn't find the pool
* @deprecated use {@link #getSnapshot}
*/
public static ConnectionPoolStatisticsIF getConnectionPoolStatistics(String alias) throws ProxoolException {
return ConnectionPoolManager.getInstance().getConnectionPool(alias);
}
/**
* Get real-time statistical information about how a pool is performing.
* and extract the information piece by piece.
* @param alias to identify the pool
* @return a horrible string describing the statistics
* @throws ProxoolException if we couldn't find the pool
* @deprecated use {@link #getSnapshot}
*/
public static String getConnectionPoolStatisticsDump(String alias) throws ProxoolException {
return ConnectionPoolManager.getInstance().getConnectionPool(alias).displayStatistics();
}
/**
* Get the definition of a pool.
* @param alias identifies the pool
* @throws ProxoolException if we couldn't find the pool
*/
public static ConnectionPoolDefinitionIF getConnectionPoolDefinition(String alias) throws ProxoolException {
return ConnectionPoolManager.getInstance().getConnectionPool(alias).getDefinition();
}
/**
* Get details on each connection within the pool. This can tell you which ones are active, how long they have
* been active, etc.
* @param alias identifies the pool
* @return a collection of {@link ConnectionInfoIF ConnectionInfoIFs}
* @throws ProxoolException if we couldn't find the pool
* @deprecated use {@link #getSnapshot(java.lang.String, boolean) snapshot} instead.
*/
public static Collection getConnectionInfos(String alias) throws ProxoolException {
return ConnectionPoolManager.getInstance().getConnectionPool(alias).getConnectionInfos();
}
/**
* Kill all connections in a pool. The pool continues to work however, and new connections will be
* made as required.
* @param alias the pool containing the connection
* @param merciful if true will only kill connections that aren't active
* @throws ProxoolException if we couldn't find the pool
* @deprecated use {@link #killAllConnections(java.lang.String, java.lang.String, boolean) alternative}
* to provide better auditing in log
*/
public static void killAllConnections(String alias, boolean merciful) throws ProxoolException {
killAllConnections(alias, "of thread " + Thread.currentThread().getName(), merciful);
}
/**
* Kill all connections in a pool. The pool continues to work however, and new connections will be
* made as required.
* @param alias the pool containing the connection
* @param reason provides audit in log of why connections were killed
* @param merciful if true will only kill connections that aren't active
* @throws ProxoolException if we couldn't find the pool
*/
public static void killAllConnections(String alias, String reason, boolean merciful) throws ProxoolException {
ConnectionPoolManager.getInstance().getConnectionPool(alias).expireAllConnections(ConnectionListenerIF.MANUAL_EXPIRY, reason, merciful);
}
/**
* Like {@link #killAllConnections} but defaults to merciful.
* @param alias to identify the pool
* @throws ProxoolException if we couldn't find the pool
* @deprecated use {@link #killAllConnections(java.lang.String, java.lang.String) alternative}
* to provide better auditing in log
*/
public static void killAllConnections(String alias) throws ProxoolException {
killAllConnections(alias, "of thread " + Thread.currentThread().getName(), MERCIFUL);
}
/**
* Like {@link #killAllConnections} but defaults to merciful.
* @param alias to identify the pool
* @param reason provides audit in log of why connections were killed
* @throws ProxoolException if we couldn't find the pool
*/
public static void killAllConnections(String alias, String reason) throws ProxoolException {
killAllConnections(alias, reason, MERCIFUL);
}
/**
* Kill a single connection
* @param alias the pool containing the connection
* @param id the id of the specific connection
* @param merciful if true will only kill connections that aren't active
* @return true if the connection was killed, or false if it couldn't be found.
* @throws ProxoolException if we couldn't find the pool
*/
public static boolean killConnecton(String alias, long id, boolean merciful) throws ProxoolException {
// Let's be explicit about what we're doing here
boolean forceExpiry = !merciful;
return ConnectionPoolManager.getInstance().getConnectionPool(alias).expireConnection(id, forceExpiry);
}
/**
* Kill a single connection
* @param connection the connection to kill
* @param merciful if true will only kill connections that aren't active
* @return true if the connection was killed, or false if it couldn't be found.
* @throws ProxoolException if we didn't recognise the connection
*/
public static boolean killConnecton(Connection connection, boolean merciful) throws ProxoolException {
WrappedConnection wrappedConnection = ProxyFactory.getWrappedConnection(connection);
if (wrappedConnection != null) {
long id = wrappedConnection.getId();
String alias = wrappedConnection.getAlias();
return killConnecton(alias, id, merciful);
} else {
throw new ProxoolException("Attempt to kill unrecognised exception " + connection);
}
}
/**
* Add a listener that gets called everytime a global Proxool event ocours.
* @param proxoolListener the listener to add.
*/
public static void addProxoolListener(ProxoolListenerIF proxoolListener) {
compositeProxoolListener.addListener(proxoolListener);
}
/**
* Remove a registered <code>ProxoolListenerIF</code>.
* @param proxoolListener the listener to remove.
* @return whether the listener was found or removed or not.
*/
public static boolean removeProxoolListener(ProxoolListenerIF proxoolListener) {
return compositeProxoolListener.removeListener(proxoolListener);
}
/**
* @deprecated use {@link #addStateListener(String, StateListenerIF)} instead.
*/
public static void setStateListener(String alias, StateListenerIF stateListener) throws ProxoolException {
addStateListener(alias, stateListener);
}
/**
* Add a listener that monitors the change of state of the pool (quiet, busy, overloaded, or down)
* @param alias identifies the pool
* @param stateListener the new listener
* @throws ProxoolException if we couldn't find the pool
*/
public static void addStateListener(String alias, StateListenerIF stateListener) throws ProxoolException {
ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
cp.addStateListener(stateListener);
}
/**
* Remove a listener that monitors the change of state of the pool (quiet, busy, overloaded, or down)
* @param alias identifies the pool
* @param stateListener the listener to be removed.
* @throws ProxoolException if we couldn't find the pool
* @return wether the listnener was found and removed or not.
*/
public static boolean removeStateListener(String alias, StateListenerIF stateListener) throws ProxoolException {
ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
return cp.removeStateListener(stateListener);
}
/**
* @deprecated use {@link #addConnectionListener(String, ConnectionListenerIF)} instead.
*/
public static void setConnectionListener(String alias, ConnectionListenerIF connectionListener) throws ProxoolException {
addConnectionListener(alias, connectionListener);
}
/**
* Add a listener that monitors each time a connection is made or destroyed.
* @param alias identifies the pool
* @param connectionListener the new listener
* @throws ProxoolException if we couldn't find the pool
*/
public static void addConnectionListener(String alias, ConnectionListenerIF connectionListener) throws ProxoolException {
ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
cp.addConnectionListener(connectionListener);
}
/**
* Remove a listener that monitors each time a connection is made or destroyed.
* @param alias identifies the pool
* @param connectionListener the listener to be removed
* @throws ProxoolException if we couldn't find the pool
* @return wether the listnener was found and removed or not.
*/
public static boolean removeConnectionListener(String alias, ConnectionListenerIF connectionListener) throws ProxoolException {
ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
return cp.removeConnectionListener(connectionListener);
}
/**
* @deprecated use {@link #addConfigurationListener(String, ConfigurationListenerIF)} instead.
*/
public static void setConfigurationListener(String alias, ConfigurationListenerIF configurationListener) throws ProxoolException {
addConfigurationListener(alias, configurationListener);
}
/**
* Adds a listener that gets called everytime the configuration changes.
* @param alias identifies the pool
* @param configurationListener the new listener
* @throws ProxoolException if we couldn't find the pool
*/
public static void addConfigurationListener(String alias, ConfigurationListenerIF configurationListener) throws ProxoolException {
if (ConnectionPoolManager.getInstance().isPoolExists(alias)) {
CompositeConfigurationListener compositeConfigurationListener = (CompositeConfigurationListener)
configurators.get(alias);
if (compositeConfigurationListener == null) {
compositeConfigurationListener = new CompositeConfigurationListener();
configurators.put(alias, compositeConfigurationListener);
}
compositeConfigurationListener.addListener(configurationListener);
} else {
throw new ProxoolException(ConnectionPoolManager.getInstance().getKnownPools(alias));
}
}
/**
* Broadcast a configuration change
* @param alias identifies the pool
* @param connectionPoolDefinition the definition
* @param completeInfo all properties
* @param changedInfo only changed properties (since the last
* time this method was called)
*/
protected static void definitionUpdated(String alias, ConnectionPoolDefinitionIF connectionPoolDefinition,
Properties completeInfo, Properties changedInfo) {
CompositeConfigurationListener ccl = (CompositeConfigurationListener) configurators.get(alias);
if (ccl != null) {
ccl.definitionUpdated(connectionPoolDefinition, completeInfo, changedInfo);
}
}
/**
* Remove a listener that gets called everytime the configuration changes.
* @param alias identifies the pool.
* @param configurationListener the listener to be removed.
* @throws ProxoolException if we couldn't find the pool
* @return wether the listnener was found and removed or not.
*
*/
public static boolean removeConfigurationListener(String alias, ConfigurationListenerIF configurationListener) throws ProxoolException {
boolean removed = false;
if (ConnectionPoolManager.getInstance().isPoolExists(alias)) {
CompositeConfigurationListener compositeConfigurationListener = (CompositeConfigurationListener)
configurators.get(alias);
if (compositeConfigurationListener != null) {
removed = compositeConfigurationListener.removeListener(configurationListener);
}
} else {
throw new ProxoolException(ConnectionPoolManager.getInstance().getKnownPools(alias));
}
return removed;
}
/**
* @see #killAllConnections(java.lang.String)
*/
private static final boolean MERCIFUL = true;
/**
* Redefine the behaviour of the pool. All existing properties (for Proxool
* and the delegate driver are reset to their default) and reapplied
* based on the parameters sent here.
*
* @param url the url that defines the pool (or the abbreviated ""proxool.alias")
* @param info the new properties
* @see #updateConnectionPool
*/
public static void redefineConnectionPool(String url, Properties info) throws ProxoolException {
String alias = getAlias(url);
ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
try {
// Clone the old one
ConnectionPoolDefinition cpd = (ConnectionPoolDefinition) cp.getDefinition().clone();
cpd.redefine(url, info);
cp.setDefinition(cpd);
} catch (CloneNotSupportedException e) {
throw new ProxoolException("Funny, why couldn't we clone a definition?", e);
}
}
/**
* Update the behaviour of the pool. Only properties that are defined here are overwritten. That is, properties
* that were defined before but are not mentioned here are retained.
*
* @param url the url that defines the pool (or the abbreviated ""proxool.alias")
* @param info the new properties
* @see #redefineConnectionPool
*/
public static void updateConnectionPool(String url, Properties info) throws ProxoolException {
String alias = getAlias(url);
ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
try {
// Clone the old one
ConnectionPoolDefinition cpd = (ConnectionPoolDefinition) cp.getDefinition().clone();
cpd.update(url, info);
cp.setDefinition(cpd);
} catch (CloneNotSupportedException e) {
throw new ProxoolException("Funny, why couldn't we clone a definition?", e);
}
}
protected void finalize() throws Throwable {
super.finalize();
LOG.debug("Finalising");
}
/**
* Returns the driver provided statement that Proxool wraps up before it gives it to you.
* @return delegate statement
* @deprecated Just cast the statement that you are given into the driver specific one.
*/
public static Statement getDelegateStatement(Statement statement) throws ProxoolException {
try {
return ProxyFactory.getDelegateStatement(statement);
} catch (IllegalArgumentException e) {
throw new ProxoolException("Statement argument is not one provided by Proxool (it's a " + statement.getClass() + ")");
}
}
/**
* Returns the driver provided connection that Proxool wraps up before it gives it to you.
* @return delegate connection
* @deprecated Just cast the connection that you are given into the driver specific one.
*/
public static Connection getDelegateConnection(Connection connection) throws ProxoolException {
try {
return ProxyFactory.getDelegateConnection(connection);
} catch (IllegalArgumentException e) {
throw new ProxoolException("Connection argument is not one provided by Proxool (it's a " + connection.getClass() + ")");
}
}
/**
* Get the connection ID for a connection
* @param connection the connection that was served
* @return the ID
* @throws ProxoolException if the connection wasn't recognised.
*/
public static long getId(Connection connection) throws ProxoolException {
try {
return ProxyFactory.getWrappedConnection(connection).getId();
} catch (NullPointerException e) {
throw new ProxoolException("Connection argument is not one provided by Proxool (it's a " + connection.getClass() + ")");
} catch (IllegalArgumentException e) {
throw new ProxoolException("Connection argument is not one provided by Proxool (it's a " + connection.getClass() + ")");
}
}
/**
* Get the alias for the connection pool that served a connection
* @param connection the connection that was served
* @return the alias
* @throws ProxoolException if the connection wasn't recognised.
*/
public static String getAlias(Connection connection) throws ProxoolException {
try {
return ProxyFactory.getWrappedConnection(connection).getAlias();
} catch (NullPointerException e) {
throw new ProxoolException("Connection argument is not one provided by Proxool (it's a " + connection.getClass() + ")");
} catch (IllegalArgumentException e) {
throw new ProxoolException("Connection argument is not one provided by Proxool (it's a " + connection.getClass() + ")");
}
}
/**
* Get a list of all the registered pools
* @return an array of aliases
* @since Proxool 0.7
*/
public static String[] getAliases() {
return ConnectionPoolManager.getInstance().getConnectionPoolNames();
}
/**
* Get a particular set of performance statistics for this pool
* @param alias identifies the pool
* @param token identifies which set, as defined in the configuration (see {@link ConnectionPoolDefinitionIF#getStatistics definition})
* @return a sample containing the statistics
* @throws ProxoolException if we couldn't find the pool
*/
public static StatisticsIF getStatistics(String alias, String token) throws ProxoolException {
return ConnectionPoolManager.getInstance().getConnectionPool(alias).getAdmin().getStatistics(token);
}
/**
* Get all the lastest performance statistics for this pool
* @param alias identifies the pool
* @return a sample containing the statistics, or a zero length array if there none
* @throws ProxoolException if we couldn't find the pool
*/
public static StatisticsIF[] getStatistics(String alias) throws ProxoolException {
final Admin monitor = ConnectionPoolManager.getInstance().getConnectionPool(alias).getAdmin();
if (monitor != null) {
return monitor.getStatistics();
} else {
return new StatisticsIF[0];
}
}
/**
* Add a listener that receives statistics as they are produced
* @param statisticsListener the new listener
* @throws ProxoolException if the pool couldn't be found
*/
public static void addStatisticsListener(String alias, StatisticsListenerIF statisticsListener) throws ProxoolException {
// TODO investigate what happens if we add a statistics monitor after we register a listener
final Admin monitor = ConnectionPoolManager.getInstance().getConnectionPool(alias).getAdmin();
if (monitor != null) {
monitor.addStatisticsListener(statisticsListener);
} else {
throw new ProxoolException("Statistics are switched off, your can't add a listener");
}
}
/**
* Gives a snapshot of what the pool is doing
* @param alias identifies the pool
* @param detail if true then include detail of each connection. Note it you ask for
* detail then the pool must necessarily be locked for the duration it takes to gather
* the information (which isn't very long). You probably shouldn't do it that often (like
* not every second or something). Being locked means that connections cannot be
* served or returned (it doesn't mean that they can't be active).
* @return the current status of the pool
* @throws ProxoolException if we couldn't find the pool
*/
public static SnapshotIF getSnapshot(String alias, boolean detail) throws ProxoolException {
SnapshotIF snapshot = null;
ConnectionPool cp = ConnectionPoolManager.getInstance().getConnectionPool(alias);
if (detail) {
try {
// Only try for 10 seconds!
long start = System.currentTimeMillis();
if (cp.attemptConnectionStatusReadLock(10000)) {
snapshot = Admin.getSnapshot(cp, cp.getDefinition(), cp.getConnectionInfos());
} else {
LOG.warn("Give up waiting for detailed snapshot after " + (System.currentTimeMillis() - start) + " milliseconds. Serving standard snapshot instead.");
}
} finally {
cp.releaseConnectionStatusReadLock();
}
}
if (snapshot == null) {
snapshot = Admin.getSnapshot(cp, cp.getDefinition(), null);
}
return snapshot;
}
/**
* Calls {@link #getSnapshot(java.lang.String, boolean) getSnapshot}
* using false for the detail parameter.
* @see #getSnapshot(java.lang.String, boolean)
*/
public static SnapshotIF getSnapshot(String alias) throws ProxoolException {
return getSnapshot(alias, false);
}
// all jmx operations are done through reflection
// to avoid making the facade dependant on the JMX classes
private static boolean registerForJmx(String alias, Properties properties) {
boolean success = false;
try {
Class jmxHelperClass = Class.forName("org.logicalcobwebs.proxool.admin.jmx.ProxoolJMXHelper");
Method registerMethod = jmxHelperClass.getDeclaredMethod("registerPool", new Class[]{String.class, Properties.class});
registerMethod.invoke(null, new Object[]{alias, properties});
success = true;
} catch (Exception e) {
LOG.error("JMX registration of " + alias + " pool failed.", e);
}
return success;
}
// all JNDI operations are done through reflection
// to avoid making the facade dependant on the JNDI classes
private static boolean registerDataSource(String alias, Properties jndiProperties) {
boolean success = false;
try {
Class jndiHelperClass = Class.forName("org.logicalcobwebs.proxool.admin.jndi.ProxoolJNDIHelper");
Method registerMethod = jndiHelperClass.getDeclaredMethod("registerDatasource", new Class[]{String.class,
Properties.class});
registerMethod.invoke(null, new Object[]{alias, jndiProperties});
success = true;
} catch (Exception e) {
LOG.error("JNDI DataSource binding of " + alias + " pool failed.", e);
}
return success;
}
/**
* Get the JNDI properties for the given pool definition if it is configured for JNDI registration.
* Will remove generic JNDI properties from the delegate properties so that they will not be passed to the
* delegate driver.
* @param connectionPoolDefinition the pool definition to get the eventual JNDI configuration from.
* @return the JNDI properties, or <code>null</code> if the given definition was not configured for JNDI.
*/
private static Properties extractJndiProperties(ConnectionPoolDefinition connectionPoolDefinition) {
if (connectionPoolDefinition.getJndiName() == null) {
return null;
}
Properties jndiProperties = new Properties();
jndiProperties.setProperty(ProxoolConstants.JNDI_NAME, connectionPoolDefinition.getJndiName());
if (connectionPoolDefinition.getDelegateProperties() != null) {
Properties delegateProperties = connectionPoolDefinition.getDelegateProperties();
// we must retrieve all the relevant property names before removing them from
// the given properties to avoid ConcurrentModificationException
String propertyName = null;
List propertyNamesList = new ArrayList(10);
Iterator keySetIterator = delegateProperties.keySet().iterator();
while (keySetIterator.hasNext()) {
propertyName = (String) keySetIterator.next();
if (propertyName.startsWith(ProxoolConstants.JNDI_PROPERTY_PREFIX)) {
propertyNamesList.add(propertyName);
}
}
for (int i = 0; i < propertyNamesList.size(); i++) {
propertyName = (String) propertyNamesList.get(i);
if (propertyName.startsWith(ProxoolConstants.JNDI_PROPERTY_PREFIX)) {
jndiProperties.setProperty(propertyName.substring(ProxoolConstants.JNDI_PROPERTY_PREFIX.length()),
(String) delegateProperties.getProperty(propertyName));
delegateProperties.remove(propertyName);
}
}
}
return jndiProperties;
}
/**
* Get wether the given pool properties contains configuration for JMX instrumentation of the pool.
* @param poolProperties the properties to check for JMX configuration.
* @return wether the given pool properties contains configuration for JMX instrumentation or not.
*/
private static boolean isConfiguredForJMX(Properties poolProperties) {
final String jmxProperty = poolProperties.getProperty(ProxoolConstants.JMX_PROPERTY);
if (jmxProperty != null && jmxProperty.equalsIgnoreCase("true")) {
return true;
} else {
return false;
}
}
/**
* By remembering the most recent {@link ShutdownHook} ProxoolFacade
* will know to disable it when it is {@link #shutdown}. It will gracefully
* cope with the fact that it may be shutting down by the request of the
* sutdownHook. If you don't do this and do several "hot deploys" then you
* end up with a series of shutdown hooks. We only every want one.
* @param t the thread that will be run as a shutdown hook
* @see ShutdownHook
*/
protected static void setShutdownHook(Thread t) {
shutdownHook = t;
}
}
/*
Revision history:
$Log: ProxoolFacade.java,v $
Revision 1.87 2007/05/15 23:00:22 billhorsman
Made removeStateListener() static like the other removeFooListener() methods. Credit to gazzamop@hotmail.com (bug 1716868).
Revision 1.86 2007/01/25 23:38:24 billhorsman
Scrapped onAboutToDie and altered onDeath signature instead. Now includes reasonCode (see ConnectionListenerIF)
Revision 1.85 2006/11/02 10:00:34 billhorsman
Added ProxoolFacade.disableShutdownHook.
Revision 1.84 2006/01/18 14:40:01 billhorsman
Unbundled Jakarta's Commons Logging.
Revision 1.83 2005/09/26 09:54:14 billhorsman
Avoid suspected deadlock when getting a detailed snapshot. Only attempt to get the concurrent lock for 10 seconds before giving up.
Revision 1.82 2005/05/04 16:32:31 billhorsman
Clone the definition when redefining or updating the pool.
Revision 1.81 2004/09/29 15:43:25 billhorsman
Recheck isPoolExists inside synchronized registerConnectionPool method. Credit Juergen Hoeller.
Revision 1.80 2004/06/02 20:47:05 billhorsman
Override shutdown with a zero-parameter version for Spring integration.
Revision 1.79 2004/03/26 15:58:56 billhorsman
Fixes to ensure that house keeper and prototyper threads finish after shutdown.
Revision 1.78 2004/03/23 21:25:54 billhorsman
Added getAlias() call.
Revision 1.77 2004/03/23 21:19:45 billhorsman
Added disposable wrapper to proxied connection. And made proxied objects implement delegate interfaces too.
Revision 1.76 2004/03/15 02:45:19 chr32
Added handling of Proxool managed JNDI DataSources.
Revision 1.75 2004/02/12 12:54:49 billhorsman
Fix merciful/forceExpiry confusion
Revision 1.74 2003/10/30 00:16:13 billhorsman
Throw a friendlier exception if you try and add a statistics listener to a pool with no statistics
Revision 1.73 2003/10/16 18:52:35 billhorsman
Fixed a bug: the redefine() method was actually calling the update() method. Also, added checks to make the
"Attempt to use a pool with incomplete definition" exception a bit more descriptive. It's often because you
are referring to an unregistered pool simply by using an alias.
Revision 1.72 2003/09/07 22:09:21 billhorsman
Remove any registered ShutdownHooks during shutdown.
Revision 1.71 2003/08/30 14:54:04 billhorsman
Checkstyle
Revision 1.70 2003/08/28 10:55:49 billhorsman
comment out JNDI stuff for now
Revision 1.69 2003/08/27 18:03:20 billhorsman
added new getDelegateConnection() method
Revision 1.68 2003/07/23 12:38:50 billhorsman
some fixes, but more to come
Revision 1.67 2003/07/23 06:54:48 billhorsman
draft JNDI changes (shouldn't effect normal operation)
Revision 1.66 2003/04/10 21:49:34 billhorsman
refactored registration slightly to allow DataSource access
Revision 1.65 2003/03/11 14:51:53 billhorsman
more concurrency fixes relating to snapshots
Revision 1.64 2003/03/10 15:26:49 billhorsman
refactoringn of concurrency stuff (and some import
optimisation)
Revision 1.63 2003/03/03 11:11:58 billhorsman
fixed licence
Revision 1.62 2003/02/28 10:42:59 billhorsman
ConnectionPoolManager now passes ProxoolFacade an
array of ConnectionPools rather than a Collection
to avoid a ConcurrentModificationException during
shutdown.
Revision 1.61 2003/02/27 17:19:18 billhorsman
new overloaded getSnapshot method
Revision 1.60 2003/02/26 16:05:53 billhorsman
widespread changes caused by refactoring the way we
update and redefine pool definitions.
Revision 1.59 2003/02/24 18:03:24 chr32
Added JMX operations.
Revision 1.58 2003/02/24 01:15:33 chr32
Added support for ProxoolListenerIF.
Revision 1.57 2003/02/19 23:46:10 billhorsman
renamed monitor package to admin
Revision 1.56 2003/02/19 13:48:28 chr32
Added 'removeConfigurationListener' method.
Revision 1.55 2003/02/18 16:50:00 chr32
Added possibility to remove connection and state listeners.
Revision 1.54 2003/02/14 14:19:42 billhorsman
automatically load ProxoolDriver
Revision 1.53 2003/02/14 13:26:23 billhorsman
better exception for incorrect url
Revision 1.52 2003/02/12 12:28:27 billhorsman
added url, proxyHashcode and delegateHashcode to
ConnectionInfoIF
Revision 1.51 2003/02/07 17:26:05 billhorsman
deprecated removeAllConnectionPools in favour of
shutdown (and dropped unreliable finalize() method)
Revision 1.50 2003/02/07 15:12:41 billhorsman
fix statisticsLogLevel property recognition again
Revision 1.49 2003/02/07 14:45:40 billhorsman
fix statisticsLogLevel property recognition
Revision 1.48 2003/02/07 14:16:46 billhorsman
support for StatisticsListenerIF
Revision 1.47 2003/02/07 10:27:47 billhorsman
change in shutdown procedure to allow re-registration
Revision 1.46 2003/02/07 01:48:15 chr32
Started using new composite listeners.
Revision 1.45 2003/02/06 17:41:04 billhorsman
now uses imported logging
Revision 1.44 2003/02/06 15:46:43 billhorsman
checkstyle
Revision 1.43 2003/02/06 15:41:16 billhorsman
add statistics-log-level
Revision 1.42 2003/02/05 17:05:02 billhorsman
registerConnectionPool is now synchronized
Revision 1.41 2003/02/05 00:20:01 billhorsman
copes with pools with no statistics
Revision 1.40 2003/02/04 17:18:29 billhorsman
move ShutdownHook init code
Revision 1.39 2003/02/04 15:04:17 billhorsman
New ShutdownHook
Revision 1.38 2003/01/31 16:53:17 billhorsman
checkstyle
Revision 1.37 2003/01/31 11:50:39 billhorsman
changes for snapshot improvements
Revision 1.36 2003/01/31 00:18:27 billhorsman
statistics is now a string to allow multiple,
comma-delimited values (plus allow access to all
statistics)
Revision 1.35 2003/01/30 17:50:28 billhorsman
spelling
Revision 1.34 2003/01/30 17:48:50 billhorsman
configuration listener now linked to alias not url
Revision 1.33 2003/01/30 17:22:23 billhorsman
add statistics support
Revision 1.32 2003/01/27 18:26:36 billhorsman
refactoring of ProxyConnection and ProxyStatement to
make it easier to write JDK 1.2 patch
Revision 1.31 2003/01/23 11:08:26 billhorsman
new setConfiguratorListener method (and remove from optional
parameter when registering pool)
Revision 1.30 2003/01/19 15:21:07 billhorsman
doc
Revision 1.29 2003/01/18 15:13:12 billhorsman
Signature changes (new ProxoolException
thrown) on the ProxoolFacade API.
Revision 1.28 2003/01/17 00:38:12 billhorsman
wide ranging changes to clarify use of alias and url -
this has led to some signature changes (new exceptions
thrown) on the ProxoolFacade API.
Revision 1.27 2003/01/15 14:51:40 billhorsman
checkstyle
Revision 1.26 2003/01/15 12:20:06 billhorsman
deprecated getConnectionPoolStatisticsDump
Revision 1.25 2003/01/14 23:50:58 billhorsman
logs version
Revision 1.24 2002/12/16 17:15:03 billhorsman
fix for url
Revision 1.23 2002/12/16 16:47:22 billhorsman
fix for updating properties with zero length strings
Revision 1.22 2002/12/16 16:42:30 billhorsman
allow URL updates to pool
Revision 1.21 2002/12/16 11:46:00 billhorsman
send properties to definitionUpdated
Revision 1.20 2002/12/16 11:16:51 billhorsman
checkstyle
Revision 1.19 2002/12/16 11:15:19 billhorsman
fixed getDelegateStatement
Revision 1.18 2002/12/16 10:57:48 billhorsman
add getDelegateStatement to allow access to the
delegate JDBC driver's Statement
Revision 1.17 2002/12/12 10:49:43 billhorsman
now includes properties in definitionChanged event
Revision 1.16 2002/12/04 13:19:43 billhorsman
draft ConfigurationListenerIF stuff for persistent configuration
Revision 1.15 2002/11/13 19:12:24 billhorsman
fix where update properties weren't being recognised
when the properties object was the same as the original
Revision 1.14 2002/11/13 11:28:38 billhorsman
trace property wasn't being configured
Revision 1.13 2002/11/09 15:56:31 billhorsman
log if serConnectionListener couldn't find pool
Revision 1.12 2002/11/03 10:46:57 billhorsman
hide passwords in log
Revision 1.11 2002/11/02 13:57:33 billhorsman
checkstyle
Revision 1.10 2002/10/29 08:54:45 billhorsman
fix to getAlias so that it correctly extracts alias from "proxool.alias" form
Revision 1.9 2002/10/28 19:43:30 billhorsman
configuring of pool now gets logged to that pool's logger (rather than general log)
Revision 1.8 2002/10/27 13:29:38 billhorsman
deprecated debug-level in favour of verbose
Revision 1.7 2002/10/27 13:01:23 billhorsman
layout
Revision 1.6 2002/10/25 15:59:32 billhorsman
made non-public where possible
Revision 1.5 2002/10/25 10:12:52 billhorsman
Improvements and fixes to the way connection pools close down. Including new ReloadMonitor to detect when a class is reloaded. Much better logging too.
Revision 1.4 2002/10/24 17:40:31 billhorsman
Fixed recognition of existing pool (which was resulting in an extra configuration step - but which didn't cause any problems)
Revision 1.3 2002/10/23 21:04:36 billhorsman
checkstyle fixes (reduced max line width and lenient naming convention
Revision 1.2 2002/10/17 15:27:31 billhorsman
better reporting of property settings
Revision 1.1.1.1 2002/09/13 08:13:19 billhorsman
new
Revision 1.11 2002/08/24 20:07:28 billhorsman
removed debug to stdout
Revision 1.10 2002/08/24 19:44:13 billhorsman
fixes for logging
Revision 1.9 2002/07/10 16:14:47 billhorsman
widespread layout changes and move constants into ProxoolConstants
Revision 1.8 2002/07/05 13:24:32 billhorsman
doc
Revision 1.7 2002/07/04 09:04:20 billhorsman
Now throws an SQLException if you ask for a ConnectionPoolDefinition, ConnectionPoolStatistics that doesn't exist. This makes it easier to show the list of possible ones you can choose.
Revision 1.6 2002/07/02 11:19:08 billhorsman
layout code and imports
Revision 1.5 2002/07/02 11:14:26 billhorsman
added test (andbug fixes) for FileLogger
Revision 1.4 2002/07/02 09:13:08 billhorsman
removed redundant import
Revision 1.3 2002/07/02 08:52:42 billhorsman
Added lots more methods and moved configuration stuff here
Revision 1.2 2002/06/28 11:19:47 billhorsman
improved doc
*/