/* * 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 com.frameworkset.commons.dbcp; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import com.frameworkset.commons.pool.KeyedObjectPool; import com.frameworkset.commons.pool.KeyedObjectPoolFactory; import com.frameworkset.commons.pool.ObjectPool; import com.frameworkset.commons.pool.PoolableObjectFactory; /** * A {@link PoolableObjectFactory} that creates * {@link PoolableConnection}s. * * @author Rodney Waldhoff * @author Glenn L. Nielsen * @author James House * @author Dirk Verbeeck * @version $Revision: 479187 $ $Date: 2006-11-25 13:13:45 -0700 (Sat, 25 Nov 2006) $ */ public class PoolableConnectionFactory implements PoolableObjectFactory { /** * Create a new <tt>PoolableConnectionFactory</tt>. * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s */ public PoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit) { _connFactory = connFactory; _pool = pool; _pool.setFactory(this); _stmtPoolFactory = stmtPoolFactory; _validationQuery = validationQuery; _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; _defaultAutoCommit = defaultAutoCommit; } /** * Create a new <tt>PoolableConnectionFactory</tt>. * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s */ public PoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation) { _connFactory = connFactory; _pool = pool; _pool.setFactory(this); _stmtPoolFactory = stmtPoolFactory; _validationQuery = validationQuery; _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; _defaultAutoCommit = defaultAutoCommit; _defaultTransactionIsolation = defaultTransactionIsolation; } /** * Create a new <tt>PoolableConnectionFactory</tt>. * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s * @param config the AbandonedConfig if tracing SQL objects * @deprecated AbandonedConfig is now deprecated. */ public PoolableConnectionFactory( ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit, AbandonedConfig config) { _connFactory = connFactory; _pool = pool; _config = config; _pool.setFactory(this); _stmtPoolFactory = stmtPoolFactory; _validationQuery = validationQuery; _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; _defaultAutoCommit = defaultAutoCommit; } /** * Create a new <tt>PoolableConnectionFactory</tt>. * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s * @param config the AbandonedConfig if tracing SQL objects * @deprecated AbandonedConfig is now deprecated. */ public PoolableConnectionFactory( ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation, AbandonedConfig config) { _connFactory = connFactory; _pool = pool; _config = config; _pool.setFactory(this); _stmtPoolFactory = stmtPoolFactory; _validationQuery = validationQuery; _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; _defaultAutoCommit = defaultAutoCommit; _defaultTransactionIsolation = defaultTransactionIsolation; } /** * Create a new <tt>PoolableConnectionFactory</tt>. * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s * @param defaultCatalog the default "catalog" setting for returned {@link Connection}s * @param config the AbandonedConfig if tracing SQL objects * @deprecated AbandonedConfig is now deprecated. */ public PoolableConnectionFactory( ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation, String defaultCatalog, AbandonedConfig config) { _connFactory = connFactory; _pool = pool; _config = config; _pool.setFactory(this); _stmtPoolFactory = stmtPoolFactory; _validationQuery = validationQuery; _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; _defaultAutoCommit = defaultAutoCommit; _defaultTransactionIsolation = defaultTransactionIsolation; _defaultCatalog = defaultCatalog; } /** * Create a new <tt>PoolableConnectionFactory</tt>. * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation. * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s * @param defaultCatalog the default "catalog" setting for returned {@link Connection}s * @param config the AbandonedConfig if tracing SQL objects */ public PoolableConnectionFactory( ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, Boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation, String defaultCatalog, AbandonedConfig config) { _connFactory = connFactory; _pool = pool; _config = config; _pool.setFactory(this); _stmtPoolFactory = stmtPoolFactory; _validationQuery = validationQuery; _defaultReadOnly = defaultReadOnly; _defaultAutoCommit = defaultAutoCommit; _defaultTransactionIsolation = defaultTransactionIsolation; _defaultCatalog = defaultCatalog; } /** * Sets the {@link ConnectionFactory} from which to obtain base {@link Connection}s. * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s */ synchronized public void setConnectionFactory(ConnectionFactory connFactory) { _connFactory = connFactory; } /** * Sets the query I use to {@link #validateObject validate} {@link Connection}s. * Should return at least one row. * Using <tt>null</tt> turns off validation. * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. */ synchronized public void setValidationQuery(String validationQuery) { _validationQuery = validationQuery; } /** * Sets the {@link ObjectPool} in which to pool {@link Connection}s. * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s */ synchronized public void setPool(ObjectPool pool) { if(null != _pool && pool != _pool) { try { _pool.close(); } catch(Exception e) { // ignored !?! } } _pool = pool; } public ObjectPool getPool() { return _pool; } /** * Sets the {@link KeyedObjectPoolFactory} I use to create {@link KeyedObjectPool}s * for pooling {@link java.sql.PreparedStatement}s. * Set to <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling. * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s */ synchronized public void setStatementPoolFactory(KeyedObjectPoolFactory stmtPoolFactory) { _stmtPoolFactory = stmtPoolFactory; } /** * Sets the default "read only" setting for borrowed {@link Connection}s * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s */ public void setDefaultReadOnly(boolean defaultReadOnly) { _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE; } /** * Sets the default "auto commit" setting for borrowed {@link Connection}s * @param defaultAutoCommit the default "auto commit" setting for borrowed {@link Connection}s */ public void setDefaultAutoCommit(boolean defaultAutoCommit) { _defaultAutoCommit = defaultAutoCommit; } /** * Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s */ public void setDefaultTransactionIsolation(int defaultTransactionIsolation) { _defaultTransactionIsolation = defaultTransactionIsolation; } /** * Sets the default "catalog" setting for borrowed {@link Connection}s * @param defaultCatalog the default "catalog" setting for borrowed {@link Connection}s */ public void setDefaultCatalog(String defaultCatalog) { _defaultCatalog = defaultCatalog; } synchronized public Object makeObject() throws Exception { Connection conn = _connFactory.createConnection(); if(null != _stmtPoolFactory) { KeyedObjectPool stmtpool = _stmtPoolFactory.createPool(); conn = new PoolingConnection(conn,stmtpool); stmtpool.setFactory((PoolingConnection)conn); } return new PoolableConnection(conn,_pool,_config); } public void destroyObject(Object obj) throws Exception { if(obj instanceof PoolableConnection) { ((PoolableConnection)obj).reallyClose(); } } public boolean validateObject(Object obj) { if(obj instanceof Connection) { try { validateConnection((Connection) obj); return true; } catch(Exception e) { return false; } } else { return false; } } public void validateConnection(Connection conn) throws SQLException { String query = _validationQuery; if(conn.isClosed()) { throw new SQLException("validateConnection: connection closed"); } if(null != query) { Statement stmt = null; ResultSet rset = null; try { stmt = conn.createStatement(); rset = stmt.executeQuery(query); if(!rset.next()) { throw new SQLException("validationQuery didn't return a row"); } } finally { if (rset != null) { try { rset.close(); } catch(Exception t) { // ignored } } if (stmt != null) { try { stmt.close(); } catch(Exception t) { // ignored } } } } } public void passivateObject(Object obj) throws Exception { if(obj instanceof Connection) { Connection conn = (Connection)obj; if(!conn.getAutoCommit() && !conn.isReadOnly()) { conn.rollback(); } conn.clearWarnings(); if(!conn.getAutoCommit()) { conn.setAutoCommit(true); } } if(obj instanceof DelegatingConnection) { ((DelegatingConnection)obj).passivate(); } } public void activateObject(Object obj) throws Exception { if(obj instanceof DelegatingConnection) { ((DelegatingConnection)obj).activate(); } if(obj instanceof Connection) { Connection conn = (Connection)obj; if (conn.getAutoCommit() != _defaultAutoCommit) { conn.setAutoCommit(_defaultAutoCommit); } if ((_defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) && (conn.getTransactionIsolation() != _defaultTransactionIsolation)) { conn.setTransactionIsolation(_defaultTransactionIsolation); } if ((_defaultReadOnly != null) && (conn.isReadOnly() != _defaultReadOnly.booleanValue())) { conn.setReadOnly(_defaultReadOnly.booleanValue()); } if ((_defaultCatalog != null) && (!_defaultCatalog.equals(conn.getCatalog()))) { conn.setCatalog(_defaultCatalog); } } } protected ConnectionFactory _connFactory = null; protected String _validationQuery = null; protected ObjectPool _pool = null; protected KeyedObjectPoolFactory _stmtPoolFactory = null; protected Boolean _defaultReadOnly = null; protected boolean _defaultAutoCommit = true; protected int _defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION; protected String _defaultCatalog; /** * @deprecated AbandonedConfig is now deprecated. */ protected AbandonedConfig _config = null; /** * Internal constant to indicate the level is not set. */ static final int UNKNOWN_TRANSACTIONISOLATION = -1; }