/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.dbcp2;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.HashMap;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Logger;

import org.apache.commons.pool2.ObjectPool;

A Driver implementation that obtains Connections from a registered ObjectPool.
Since:2.0
/** * A {@link Driver} implementation that obtains {@link Connection}s from a registered {@link ObjectPool}. * * @since 2.0 */
public class PoolingDriver implements Driver {
Register myself with the DriverManager.
/** Register myself with the {@link DriverManager}. */
static { try { DriverManager.registerDriver(new PoolingDriver()); } catch (final Exception e) { // ignore } }
The map of registered pools.
/** The map of registered pools. */
protected static final HashMap<String, ObjectPool<? extends Connection>> pools = new HashMap<>();
Controls access to the underlying connection
/** Controls access to the underlying connection */
private final boolean accessToUnderlyingConnectionAllowed;
Constructs a new driver with accessToUnderlyingConnectionAllowed enabled.
/** * Constructs a new driver with <code>accessToUnderlyingConnectionAllowed</code> enabled. */
public PoolingDriver() { this(true); }
For unit testing purposes.
Params:
  • accessToUnderlyingConnectionAllowed – Do DelegatingConnections created by this driver permit access to the delegate?
/** * For unit testing purposes. * * @param accessToUnderlyingConnectionAllowed * Do {@link DelegatingConnection}s created by this driver permit access to the delegate? */
protected PoolingDriver(final boolean accessToUnderlyingConnectionAllowed) { this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed; }
Returns the value of the accessToUnderlyingConnectionAllowed property.
Returns:true if access to the underlying is allowed, false otherwise.
/** * Returns the value of the accessToUnderlyingConnectionAllowed property. * * @return true if access to the underlying is allowed, false otherwise. */
protected boolean isAccessToUnderlyingConnectionAllowed() { return accessToUnderlyingConnectionAllowed; }
Gets the connection pool for the given name.
Params:
  • name – The pool name
Throws:
  • SQLException – Thrown when the named pool is not registered.
Returns:The pool
/** * Gets the connection pool for the given name. * * @param name * The pool name * @return The pool * @throws SQLException * Thrown when the named pool is not registered. */
public synchronized ObjectPool<? extends Connection> getConnectionPool(final String name) throws SQLException { final ObjectPool<? extends Connection> pool = pools.get(name); if (null == pool) { throw new SQLException("Pool not registered: " + name); } return pool; }
Registers a named pool.
Params:
  • name – The pool name.
  • pool – The pool.
/** * Registers a named pool. * * @param name * The pool name. * @param pool * The pool. */
public synchronized void registerPool(final String name, final ObjectPool<? extends Connection> pool) { pools.put(name, pool); }
Closes a named pool.
Params:
  • name – The pool name.
Throws:
  • SQLException – Thrown when a problem is caught closing the pool.
/** * Closes a named pool. * * @param name * The pool name. * @throws SQLException * Thrown when a problem is caught closing the pool. */
public synchronized void closePool(final String name) throws SQLException { @SuppressWarnings("resource") final ObjectPool<? extends Connection> pool = pools.get(name); if (pool != null) { pools.remove(name); try { pool.close(); } catch (final Exception e) { throw new SQLException("Error closing pool " + name, e); } } }
Gets the pool names.
Returns:the pool names.
/** * Gets the pool names. * * @return the pool names. */
public synchronized String[] getPoolNames() { final Set<String> names = pools.keySet(); return names.toArray(new String[names.size()]); } @Override public boolean acceptsURL(final String url) throws SQLException { return url == null ? false : url.startsWith(URL_PREFIX); } @Override public Connection connect(final String url, final Properties info) throws SQLException { if (acceptsURL(url)) { final ObjectPool<? extends Connection> pool = getConnectionPool(url.substring(URL_PREFIX_LEN)); try { final Connection conn = pool.borrowObject(); if (conn == null) { return null; } return new PoolGuardConnectionWrapper(pool, conn); } catch (final SQLException e) { throw e; } catch (final NoSuchElementException e) { throw new SQLException("Cannot get a connection, pool error: " + e.getMessage(), e); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { throw new SQLException("Cannot get a connection, general error: " + e.getMessage(), e); } } return null; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { throw new SQLFeatureNotSupportedException(); }
Invalidates the given connection.
Params:
  • conn – connection to invalidate
Throws:
  • SQLException – if the connection is not a PoolGuardConnectionWrapper or an error occurs invalidating the connection
/** * Invalidates the given connection. * * @param conn * connection to invalidate * @throws SQLException * if the connection is not a <code>PoolGuardConnectionWrapper</code> or an error occurs invalidating * the connection */
public void invalidateConnection(final Connection conn) throws SQLException { if (conn instanceof PoolGuardConnectionWrapper) { // normal case final PoolGuardConnectionWrapper pgconn = (PoolGuardConnectionWrapper) conn; @SuppressWarnings("unchecked") final ObjectPool<Connection> pool = (ObjectPool<Connection>) pgconn.pool; try { pool.invalidateObject(pgconn.getDelegateInternal()); } catch (final Exception e) { // Ignore. } } else { throw new SQLException("Invalid connection class"); } } @Override public int getMajorVersion() { return MAJOR_VERSION; } @Override public int getMinorVersion() { return MINOR_VERSION; } @Override public boolean jdbcCompliant() { return true; } @Override public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) { return new DriverPropertyInfo[0]; }
My URL prefix
/** My URL prefix */
public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:"; protected static final int URL_PREFIX_LEN = URL_PREFIX.length(); // version numbers protected static final int MAJOR_VERSION = 1; protected static final int MINOR_VERSION = 0;
PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore.
Since:2.0
/** * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore. * * @since 2.0 */
private class PoolGuardConnectionWrapper extends DelegatingConnection<Connection> { private final ObjectPool<? extends Connection> pool; PoolGuardConnectionWrapper(final ObjectPool<? extends Connection> pool, final Connection delegate) { super(delegate); this.pool = pool; }
See Also:
  • getDelegate.getDelegate()
/** * @see org.apache.commons.dbcp2.DelegatingConnection#getDelegate() */
@Override public Connection getDelegate() { if (isAccessToUnderlyingConnectionAllowed()) { return super.getDelegate(); } return null; }
See Also:
  • getInnermostDelegate.getInnermostDelegate()
/** * @see org.apache.commons.dbcp2.DelegatingConnection#getInnermostDelegate() */
@Override public Connection getInnermostDelegate() { if (isAccessToUnderlyingConnectionAllowed()) { return super.getInnermostDelegate(); } return null; } } }