| /* |
| * 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.dbcp.datasources; |
| |
| import java.io.Serializable; |
| import java.io.PrintWriter; |
| import java.sql.Connection; |
| import java.sql.SQLException; |
| import java.util.NoSuchElementException; |
| import java.util.Properties; |
| |
| import javax.naming.Context; |
| import javax.naming.InitialContext; |
| import javax.naming.NamingException; |
| import javax.naming.Reference; |
| import javax.naming.StringRefAddr; |
| import javax.naming.Referenceable; |
| import javax.sql.ConnectionPoolDataSource; |
| import javax.sql.DataSource; |
| import javax.sql.PooledConnection; |
| |
| import org.apache.commons.dbcp.SQLNestedException; |
| import org.apache.commons.pool.impl.GenericObjectPool; |
| |
| /** |
| * <p>The base class for <code>SharedPoolDataSource</code> and |
| * <code>PerUserPoolDataSource</code>. Many of the configuration properties |
| * are shared and defined here. This class is declared public in order |
| * to allow particular usage with commons-beanutils; do not make direct |
| * use of it outside of commons-dbcp. |
| * </p> |
| * |
| * <p> |
| * A J2EE container will normally provide some method of initializing the |
| * <code>DataSource</code> whose attributes are presented |
| * as bean getters/setters and then deploying it via JNDI. It is then |
| * available to an application as a source of pooled logical connections to |
| * the database. The pool needs a source of physical connections. This |
| * source is in the form of a <code>ConnectionPoolDataSource</code> that |
| * can be specified via the {@link #setDataSourceName(String)} used to |
| * lookup the source via JNDI. |
| * </p> |
| * |
| * <p> |
| * Although normally used within a JNDI environment, A DataSource |
| * can be instantiated and initialized as any bean. In this case the |
| * <code>ConnectionPoolDataSource</code> will likely be instantiated in |
| * a similar manner. This class allows the physical source of connections |
| * to be attached directly to this pool using the |
| * {@link #setConnectionPoolDataSource(ConnectionPoolDataSource)} method. |
| * </p> |
| * |
| * <p> |
| * The dbcp package contains an adapter, |
| * {@link org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS}, |
| * that can be used to allow the use of <code>DataSource</code>'s based on this |
| * class with jdbc driver implementations that do not supply a |
| * <code>ConnectionPoolDataSource</code>, but still |
| * provide a {@link java.sql.Driver} implementation. |
| * </p> |
| * |
| * <p> |
| * The <a href="package-summary.html">package documentation</a> contains an |
| * example using catalina and JNDI and it also contains a non-JNDI example. |
| * </p> |
| * |
| * @author John D. McNally |
| * @version $Revision$ $Date$ |
| */ |
| public abstract class InstanceKeyDataSource |
| implements DataSource, Referenceable, Serializable { |
| private static final long serialVersionUID = -4243533936955098795L; |
| private static final String GET_CONNECTION_CALLED |
| = "A Connection was already requested from this source, " |
| + "further initialization is not allowed."; |
| private static final String BAD_TRANSACTION_ISOLATION |
| = "The requested TransactionIsolation level is invalid."; |
| /** |
| * Internal constant to indicate the level is not set. |
| */ |
| protected static final int UNKNOWN_TRANSACTIONISOLATION = -1; |
| |
| private boolean getConnectionCalled = false; |
| |
| private ConnectionPoolDataSource cpds = null; |
| /** DataSource Name used to find the ConnectionPoolDataSource */ |
| private String dataSourceName = null; |
| private boolean defaultAutoCommit = false; |
| private int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION; |
| // private int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE; |
| // private int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE; |
| // private int maxWait = (int)Math.min(Integer.MAX_VALUE, |
| // GenericObjectPool.DEFAULT_MAX_WAIT); |
| private boolean defaultReadOnly = false; |
| /** Description */ |
| private String description = null; |
| /** Environment that may be used to set up a jndi initial context. */ |
| Properties jndiEnvironment = null; |
| /** Login TimeOut in seconds */ |
| private int loginTimeout = 0; |
| /** Log stream */ |
| private PrintWriter logWriter = null; |
| private boolean _testOnBorrow = GenericObjectPool.DEFAULT_TEST_ON_BORROW; |
| private boolean _testOnReturn = GenericObjectPool.DEFAULT_TEST_ON_RETURN; |
| private int _timeBetweenEvictionRunsMillis = (int) |
| Math.min(Integer.MAX_VALUE, |
| GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS); |
| private int _numTestsPerEvictionRun = |
| GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN; |
| private int _minEvictableIdleTimeMillis = (int) |
| Math.min(Integer.MAX_VALUE, |
| GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS); |
| private boolean _testWhileIdle = GenericObjectPool.DEFAULT_TEST_WHILE_IDLE; |
| private String validationQuery = null; |
| private boolean rollbackAfterValidation = false; |
| private boolean testPositionSet = false; |
| |
| protected String instanceKey = null; |
| |
| /** |
| * Default no-arg constructor for Serialization |
| */ |
| public InstanceKeyDataSource() { |
| defaultAutoCommit = true; |
| } |
| |
| /** |
| * Throws an IllegalStateException, if a PooledConnection has already |
| * been requested. |
| */ |
| protected void assertInitializationAllowed() |
| throws IllegalStateException { |
| if (getConnectionCalled) { |
| throw new IllegalStateException(GET_CONNECTION_CALLED); |
| } |
| } |
| |
| /** |
| * Close pool being maintained by this datasource. |
| */ |
| public abstract void close() throws Exception; |
| |
| /* |
| public boolean isWrapperFor(Class<?> iface) throws SQLException { |
| return false; |
| } |
| |
| public <T> T unwrap(Class<T> iface) throws SQLException { |
| throw new SQLException("InstanceKeyDataSource is not a wrapper."); |
| } |
| */ |
| |
| // ------------------------------------------------------------------- |
| // Properties |
| |
| /** |
| * Get the value of connectionPoolDataSource. This method will return |
| * null, if the backing datasource is being accessed via jndi. |
| * |
| * @return value of connectionPoolDataSource. |
| */ |
| public ConnectionPoolDataSource getConnectionPoolDataSource() { |
| return cpds; |
| } |
| |
| /** |
| * Set the backend ConnectionPoolDataSource. This property should not be |
| * set if using jndi to access the datasource. |
| * |
| * @param v Value to assign to connectionPoolDataSource. |
| */ |
| public void setConnectionPoolDataSource(ConnectionPoolDataSource v) { |
| assertInitializationAllowed(); |
| if (dataSourceName != null) { |
| throw new IllegalStateException( |
| "Cannot set the DataSource, if JNDI is used."); |
| } |
| if (cpds != null) |
| { |
| throw new IllegalStateException( |
| "The CPDS has already been set. It cannot be altered."); |
| } |
| cpds = v; |
| instanceKey = InstanceKeyObjectFactory.registerNewInstance(this); |
| } |
| |
| /** |
| * Get the name of the ConnectionPoolDataSource which backs this pool. |
| * This name is used to look up the datasource from a jndi service |
| * provider. |
| * |
| * @return value of dataSourceName. |
| */ |
| public String getDataSourceName() { |
| return dataSourceName; |
| } |
| |
| /** |
| * Set the name of the ConnectionPoolDataSource which backs this pool. |
| * This name is used to look up the datasource from a jndi service |
| * provider. |
| * |
| * @param v Value to assign to dataSourceName. |
| */ |
| public void setDataSourceName(String v) { |
| assertInitializationAllowed(); |
| if (cpds != null) { |
| throw new IllegalStateException( |
| "Cannot set the JNDI name for the DataSource, if already " + |
| "set using setConnectionPoolDataSource."); |
| } |
| if (dataSourceName != null) |
| { |
| throw new IllegalStateException( |
| "The DataSourceName has already been set. " + |
| "It cannot be altered."); |
| } |
| this.dataSourceName = v; |
| instanceKey = InstanceKeyObjectFactory.registerNewInstance(this); |
| } |
| |
| /** |
| * Get the value of defaultAutoCommit, which defines the state of |
| * connections handed out from this pool. The value can be changed |
| * on the Connection using Connection.setAutoCommit(boolean). |
| * The default is true. |
| * |
| * @return value of defaultAutoCommit. |
| */ |
| public boolean isDefaultAutoCommit() { |
| return defaultAutoCommit; |
| } |
| |
| /** |
| * Set the value of defaultAutoCommit, which defines the state of |
| * connections handed out from this pool. The value can be changed |
| * on the Connection using Connection.setAutoCommit(boolean). |
| * The default is true. |
| * |
| * @param v Value to assign to defaultAutoCommit. |
| */ |
| public void setDefaultAutoCommit(boolean v) { |
| assertInitializationAllowed(); |
| this.defaultAutoCommit = v; |
| } |
| |
| /** |
| * Get the value of defaultReadOnly, which defines the state of |
| * connections handed out from this pool. The value can be changed |
| * on the Connection using Connection.setReadOnly(boolean). |
| * The default is false. |
| * |
| * @return value of defaultReadOnly. |
| */ |
| public boolean isDefaultReadOnly() { |
| return defaultReadOnly; |
| } |
| |
| /** |
| * Set the value of defaultReadOnly, which defines the state of |
| * connections handed out from this pool. The value can be changed |
| * on the Connection using Connection.setReadOnly(boolean). |
| * The default is false. |
| * |
| * @param v Value to assign to defaultReadOnly. |
| */ |
| public void setDefaultReadOnly(boolean v) { |
| assertInitializationAllowed(); |
| this.defaultReadOnly = v; |
| } |
| |
| /** |
| * Get the value of defaultTransactionIsolation, which defines the state of |
| * connections handed out from this pool. The value can be changed |
| * on the Connection using Connection.setTransactionIsolation(int). |
| * If this method returns -1, the default is JDBC driver dependent. |
| * |
| * @return value of defaultTransactionIsolation. |
| */ |
| public int getDefaultTransactionIsolation() { |
| return defaultTransactionIsolation; |
| } |
| |
| /** |
| * Set the value of defaultTransactionIsolation, which defines the state of |
| * connections handed out from this pool. The value can be changed |
| * on the Connection using Connection.setTransactionIsolation(int). |
| * The default is JDBC driver dependent. |
| * |
| * @param v Value to assign to defaultTransactionIsolation |
| */ |
| public void setDefaultTransactionIsolation(int v) { |
| assertInitializationAllowed(); |
| switch (v) { |
| case Connection.TRANSACTION_NONE: |
| case Connection.TRANSACTION_READ_COMMITTED: |
| case Connection.TRANSACTION_READ_UNCOMMITTED: |
| case Connection.TRANSACTION_REPEATABLE_READ: |
| case Connection.TRANSACTION_SERIALIZABLE: |
| break; |
| default: |
| throw new IllegalArgumentException(BAD_TRANSACTION_ISOLATION); |
| } |
| this.defaultTransactionIsolation = v; |
| } |
| |
| /** |
| * Get the description. This property is defined by jdbc as for use with |
| * GUI (or other) tools that might deploy the datasource. It serves no |
| * internal purpose. |
| * |
| * @return value of description. |
| */ |
| public String getDescription() { |
| return description; |
| } |
| |
| /** |
| * Set the description. This property is defined by jdbc as for use with |
| * GUI (or other) tools that might deploy the datasource. It serves no |
| * internal purpose. |
| * |
| * @param v Value to assign to description. |
| */ |
| public void setDescription(String v) { |
| this.description = v; |
| } |
| |
| /** |
| * Get the value of jndiEnvironment which is used when instantiating |
| * a jndi InitialContext. This InitialContext is used to locate the |
| * backend ConnectionPoolDataSource. |
| * |
| * @return value of jndiEnvironment. |
| */ |
| public String getJndiEnvironment(String key) { |
| String value = null; |
| if (jndiEnvironment != null) { |
| value = jndiEnvironment.getProperty(key); |
| } |
| return value; |
| } |
| |
| /** |
| * Sets the value of the given JNDI environment property to be used when |
| * instantiating a JNDI InitialContext. This InitialContext is used to |
| * locate the backend ConnectionPoolDataSource. |
| * |
| * @param key the JNDI environment property to set. |
| * @param value the value assigned to specified JNDI environment property. |
| */ |
| public void setJndiEnvironment(String key, String value) { |
| if (jndiEnvironment == null) { |
| jndiEnvironment = new Properties(); |
| } |
| jndiEnvironment.setProperty(key, value); |
| } |
| |
| /** |
| * Get the value of loginTimeout. |
| * @return value of loginTimeout. |
| */ |
| public int getLoginTimeout() { |
| return loginTimeout; |
| } |
| |
| /** |
| * Set the value of loginTimeout. |
| * @param v Value to assign to loginTimeout. |
| */ |
| public void setLoginTimeout(int v) { |
| this.loginTimeout = v; |
| } |
| |
| /** |
| * Get the value of logWriter. |
| * @return value of logWriter. |
| */ |
| public PrintWriter getLogWriter() { |
| if (logWriter == null) { |
| logWriter = new PrintWriter(System.out); |
| } |
| return logWriter; |
| } |
| |
| /** |
| * Set the value of logWriter. |
| * @param v Value to assign to logWriter. |
| */ |
| public void setLogWriter(PrintWriter v) { |
| this.logWriter = v; |
| } |
| |
| /** |
| * @see #getTestOnBorrow |
| */ |
| public final boolean isTestOnBorrow() { |
| return getTestOnBorrow(); |
| } |
| |
| /** |
| * When <tt>true</tt>, objects will be |
| * {*link PoolableObjectFactory#validateObject validated} |
| * before being returned by the {*link #borrowObject} |
| * method. If the object fails to validate, |
| * it will be dropped from the pool, and we will attempt |
| * to borrow another. |
| * |
| * @see #setTestOnBorrow |
| */ |
| public boolean getTestOnBorrow() { |
| return _testOnBorrow; |
| } |
| |
| /** |
| * When <tt>true</tt>, objects will be |
| * {*link PoolableObjectFactory#validateObject validated} |
| * before being returned by the {*link #borrowObject} |
| * method. If the object fails to validate, |
| * it will be dropped from the pool, and we will attempt |
| * to borrow another. For a <code>true</code> value to have any effect, |
| * the <code>validationQuery</code> property must be set to a non-null |
| * string. |
| * |
| * @see #getTestOnBorrow |
| */ |
| public void setTestOnBorrow(boolean testOnBorrow) { |
| assertInitializationAllowed(); |
| _testOnBorrow = testOnBorrow; |
| testPositionSet = true; |
| } |
| |
| /** |
| * @see #getTestOnReturn |
| */ |
| public final boolean isTestOnReturn() { |
| return getTestOnReturn(); |
| } |
| |
| /** |
| * When <tt>true</tt>, objects will be |
| * {*link PoolableObjectFactory#validateObject validated} |
| * before being returned to the pool within the |
| * {*link #returnObject}. |
| * |
| * @see #setTestOnReturn |
| */ |
| public boolean getTestOnReturn() { |
| return _testOnReturn; |
| } |
| |
| /** |
| * When <tt>true</tt>, objects will be |
| * {*link PoolableObjectFactory#validateObject validated} |
| * before being returned to the pool within the |
| * {*link #returnObject}. For a <code>true</code> value to have any effect, |
| * the <code>validationQuery</code> property must be set to a non-null |
| * string. |
| * |
| * @see #getTestOnReturn |
| */ |
| public void setTestOnReturn(boolean testOnReturn) { |
| assertInitializationAllowed(); |
| _testOnReturn = testOnReturn; |
| testPositionSet = true; |
| } |
| |
| /** |
| * Returns the number of milliseconds to sleep between runs of the |
| * idle object evictor thread. |
| * When non-positive, no idle object evictor thread will be |
| * run. |
| * |
| * @see #setTimeBetweenEvictionRunsMillis |
| */ |
| public int getTimeBetweenEvictionRunsMillis() { |
| return _timeBetweenEvictionRunsMillis; |
| } |
| |
| /** |
| * Sets the number of milliseconds to sleep between runs of the |
| * idle object evictor thread. |
| * When non-positive, no idle object evictor thread will be |
| * run. |
| * |
| * @see #getTimeBetweenEvictionRunsMillis |
| */ |
| public void |
| setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) { |
| assertInitializationAllowed(); |
| _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; |
| } |
| |
| /** |
| * Returns the number of objects to examine during each run of the |
| * idle object evictor thread (if any). |
| * |
| * @see #setNumTestsPerEvictionRun |
| * @see #setTimeBetweenEvictionRunsMillis |
| */ |
| public int getNumTestsPerEvictionRun() { |
| return _numTestsPerEvictionRun; |
| } |
| |
| /** |
| * Sets the number of objects to examine during each run of the |
| * idle object evictor thread (if any). |
| * <p> |
| * When a negative value is supplied, <tt>ceil({*link #numIdle})/abs({*link #getNumTestsPerEvictionRun})</tt> |
| * tests will be run. I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the |
| * idle objects will be tested per run. |
| * |
| * @see #getNumTestsPerEvictionRun |
| * @see #setTimeBetweenEvictionRunsMillis |
| */ |
| public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { |
| assertInitializationAllowed(); |
| _numTestsPerEvictionRun = numTestsPerEvictionRun; |
| } |
| |
| /** |
| * Returns the minimum amount of time an object may sit idle in the pool |
| * before it is eligable for eviction by the idle object evictor |
| * (if any). |
| * |
| * @see #setMinEvictableIdleTimeMillis |
| * @see #setTimeBetweenEvictionRunsMillis |
| */ |
| public int getMinEvictableIdleTimeMillis() { |
| return _minEvictableIdleTimeMillis; |
| } |
| |
| /** |
| * Sets the minimum amount of time an object may sit idle in the pool |
| * before it is eligable for eviction by the idle object evictor |
| * (if any). |
| * When non-positive, no objects will be evicted from the pool |
| * due to idle time alone. |
| * |
| * @see #getMinEvictableIdleTimeMillis |
| * @see #setTimeBetweenEvictionRunsMillis |
| */ |
| public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { |
| assertInitializationAllowed(); |
| _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; |
| } |
| |
| /** |
| * @see #getTestWhileIdle |
| */ |
| public final boolean isTestWhileIdle() { |
| return getTestWhileIdle(); |
| } |
| |
| /** |
| * When <tt>true</tt>, objects will be |
| * {*link PoolableObjectFactory#validateObject validated} |
| * by the idle object evictor (if any). If an object |
| * fails to validate, it will be dropped from the pool. |
| * |
| * @see #setTestWhileIdle |
| * @see #setTimeBetweenEvictionRunsMillis |
| */ |
| public boolean getTestWhileIdle() { |
| return _testWhileIdle; |
| } |
| |
| /** |
| * When <tt>true</tt>, objects will be |
| * {*link PoolableObjectFactory#validateObject validated} |
| * by the idle object evictor (if any). If an object |
| * fails to validate, it will be dropped from the pool. For a |
| * <code>true</code> value to have any effect, |
| * the <code>validationQuery</code> property must be set to a non-null |
| * string. |
| * |
| * @see #getTestWhileIdle |
| * @see #setTimeBetweenEvictionRunsMillis |
| */ |
| public void setTestWhileIdle(boolean testWhileIdle) { |
| assertInitializationAllowed(); |
| _testWhileIdle = testWhileIdle; |
| testPositionSet = true; |
| } |
| |
| /** |
| * The SQL query that will be used to validate connections from this pool |
| * before returning them to the caller. If specified, this query |
| * <strong>MUST</strong> be an SQL SELECT statement that returns at least |
| * one row. |
| */ |
| public String getValidationQuery() { |
| return (this.validationQuery); |
| } |
| |
| /** |
| * The SQL query that will be used to validate connections from this pool |
| * before returning them to the caller. If specified, this query |
| * <strong>MUST</strong> be an SQL SELECT statement that returns at least |
| * one row. Default behavior is to test the connection when it is |
| * borrowed. |
| */ |
| public void setValidationQuery(String validationQuery) { |
| assertInitializationAllowed(); |
| this.validationQuery = validationQuery; |
| if (!testPositionSet) { |
| setTestOnBorrow(true); |
| } |
| } |
| |
| /** |
| * Whether a rollback will be issued after executing the SQL query |
| * that will be used to validate connections from this pool |
| * before returning them to the caller. |
| * |
| * @return true if a rollback will be issued after executing the |
| * validation query |
| * @since 1.2.2 |
| */ |
| public boolean isRollbackAfterValidation() { |
| return (this.rollbackAfterValidation); |
| } |
| |
| /** |
| * Whether a rollback will be issued after executing the SQL query |
| * that will be used to validate connections from this pool |
| * before returning them to the caller. Default behavior is NOT |
| * to issue a rollback. The setting will only have an effect |
| * if a validation query is set |
| * |
| * @param rollbackAfterValidation new property value |
| * @since 1.2.2 |
| */ |
| public void setRollbackAfterValidation(boolean rollbackAfterValidation) { |
| assertInitializationAllowed(); |
| this.rollbackAfterValidation = rollbackAfterValidation; |
| } |
| |
| // ---------------------------------------------------------------------- |
| // Instrumentation Methods |
| |
| // ---------------------------------------------------------------------- |
| // DataSource implementation |
| |
| /** |
| * Attempt to establish a database connection. |
| */ |
| public Connection getConnection() throws SQLException { |
| return getConnection(null, null); |
| } |
| |
| /** |
| * Attempt to establish a database connection. |
| */ |
| public Connection getConnection(String username, String password) |
| throws SQLException { |
| if (instanceKey == null) { |
| throw new SQLException("Must set the ConnectionPoolDataSource " |
| + "through setDataSourceName or setConnectionPoolDataSource" |
| + " before calling getConnection."); |
| } |
| getConnectionCalled = true; |
| PooledConnectionAndInfo info = null; |
| try { |
| info = getPooledConnectionAndInfo(username, password); |
| } catch (NoSuchElementException e) { |
| closeDueToException(info); |
| throw new SQLNestedException("Cannot borrow connection from pool", e); |
| } catch (RuntimeException e) { |
| closeDueToException(info); |
| throw e; |
| } catch (SQLException e) { |
| closeDueToException(info); |
| throw e; |
| } catch (Exception e) { |
| closeDueToException(info); |
| throw new SQLNestedException("Cannot borrow connection from pool", e); |
| } |
| |
| if (!(null == password ? null == info.getPassword() |
| : password.equals(info.getPassword()))) { |
| closeDueToException(info); |
| throw new SQLException("Given password did not match password used" |
| + " to create the PooledConnection."); |
| } |
| |
| Connection con = info.getPooledConnection().getConnection(); |
| try { |
| setupDefaults(con, username); |
| con.clearWarnings(); |
| return con; |
| } catch (SQLException ex) { |
| try { |
| con.close(); |
| } catch (Exception exc) { |
| getLogWriter().println( |
| "ignoring exception during close: " + exc); |
| } |
| throw ex; |
| } |
| } |
| |
| protected abstract PooledConnectionAndInfo |
| getPooledConnectionAndInfo(String username, String password) |
| throws SQLException; |
| |
| protected abstract void setupDefaults(Connection con, String username) |
| throws SQLException; |
| |
| |
| private void closeDueToException(PooledConnectionAndInfo info) { |
| if (info != null) { |
| try { |
| info.getPooledConnection().getConnection().close(); |
| } catch (Exception e) { |
| // do not throw this exception because we are in the middle |
| // of handling another exception. But record it because |
| // it potentially leaks connections from the pool. |
| getLogWriter().println("[ERROR] Could not return connection to " |
| + "pool during exception handling. " + e.getMessage()); |
| } |
| } |
| } |
| |
| protected ConnectionPoolDataSource |
| testCPDS(String username, String password) |
| throws javax.naming.NamingException, SQLException { |
| // The source of physical db connections |
| ConnectionPoolDataSource cpds = this.cpds; |
| if (cpds == null) { |
| Context ctx = null; |
| if (jndiEnvironment == null) { |
| ctx = new InitialContext(); |
| } else { |
| ctx = new InitialContext(jndiEnvironment); |
| } |
| Object ds = ctx.lookup(dataSourceName); |
| if (ds instanceof ConnectionPoolDataSource) { |
| cpds = (ConnectionPoolDataSource) ds; |
| } else { |
| throw new SQLException("Illegal configuration: " |
| + "DataSource " + dataSourceName |
| + " (" + ds.getClass().getName() + ")" |
| + " doesn't implement javax.sql.ConnectionPoolDataSource"); |
| } |
| } |
| |
| // try to get a connection with the supplied username/password |
| PooledConnection conn = null; |
| try { |
| if (username != null) { |
| conn = cpds.getPooledConnection(username, password); |
| } |
| else { |
| conn = cpds.getPooledConnection(); |
| } |
| if (conn == null) { |
| throw new SQLException( |
| "Cannot connect using the supplied username/password"); |
| } |
| } |
| finally { |
| if (conn != null) { |
| try { |
| conn.close(); |
| } |
| catch (SQLException e) { |
| // at least we could connect |
| } |
| } |
| } |
| return cpds; |
| } |
| |
| protected byte whenExhaustedAction(int maxActive, int maxWait) { |
| byte whenExhausted = GenericObjectPool.WHEN_EXHAUSTED_BLOCK; |
| if (maxActive <= 0) { |
| whenExhausted = GenericObjectPool.WHEN_EXHAUSTED_GROW; |
| } else if (maxWait == 0) { |
| whenExhausted = GenericObjectPool.WHEN_EXHAUSTED_FAIL; |
| } |
| return whenExhausted; |
| } |
| |
| // ---------------------------------------------------------------------- |
| // Referenceable implementation |
| |
| /** |
| * Retrieves the Reference of this object. |
| * <strong>Note:</strong> <code>InstanceKeyDataSource</code> subclasses |
| * should override this method. The implementaion included below |
| * is not robust and will be removed at the next major version DBCP |
| * release. |
| * |
| * @return The non-null Reference of this object. |
| * @exception NamingException If a naming exception was encountered |
| * while retrieving the reference. |
| */ |
| // TODO: Remove the implementation of this method at next major |
| // version release. |
| |
| public Reference getReference() throws NamingException { |
| final String className = getClass().getName(); |
| final String factoryName = className + "Factory"; // XXX: not robust |
| Reference ref = new Reference(className, factoryName, null); |
| ref.add(new StringRefAddr("instanceKey", instanceKey)); |
| return ref; |
| } |
| } |