| package org.apache.commons.dbcp.cpdsadapter; |
| |
| /* ==================================================================== |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2001-2003 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Apache" and "Apache Software Foundation" and |
| * "Apache Turbine" must not be used to endorse or promote products |
| * derived from this software without prior written permission. For |
| * written permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * "Apache Turbine", nor may "Apache" appear in their name, without |
| * prior written permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| |
| import java.util.Hashtable; |
| import java.io.PrintWriter; |
| import java.io.Serializable; |
| import java.sql.DriverManager; |
| import java.sql.SQLException; |
| import javax.sql.PooledConnection; |
| import javax.sql.ConnectionPoolDataSource; |
| import javax.naming.Name; |
| import javax.naming.Context; |
| import javax.naming.Referenceable; |
| import javax.naming.spi.ObjectFactory; |
| import javax.naming.Reference; |
| import javax.naming.RefAddr; |
| import javax.naming.StringRefAddr; |
| import javax.naming.NamingException; |
| |
| import org.apache.commons.pool.KeyedObjectPool; |
| import org.apache.commons.pool.impl.GenericKeyedObjectPool; |
| |
| /** |
| * <p> |
| * An adapter for jdbc drivers that do not include an implementation |
| * of {@link javax.sql.ConnectionPoolDataSource}, but still include a |
| * {@link java.sql.DriverManager} implementation. |
| * <code>ConnectionPoolDataSource</code>s are not used within general |
| * applications. They are used by <code>DataSource</code> implementations |
| * that pool <code>Connection</code>s, such as |
| * {@link org.apache.commons.dbcp.jdbc2pool.Jdbc2PoolDataSource}. A J2EE |
| * container will normally provide some method of initializing the |
| * <code>ConnectionPoolDataSource</code> whose attributes are presented |
| * as bean getters/setters and then deploying it via JNDI. It is then |
| * available as a source of physical connections to the database, when |
| * the pooling <code>DataSource</code> needs to create a new |
| * physical connection. |
| * </p> |
| * |
| * <p> |
| * Although normally used within a JNDI environment, the DriverAdapterCPDS |
| * can be instantiated and initialized as any bean and then attached |
| * directly to a pooling <code>DataSource</code>. |
| * <code>Jdbc2PoolDataSource</code> can use the |
| * <code>ConnectionPoolDataSource</code> with or without the use of JNDI. |
| * </p> |
| * |
| * <p> |
| * The DriverAdapterCPDS also provides <code>PreparedStatement</code> pooling |
| * which is not generally available in jbdc2 |
| * <code>ConnectionPoolDataSource</code> implementation, but is |
| * addressed within the jdbc3 specification. The <code>PreparedStatement</code> |
| * pool in DriverAdapterCPDS has been in the dbcp package for some time, but |
| * it has not undergone extensive testing in the configuration used here. |
| * It should be considered experimental and can be toggled with the |
| * poolPreparedStatements attribute. |
| * </p> |
| * |
| * <p> |
| * The <a href="package-summary.html">package documentation</a> contains an |
| * example using catalina and JNDI. The <a |
| * href="../jdbc2pool/package-summary.html">jdbc2pool package documentation</a> |
| * shows how to use <code>DriverAdapterCPDS</code> as a source for |
| * <code>Jdbc2PoolDataSource</code> without the use of JNDI. |
| * </p> |
| * |
| * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a> |
| * @version $Id: DriverAdapterCPDS.java,v 1.2 2003/06/29 12:42:16 mpoeschl Exp $ |
| */ |
| public class DriverAdapterCPDS |
| implements ConnectionPoolDataSource, Referenceable, Serializable, |
| ObjectFactory { |
| |
| private static final String GET_CONNECTION_CALLED |
| = "A PooledConnection was already requested from this source, " |
| + "further initialization is not allowed."; |
| |
| /** Description */ |
| private String description; |
| /** Password */ |
| private String password; |
| /** Url name */ |
| private String url; |
| /** User name */ |
| private String user; |
| /** Driver class name */ |
| private String driver; |
| |
| /** Login TimeOut in seconds */ |
| private int loginTimeout; |
| /** Log stream */ |
| private PrintWriter logWriter = null; |
| |
| // PreparedStatement pool properties |
| private boolean poolPreparedStatements; |
| private int maxActive = 10; |
| private int maxIdle = 10; |
| private int _timeBetweenEvictionRunsMillis = -1; |
| private int _numTestsPerEvictionRun = -1; |
| private int _minEvictableIdleTimeMillis = -1; |
| |
| private boolean getConnectionCalled = false; |
| |
| /** |
| * Default no-arg constructor for Serialization |
| */ |
| public DriverAdapterCPDS() { |
| } |
| |
| /** |
| * Attempt to establish a database connection using the default |
| * user and password. |
| */ |
| public PooledConnection getPooledConnection() throws SQLException { |
| return getPooledConnection(getUser(), getPassword()); |
| } |
| |
| /** |
| * Attempt to establish a database connection. |
| */ |
| public PooledConnection getPooledConnection(String username, |
| String password) |
| throws SQLException { |
| getConnectionCalled = true; |
| /* |
| public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, |
| int maxActive, byte whenExhaustedAction, long maxWait, |
| int maxIdle, boolean testOnBorrow, boolean testOnReturn, |
| long timeBetweenEvictionRunsMillis, |
| int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, |
| boolean testWhileIdle) { |
| */ |
| KeyedObjectPool stmtPool = null; |
| if (isPoolPreparedStatements()) { |
| stmtPool = new GenericKeyedObjectPool(null, |
| getMaxActive(), GenericKeyedObjectPool.WHEN_EXHAUSTED_GROW, 0, |
| getMaxIdle(), false, false, getTimeBetweenEvictionRunsMillis(), |
| getNumTestsPerEvictionRun(), |
| getMinEvictableIdleTimeMillis(), false); |
| } |
| |
| // Workaround for buggy WebLogic 5.1 classloader - ignore the |
| // exception upon first invocation. |
| try { |
| return new PooledConnectionImpl( |
| DriverManager.getConnection(getUrl(), username, password), |
| stmtPool ); |
| } |
| catch (ClassCircularityError e) |
| { |
| return new PooledConnectionImpl( |
| DriverManager.getConnection(getUrl(), username, password), |
| stmtPool ); |
| } |
| } |
| |
| // ---------------------------------------------------------------------- |
| // Referenceable implementation |
| |
| /** |
| * <CODE>Referenceable</CODE> implementation. |
| */ |
| public Reference getReference() throws NamingException { |
| // this class implements its own factory |
| String factory = getClass().getName(); |
| |
| Reference ref = new Reference(getClass().getName(), factory, null); |
| |
| ref.add(new StringRefAddr("description", getDescription())); |
| ref.add(new StringRefAddr("driver", getDriver())); |
| ref.add(new StringRefAddr("loginTimeout", |
| String.valueOf(getLoginTimeout()))); |
| ref.add(new StringRefAddr("password", getPassword())); |
| ref.add(new StringRefAddr("user", getUser())); |
| ref.add(new StringRefAddr("url", getUrl())); |
| |
| ref.add(new StringRefAddr("poolPreparedStatements", |
| String.valueOf(isPoolPreparedStatements()))); |
| ref.add(new StringRefAddr("maxActive", |
| String.valueOf(getMaxActive()))); |
| ref.add(new StringRefAddr("maxIdle", |
| String.valueOf(getMaxIdle()))); |
| ref.add(new StringRefAddr("timeBetweenEvictionRunsMillis", |
| String.valueOf(getTimeBetweenEvictionRunsMillis()))); |
| ref.add(new StringRefAddr("numTestsPerEvictionRun", |
| String.valueOf(getNumTestsPerEvictionRun()))); |
| ref.add(new StringRefAddr("minEvictableIdleTimeMillis", |
| String.valueOf(getMinEvictableIdleTimeMillis()))); |
| |
| return ref; |
| } |
| |
| |
| // ---------------------------------------------------------------------- |
| // ObjectFactory implementation |
| |
| /** |
| * implements ObjectFactory to create an instance of this class |
| */ |
| public Object getObjectInstance(Object refObj, Name name, |
| Context context, Hashtable env) |
| throws Exception { |
| // The spec says to return null if we can't create an instance |
| // of the reference |
| DriverAdapterCPDS cpds = null; |
| if (refObj instanceof Reference) { |
| Reference ref = (Reference)refObj; |
| if (ref.getClassName().equals(getClass().getName())) { |
| RefAddr ra = ref.get("description"); |
| if (ra != null && ra.getContent() != null) { |
| setDescription(ra.getContent().toString()); |
| } |
| |
| ra = ref.get("driver"); |
| if (ra != null && ra.getContent() != null) { |
| setDriver(ra.getContent().toString()); |
| } |
| ra = ref.get("url"); |
| if (ra != null && ra.getContent() != null) { |
| setUrl(ra.getContent().toString()); |
| } |
| ra = ref.get("user"); |
| if (ra != null && ra.getContent() != null) { |
| setUser(ra.getContent().toString()); |
| } |
| ra = ref.get("password"); |
| if (ra != null && ra.getContent() != null) { |
| setPassword(ra.getContent().toString()); |
| } |
| |
| ra = ref.get("poolPreparedStatements"); |
| if (ra != null && ra.getContent() != null) { |
| setPoolPreparedStatements( |
| Boolean.getBoolean(ra.getContent().toString())); |
| } |
| ra = ref.get("maxActive"); |
| if (ra != null && ra.getContent() != null) { |
| setMaxActive(Integer.parseInt(ra.getContent().toString())); |
| } |
| |
| ra = ref.get("maxIdle"); |
| if (ra != null && ra.getContent() != null) { |
| setMaxIdle(Integer.parseInt(ra.getContent().toString())); |
| } |
| |
| ra = ref.get("timeBetweenEvictionRunsMillis"); |
| if (ra != null && ra.getContent() != null) { |
| setTimeBetweenEvictionRunsMillis( |
| Integer.parseInt(ra.getContent().toString())); |
| } |
| |
| ra = ref.get("numTestsPerEvictionRun"); |
| if (ra != null && ra.getContent() != null) { |
| setNumTestsPerEvictionRun( |
| Integer.parseInt(ra.getContent().toString())); |
| } |
| |
| ra = ref.get("minEvictableIdleTimeMillis"); |
| if (ra != null && ra.getContent() != null) { |
| setMinEvictableIdleTimeMillis( |
| Integer.parseInt(ra.getContent().toString())); |
| } |
| |
| cpds = this; |
| } |
| } |
| return cpds; |
| } |
| |
| /** |
| * Throws an IllegalStateException, if a PooledConnection has already |
| * been requested. |
| */ |
| private void assertInitializationAllowed() throws IllegalStateException { |
| if (getConnectionCalled) { |
| throw new IllegalStateException(GET_CONNECTION_CALLED); |
| } |
| } |
| |
| // ---------------------------------------------------------------------- |
| // Properties |
| |
| /** |
| * Get the value of description. This property is here for use by |
| * the code which will deploy this datasource. It is not used |
| * internally. |
| * |
| * @return value of description. |
| */ |
| public String getDescription() { |
| return description; |
| } |
| |
| /** |
| * Set the value of description. This property is here for use by |
| * the code which will deploy this datasource. It is not used |
| * internally. |
| * |
| * @param v Value to assign to description. |
| */ |
| public void setDescription(String v) { |
| this.description = v; |
| } |
| |
| /** |
| * Get the value of password for the default user. |
| * @return value of password. |
| */ |
| public String getPassword() { |
| return password; |
| } |
| |
| /** |
| * Set the value of password for the default user. |
| * @param v Value to assign to password. |
| */ |
| public void setPassword(String v) { |
| assertInitializationAllowed(); |
| this.password = v; |
| } |
| |
| /** |
| * Get the value of url used to locate the database for this datasource. |
| * @return value of url. |
| */ |
| public String getUrl() { |
| return url; |
| } |
| |
| /** |
| * Set the value of url used to locate the database for this datasource. |
| * @param v Value to assign to url. |
| */ |
| public void setUrl(String v) { |
| assertInitializationAllowed(); |
| this.url = v; |
| } |
| |
| /** |
| * Get the value of default user (login or username). |
| * @return value of user. |
| */ |
| public String getUser() { |
| return user; |
| } |
| |
| /** |
| * Set the value of default user (login or username). |
| * @param v Value to assign to user. |
| */ |
| public void setUser(String v) { |
| assertInitializationAllowed(); |
| this.user = v; |
| } |
| |
| /** |
| * Get the driver classname. |
| * @return value of driver. |
| */ |
| public String getDriver() { |
| return driver; |
| } |
| |
| /** |
| * Set the driver classname. Setting the driver classname cause the |
| * driver to be registered with the DriverManager. |
| * @param v Value to assign to driver. |
| */ |
| public void setDriver(String v) throws ClassNotFoundException { |
| assertInitializationAllowed(); |
| this.driver = v; |
| // make sure driver is registered |
| Class.forName(v); |
| } |
| |
| /** |
| * Gets the maximum time in seconds that this data source can wait |
| * while attempting to connect to a database. NOT USED. |
| */ |
| public int getLoginTimeout() { |
| return loginTimeout; |
| } |
| |
| /** |
| * Get the log writer for this data source. NOT USED. |
| */ |
| public PrintWriter getLogWriter() { |
| return logWriter; |
| } |
| |
| /** |
| * Sets the maximum time in seconds that this data source will wait |
| * while attempting to connect to a database. NOT USED. |
| */ |
| public void setLoginTimeout(int seconds) { |
| loginTimeout = seconds; |
| } |
| |
| /** |
| * Set the log writer for this data source. NOT USED. |
| */ |
| public void setLogWriter(java.io.PrintWriter out) { |
| logWriter = out; |
| } |
| |
| |
| // ------------------------------------------------------------------ |
| // PreparedStatement pool properties |
| |
| |
| /** |
| * Flag to toggle the pooling of <code>PreparedStatement</code>s |
| * @return value of poolPreparedStatements. |
| */ |
| public boolean isPoolPreparedStatements() { |
| return poolPreparedStatements; |
| } |
| |
| /** |
| * Flag to toggle the pooling of <code>PreparedStatement</code>s |
| * @param v true to pool statements. |
| */ |
| public void setPoolPreparedStatements(boolean v) { |
| assertInitializationAllowed(); |
| this.poolPreparedStatements = v; |
| } |
| |
| /** |
| * The maximum number of active statements that can be allocated from |
| * this pool at the same time, or zero for no limit. |
| */ |
| public int getMaxActive() { |
| return (this.maxActive); |
| } |
| |
| /** |
| * The maximum number of active statements that can be allocated from |
| * this pool at the same time, or zero for no limit. |
| */ |
| public void setMaxActive(int maxActive) { |
| assertInitializationAllowed(); |
| this.maxActive = maxActive; |
| } |
| |
| /** |
| * The maximum number of statements that can remain idle in the |
| * pool, without extra ones being released, or zero for no limit. |
| */ |
| public int getMaxIdle() { |
| return (this.maxIdle); |
| } |
| |
| /** |
| * The maximum number of statements that can remain idle in the |
| * pool, without extra ones being released, or zero for no limit. |
| */ |
| public void setMaxIdle(int maxIdle) { |
| assertInitializationAllowed(); |
| this.maxIdle = maxIdle; |
| } |
| |
| /** |
| * 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 statements 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 statements 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 a statement may sit idle in the pool |
| * before it is eligible for eviction by the idle object evictor |
| * (if any). |
| * |
| * *see #setMinEvictableIdleTimeMillis |
| * *see #setTimeBetweenEvictionRunsMillis |
| */ |
| public int getMinEvictableIdleTimeMillis() { |
| return _minEvictableIdleTimeMillis; |
| } |
| |
| /** |
| * Sets the minimum amount of time a statement 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; |
| } |
| } |