PoolingDriver.java
- /*
- * 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.logging.Logger;
- import org.apache.commons.pool2.ObjectPool;
- /**
- * A {@link Driver} implementation that obtains {@link Connection}s from a registered {@link ObjectPool}.
- *
- * @since 2.0
- */
- public class PoolingDriver implements Driver {
- /**
- * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore.
- *
- * @since 2.0
- */
- private final 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 org.apache.commons.dbcp2.DelegatingConnection#getDelegate()
- */
- @Override
- public Connection getDelegate() {
- if (isAccessToUnderlyingConnectionAllowed()) {
- return super.getDelegate();
- }
- return null;
- }
- /**
- * @see org.apache.commons.dbcp2.DelegatingConnection#getInnermostDelegate()
- */
- @Override
- public Connection getInnermostDelegate() {
- if (isAccessToUnderlyingConnectionAllowed()) {
- return super.getInnermostDelegate();
- }
- return null;
- }
- }
- private static final DriverPropertyInfo[] EMPTY_DRIVER_PROPERTY_INFO_ARRAY = {};
- /* Register myself with the {@link DriverManager}. */
- static {
- try {
- DriverManager.registerDriver(new PoolingDriver());
- } catch (final Exception ignored) {
- // Ignored
- }
- }
- /** The map of registered pools. */
- protected static final HashMap<String, ObjectPool<? extends Connection>> pools = new HashMap<>();
- /**
- * The Apache Commons connection string prefix {@value}.
- */
- public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:";
- /**
- * The String length of {@link #URL_PREFIX}.
- */
- protected static final int URL_PREFIX_LEN = URL_PREFIX.length();
- /**
- * Major version number.
- */
- protected static final int MAJOR_VERSION = 1;
- /**
- * Minor version number.
- */
- protected static final int MINOR_VERSION = 0;
- /** Controls access to the underlying connection */
- private final boolean accessToUnderlyingConnectionAllowed;
- /**
- * Constructs a new driver with {@code accessToUnderlyingConnectionAllowed} enabled.
- */
- public PoolingDriver() {
- this(true);
- }
- /**
- * 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;
- }
- @Override
- public boolean acceptsURL(final String url) throws SQLException {
- return url != null && url.startsWith(URL_PREFIX);
- }
- /**
- * 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);
- }
- }
- }
- @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 NoSuchElementException e) {
- throw new SQLException("Cannot get a connection, pool error: " + e.getMessage(), e);
- } catch (final SQLException | RuntimeException e) {
- throw e;
- } catch (final Exception e) {
- throw new SQLException("Cannot get a connection, general error: " + e.getMessage(), e);
- }
- }
- return null;
- }
- /**
- * 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;
- }
- @Override
- public int getMajorVersion() {
- return MAJOR_VERSION;
- }
- @Override
- public int getMinorVersion() {
- return MINOR_VERSION;
- }
- @Override
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- throw new SQLFeatureNotSupportedException();
- }
- /**
- * Gets the pool names.
- *
- * @return the pool names.
- */
- public synchronized String[] getPoolNames() {
- return pools.keySet().toArray(Utils.EMPTY_STRING_ARRAY);
- }
- @Override
- public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) {
- return EMPTY_DRIVER_PROPERTY_INFO_ARRAY;
- }
- /**
- * Invalidates the given connection.
- *
- * @param conn
- * connection to invalidate
- * @throws SQLException
- * if the connection is not a {@code PoolGuardConnectionWrapper} or an error occurs invalidating
- * the connection
- */
- public void invalidateConnection(final Connection conn) throws SQLException {
- if (!(conn instanceof PoolGuardConnectionWrapper)) {
- throw new SQLException("Invalid connection class");
- }
- final PoolGuardConnectionWrapper pgconn = (PoolGuardConnectionWrapper) conn;
- @SuppressWarnings("unchecked")
- final ObjectPool<Connection> pool = (ObjectPool<Connection>) pgconn.pool;
- try {
- pool.invalidateObject(pgconn.getDelegateInternal());
- } catch (final Exception ignored) {
- // Ignored.
- }
- }
- /**
- * Returns the value of the accessToUnderlyingConnectionAllowed property.
- *
- * @return true if access to the underlying is allowed, false otherwise.
- */
- protected boolean isAccessToUnderlyingConnectionAllowed() {
- return accessToUnderlyingConnectionAllowed;
- }
- @Override
- public boolean jdbcCompliant() {
- return true;
- }
- /**
- * 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);
- }
- }