From: fhanik Date: Sat, 25 Oct 2008 00:06:20 +0000 (+0000) Subject: move over to an independent module X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=1f5c7240671ba042ec5c00242575cdefcae76d49;p=tomcat7.0 move over to an independent module git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@707794 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/extras.xml b/extras.xml index be34de17a..12a0ae1fa 100644 --- a/extras.xml +++ b/extras.xml @@ -82,8 +82,6 @@ - - @@ -333,31 +331,6 @@ To run the sample application, copy the following applications into your CATALIN - - - - - - - - - - - - - - - - - - - - - diff --git a/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java b/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java deleted file mode 100644 index 1b594f32c..000000000 --- a/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java +++ /dev/null @@ -1,715 +0,0 @@ -/* - * 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.tomcat.jdbc.pool; - -import java.lang.management.ManagementFactory; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.TimeUnit; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - -import org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean; - -import java.util.concurrent.atomic.AtomicInteger; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.MBeanRegistrationException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; - -/** - * @author Filip Hanik - * @version 1.0 - */ - -public class ConnectionPool { - - //logger - protected static Log log = LogFactory.getLog(ConnectionPool.class); - - //=============================================================================== - // INSTANCE/QUICK ACCESS VARIABLE - //=============================================================================== - - /** - * All the information about the connection pool - */ - protected PoolProperties poolProperties; - - /** - * Contains all the connections that are in use - */ - protected BlockingQueue busy; - - /** - * Contains all the idle connections - */ - protected BlockingQueue idle; - - /** - * The thread that is responsible for checking abandoned and idle threads - */ - protected PoolCleaner poolCleaner; - - /** - * Pool closed flag - */ - protected boolean closed = false; - - /** - * Size of the pool - */ - protected AtomicInteger size = new AtomicInteger(0); - - /** - * Since newProxyInstance performs the same operation, over and over - * again, it is much more optimized if we simply store the constructor ourselves. - */ - protected Constructor proxyClassConstructor; - - - //=============================================================================== - // PUBLIC METHODS - //=============================================================================== - - /** - * Instantiate a connection pool. This will create connections if initialSize is larger than 0 - * @param prop PoolProperties - all the properties for this connection pool - * @throws SQLException - */ - public ConnectionPool(PoolProperties prop) throws SQLException { - //setup quick access variables and pools - init(prop); - } - - /** - * Borrows a connection from the pool - * @return Connection - a java.sql.Connection reflection proxy, wrapping the underlying object. - * @throws SQLException - */ - public Connection getConnection() throws SQLException { - //check out a connection - PooledConnection con = (PooledConnection)borrowConnection(); - JdbcInterceptor handler = con.getHandler(); - if (handler==null) { - //build the proxy handler - handler = new ProxyConnection(this,con); - //set up the interceptor chain - String[] proxies = getPoolProperties().getJdbcInterceptorsAsArray(); - for (int i=proxies.length-1; i>=0; i--) { - try { - JdbcInterceptor interceptor = - (JdbcInterceptor) Class.forName(proxies[i], true, - Thread.currentThread().getContextClassLoader()).newInstance(); - interceptor.setNext(handler); - handler = interceptor; - }catch(Exception x) { - SQLException sx = new SQLException("Unable to instantiate interceptor chain."); - sx.initCause(x); - throw sx; - } - } - //cache handler for the next iteration - con.setHandler(handler); - } else { - JdbcInterceptor next = handler; - //we have a cached handler, reset it - while (next!=null) { - next.reset(this, con); - next = next.getNext(); - } - } - - try { - //cache the constructor - if (proxyClassConstructor == null ) { - Class proxyClass = Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class}); - proxyClassConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class }); - } - //create the proxy - //TODO possible optimization, keep track if this connection was returned properly, and don't generate a new facade - Connection connection = (Connection)proxyClassConstructor.newInstance(new Object[] { handler }); - //return the connection - return connection; - }catch (Exception x) { - throw new SQLException(); - } - } - - /** - * Returns the name of this pool - * @return String - */ - public String getName() { - return getPoolProperties().getPoolName(); - } - - /** - * Returns the pool properties associated with this connection pool - * @return PoolProperties - */ - public PoolProperties getPoolProperties() { - return this.poolProperties; - } - - /** - * Returns the total size of this pool, this includes both busy and idle connections - * @return int - */ - public int getSize() { - return idle.size()+busy.size(); - } - - /** - * Returns the number of connections that are in use - * @return int - */ - public int getActive() { - return busy.size(); - } - - public int getIdle() { - return idle.size(); - } - - /** - * Returns true if {@link #close close} has been called, and the connection pool is unusable - * @return boolean - */ - public boolean isClosed() { - return this.closed; - } - - @Override - protected void finalize() throws Throwable { - close(true); - } - - /** - * Closes the pool and all disconnects all idle connections - * Active connections will be closed upon the {@link java.sql.Connection#close close} method is called - * on the underlying connection instead of being returned to the pool - * @param force - true to even close the active connections - */ - protected void close(boolean force) { - //are we already closed - if (this.closed) return; - //prevent other threads from entering - this.closed = true; - //stop background thread - if (poolCleaner!=null) { - poolCleaner.stopRunning(); - } - - /* release all idle connections */ - BlockingQueue pool = (idle.size()>0)?idle:(force?busy:idle); - while (pool.size()>0) { - try { - //retrieve the next connection - PooledConnection con = pool.poll(1000, TimeUnit.MILLISECONDS); - //close it and retrieve the next one, if one is available - while (con != null) { - //close the connection - if (pool==idle) - release(con); - else - abandon(con); - con = pool.poll(1000, TimeUnit.MILLISECONDS); - } //while - } catch (InterruptedException ex) { - Thread.currentThread().interrupted(); - } - if (pool.size()==0 && force && pool!=busy) pool = busy; - } - size.set(0); - if (this.getPoolProperties().isJmxEnabled()) stopJmx(); - } //closePool - - - //=============================================================================== - // PROTECTED METHODS - //=============================================================================== - /** - * Initialize the connection pool - called from the constructor - * @param properties PoolProperties - properties used to initialize the pool with - * @throws SQLException - */ - protected void init (PoolProperties properties) throws SQLException { - poolProperties = properties; - //make space for 10 extra in case we flow over a bit - busy = new ArrayBlockingQueue(properties.getMaxActive(),false); - //make space for 10 extra in case we flow over a bit - idle = new ArrayBlockingQueue(properties.getMaxActive(),false); - - //if the evictor thread is supposed to run, start it now - if (properties.isPoolSweeperEnabled()) { - poolCleaner = new PoolCleaner("[Pool-Cleaner]:" + properties.getName(), this, properties.getTimeBetweenEvictionRunsMillis()); - poolCleaner.start(); - } //end if - - if (properties.getMaxActive()properties.getMaxActive()) { - log.warn("minIdle is larger than maxActive, setting minIdle to: "+properties.getMaxActive()); - properties.setMinIdle(properties.getMaxActive()); - } - if (properties.getMaxIdle()>properties.getMaxActive()) { - log.warn("maxIdle is larger than maxActive, setting maxIdle to: "+properties.getMaxActive()); - properties.setMaxIdle(properties.getMaxActive()); - } - if (properties.getMaxIdle()= maxWait) { - throw new SQLException( - "Pool empty. Unable to fetch a connection in " + (maxWait / 1000) + - " seconds, none available["+busy.size()+" in use]."); - } else { - //no timeout, lets try again - continue; - } - } - } //while - } - - protected PooledConnection createConnection(long now, PooledConnection con) { - //no connections where available we'll create one - boolean error = false; - try { - //connect and validate the connection - con = create(); - con.lock(); - if (!busy.offer(con)) { - log.debug("Connection doesn't fit into busy array, connection will not be traceable."); - } - con.connect(); - if (con.validate(PooledConnection.VALIDATE_INIT)) { - //no need to lock a new one, its not contented - con.setTimestamp(now); - if (getPoolProperties().isLogAbandoned()) { - con.setStackTrace(getThreadDump()); - } - return con; - } //end if - } catch (Exception e) { - error = true; - log.error("Unable to create a new JDBC connection.", e); - } finally { - if (error ) { - release(con); - busy.remove(con); - } - con.unlock(); - }//catch - return null; - } - - protected PooledConnection borrowConnection(long now, PooledConnection con) { - //we have a connection, lets set it up - boolean setToNull = false; - try { - con.lock(); - if (con.isDiscarded()) { - //connection has already been disconnected - setToNull = true; - } else if (con.validate(PooledConnection.VALIDATE_BORROW)) { - //set the timestamp - con.setTimestamp(now); - if (getPoolProperties().isLogAbandoned()) { - //set the stack trace for this pool - con.setStackTrace(getThreadDump()); - } - if (!busy.offer(con)) { - log.debug("Connection doesn't fit into busy array, connection will not be traceable."); - } - return con; - } else { - /*if the object wasn't validated, we may as well remove it*/ - release(con); - setToNull = true; - } //end if - } finally { - con.unlock(); - if (setToNull) { - con = null; - } - } - return con; - } - - /** - * Returns a connection to the pool - * @param con PooledConnection - */ - protected void returnConnection(PooledConnection con) { - if (isClosed()) { - //if the connection pool is closed - //close the connection instead of returning it - release(con); - return; - } //end if - - if (con != null) { - try { - con.lock(); - - if (busy.remove(con)) { - if ((!con.isDiscarded()) && (!isClosed()) && - con.validate(PooledConnection.VALIDATE_RETURN)) { - con.setStackTrace(null); - con.setTimestamp(System.currentTimeMillis()); - if (!idle.offer(con)) { - if (log.isDebugEnabled()) { - log.debug("Connection ["+con+"] will be closed and not returned to the pool, idle.offer failed."); - } - release(con); - } - } else { - if (log.isDebugEnabled()) { - log.debug("Connection ["+con+"] will be closed and not returned to the pool."); - } - release(con); - } //end if - } else { - if (log.isDebugEnabled()) { - log.debug("Connection ["+con+"] will be closed and not returned to the pool, busy.remove failed."); - } - release(con); - } - } finally { - con.unlock(); - } - } //end if - } //checkIn - - public void checkAbandoned() { - try { - long now = System.currentTimeMillis(); - Iterator locked = busy.iterator(); - while (locked.hasNext()) { - PooledConnection con = locked.next(); - boolean setToNull = false; - try { - con.lock(); - //the con has been returned to the pool - //ignore it - if (idle.contains(con)) - continue; - long time = con.getTimestamp(); - if ((now - time) > con.getAbandonTimeout()) { - busy.remove(con); - abandon(con); - release(con); - setToNull = true; - } else { - //do nothing - } //end if - } finally { - con.unlock(); - if (setToNull) - con = null; - } - } //while - } catch (ConcurrentModificationException e) { - log.debug("checkAbandoned failed." ,e); - } catch (Exception e) { - log.warn("checkAbandoned failed, it will be retried.",e); - } - } - - public void checkIdle() { - try { - long now = System.currentTimeMillis(); - Iterator unlocked = idle.iterator(); - while ( (idle.size()>=getPoolProperties().getMinIdle()) && unlocked.hasNext()) { - PooledConnection con = unlocked.next(); - boolean setToNull = false; - try { - con.lock(); - //the con been taken out, we can't clean it up - if (busy.contains(con)) - continue; - long time = con.getTimestamp(); - if (((now - time) > con.getReleaseTime()) && (getSize()>getPoolProperties().getMinIdle())) { - release(con); - idle.remove(con); - setToNull = true; - } else { - //do nothing - } //end if - } finally { - con.unlock(); - if (setToNull) - con = null; - } - } //while - } catch (ConcurrentModificationException e) { - log.debug("checkIdle failed." ,e); - } catch (Exception e) { - log.warn("checkIdle failed, it will be retried.",e); - } - - } - - public void testAllIdle() { - try { - Iterator unlocked = idle.iterator(); - while (unlocked.hasNext()) { - PooledConnection con = unlocked.next(); - try { - con.lock(); - //the con been taken out, we can't clean it up - if (busy.contains(con)) - continue; - if (!con.validate(PooledConnection.VALIDATE_IDLE)) { - idle.remove(con); - con.release(); - } - } finally { - con.unlock(); - } - } //while - } catch (ConcurrentModificationException e) { - log.debug("testAllIdle failed." ,e); - } catch (Exception e) { - log.warn("testAllIdle failed, it will be retried.",e); - } - - } - - - protected static String getThreadDump() { - Exception x = new Exception(); - x.fillInStackTrace(); - return getStackTrace(x); - } - - protected static String getStackTrace(Exception x) { - if (x == null) { - return null; - } else { - java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream(); - java.io.PrintStream writer = new java.io.PrintStream(bout); - x.printStackTrace(writer); - String result = bout.toString(); - return result; - } //end if - } - - - protected PooledConnection create() throws java.lang.Exception { - PooledConnection con = new PooledConnection(getPoolProperties(), this); - return con; - } - - protected void finalize(PooledConnection con) { - size.addAndGet(-1); - } - - public void startJmx() { - try { - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - ObjectName name = new ObjectName("org.apache.tomcat.jdbc.pool.jmx:type=ConnectionPool,name="+getName()); - mbs.registerMBean(new org.apache.tomcat.jdbc.pool.jmx.ConnectionPool(this), name); - } catch (Exception x) { - log.warn("Unable to start JMX integration for connection pool. Instance["+getName()+"] can't be monitored.",x); - } - } - - public void stopJmx() { - try { - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - ObjectName name = new ObjectName("org.apache.tomcat.jdbc.pool.jmx:type=ConnectionPool,name="+getName()); - mbs.unregisterMBean(name); - }catch (Exception x) { - log.warn("Unable to stop JMX integration for connection pool. Instance["+getName()+"].",x); - } - } - - - protected class PoolCleaner extends Thread { - protected ConnectionPool pool; - protected long sleepTime; - protected boolean run = true; - PoolCleaner(String name, ConnectionPool pool, long sleepTime) { - super(name); - this.setDaemon(true); - this.pool = pool; - this.sleepTime = sleepTime; - if (sleepTime <= 0) { - pool.log.warn("Database connection pool evicter thread interval is set to 0, defaulting to 30 seconds"); - this.sleepTime = 1000 * 30; - } else if (sleepTime < 1000) { - pool.log.warn("Database connection pool evicter thread interval is set to lower than 1 second."); - } - } - - public void run() { - while (run) { - try { - sleep(sleepTime); - } catch (InterruptedException e) { - // ignore it - Thread.currentThread().interrupted(); - continue; - } //catch - - if (pool.isClosed()) { - if (pool.getSize() <= 0) { - run = false; - } - } else { - try { - if (pool.getPoolProperties().isRemoveAbandoned()) - pool.checkAbandoned(); - if (pool.getPoolProperties().getMaxIdle()JNDI object factory that creates an instance of - * BasicDataSource that has been configured based on the - * RefAddr values of the specified Reference, - * which must match the names and data types of the - * BasicDataSource bean properties.

- *
- * Properties available for configuration:
- * Commons DBCP properties
- *
    - *
  1. initSQL - A query that gets executed once, right after the connection is established.
  2. - *
  3. testOnConnect - run validationQuery after connection has been established.
  4. - *
  5. validationInterval - avoid excess validation, only run validation at most at this frequency - time in milliseconds.
  6. - *
  7. jdbcInterceptors - a semicolon separated list of classnames extending {@link JdbcInterceptor} class.
  8. - *
  9. jmxEnabled - true of false, whether to register the pool with JMX.
  10. - *
- * @author Craig R. McClanahan - * @author Dirk Verbeeck - * @author Filip Hanik - */ -public class DataSourceFactory implements ObjectFactory { - protected static Log log = LogFactory.getLog(DataSourceFactory.class); - - protected final static String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit"; - protected final static String PROP_DEFAULTREADONLY = "defaultReadOnly"; - protected final static String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation"; - protected final static String PROP_DEFAULTCATALOG = "defaultCatalog"; - - protected final static String PROP_DRIVERCLASSNAME = "driverClassName"; - protected final static String PROP_PASSWORD = "password"; - protected final static String PROP_URL = "url"; - protected final static String PROP_USERNAME = "username"; - - protected final static String PROP_MAXACTIVE = "maxActive"; - protected final static String PROP_MAXIDLE = "maxIdle"; - protected final static String PROP_MINIDLE = "minIdle"; - protected final static String PROP_INITIALSIZE = "initialSize"; - protected final static String PROP_MAXWAIT = "maxWait"; - - protected final static String PROP_TESTONBORROW = "testOnBorrow"; - protected final static String PROP_TESTONRETURN = "testOnReturn"; - protected final static String PROP_TESTWHILEIDLE = "testWhileIdle"; - protected final static String PROP_TESTONCONNECT = "testOnConnect"; - protected final static String PROP_VALIDATIONQUERY = "validationQuery"; - - protected final static String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis"; - protected final static String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun"; - protected final static String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis"; - - protected final static String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed"; - - protected final static String PROP_REMOVEABANDONED = "removeAbandoned"; - protected final static String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout"; - protected final static String PROP_LOGABANDONED = "logAbandoned"; - - protected final static String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements"; - protected final static String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements"; - protected final static String PROP_CONNECTIONPROPERTIES = "connectionProperties"; - - protected final static String PROP_INITSQL = "initSQL"; - protected final static String PROP_INTERCEPTORS = "jdbcInterceptors"; - protected final static String PROP_VALIDATIONINTERVAL = "validationInterval"; - protected final static String PROP_JMX_ENABLED = "jmxEnabled"; - - public static final int UNKNOWN_TRANSACTIONISOLATION = -1; - - - protected final static String[] ALL_PROPERTIES = { - PROP_DEFAULTAUTOCOMMIT, - PROP_DEFAULTREADONLY, - PROP_DEFAULTTRANSACTIONISOLATION, - PROP_DEFAULTCATALOG, - PROP_DRIVERCLASSNAME, - PROP_MAXACTIVE, - PROP_MAXIDLE, - PROP_MINIDLE, - PROP_INITIALSIZE, - PROP_MAXWAIT, - PROP_TESTONBORROW, - PROP_TESTONRETURN, - PROP_TIMEBETWEENEVICTIONRUNSMILLIS, - PROP_NUMTESTSPEREVICTIONRUN, - PROP_MINEVICTABLEIDLETIMEMILLIS, - PROP_TESTWHILEIDLE, - PROP_TESTONCONNECT, - PROP_PASSWORD, - PROP_URL, - PROP_USERNAME, - PROP_VALIDATIONQUERY, - PROP_VALIDATIONINTERVAL, - PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED, - PROP_REMOVEABANDONED, - PROP_REMOVEABANDONEDTIMEOUT, - PROP_LOGABANDONED, - PROP_POOLPREPAREDSTATEMENTS, - PROP_MAXOPENPREPAREDSTATEMENTS, - PROP_CONNECTIONPROPERTIES, - PROP_INITSQL, - PROP_INTERCEPTORS, - PROP_JMX_ENABLED - }; - - // -------------------------------------------------- ObjectFactory Methods - - /** - *

Create and return a new BasicDataSource instance. If no - * instance can be created, return null instead.

- * - * @param obj The possibly null object containing location or - * reference information that can be used in creating an object - * @param name The name of this object relative to nameCtx - * @param nameCtx The context relative to which the name - * parameter is specified, or null if name - * is relative to the default initial context - * @param environment The possibly null environment that is used in - * creating this object - * - * @exception Exception if an exception occurs creating the instance - */ - public Object getObjectInstance(Object obj, Name name, Context nameCtx, - Hashtable environment) throws Exception { - - // We only know how to deal with javax.naming.References - // that specify a class name of "javax.sql.DataSource" - if ((obj == null) || !(obj instanceof Reference)) { - return null; - } - Reference ref = (Reference) obj; - if (!"javax.sql.DataSource".equals(ref.getClassName())) { - return null; - } - - Properties properties = new Properties(); - for (int i = 0; i < ALL_PROPERTIES.length; i++) { - String propertyName = ALL_PROPERTIES[i]; - RefAddr ra = ref.get(propertyName); - if (ra != null) { - String propertyValue = ra.getContent().toString(); - properties.setProperty(propertyName, propertyValue); - } - } - - return createDataSource(properties); - } - - /** - * Creates and configures a {@link BasicDataSource} instance based on the - * given properties. - * - * @param properties the datasource configuration properties - * @throws Exception if an error occurs creating the data source - */ - public static DataSource createDataSource(Properties properties) throws Exception { - org.apache.tomcat.jdbc.pool.DataSourceProxy dataSource = new org.apache.tomcat.jdbc.pool.DataSourceProxy(); - - String value = null; - - value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT); - if (value != null) { - dataSource.getPoolProperties().setDefaultAutoCommit(Boolean.valueOf(value)); - } - - value = properties.getProperty(PROP_DEFAULTREADONLY); - if (value != null) { - dataSource.getPoolProperties().setDefaultReadOnly(Boolean.valueOf(value)); - } - - value = properties.getProperty(PROP_DEFAULTTRANSACTIONISOLATION); - if (value != null) { - int level = UNKNOWN_TRANSACTIONISOLATION; - if ("NONE".equalsIgnoreCase(value)) { - level = Connection.TRANSACTION_NONE; - } else if ("READ_COMMITTED".equalsIgnoreCase(value)) { - level = Connection.TRANSACTION_READ_COMMITTED; - } else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) { - level = Connection.TRANSACTION_READ_UNCOMMITTED; - } else if ("REPEATABLE_READ".equalsIgnoreCase(value)) { - level = Connection.TRANSACTION_REPEATABLE_READ; - } else if ("SERIALIZABLE".equalsIgnoreCase(value)) { - level = Connection.TRANSACTION_SERIALIZABLE; - } else { - try { - level = Integer.parseInt(value); - } catch (NumberFormatException e) { - System.err.println("Could not parse defaultTransactionIsolation: " + value); - System.err.println("WARNING: defaultTransactionIsolation not set"); - System.err.println("using default value of database driver"); - level = UNKNOWN_TRANSACTIONISOLATION; - } - } - dataSource.getPoolProperties().setDefaultTransactionIsolation(level); - } - - value = properties.getProperty(PROP_DEFAULTCATALOG); - if (value != null) { - dataSource.getPoolProperties().setDefaultCatalog(value); - } - - value = properties.getProperty(PROP_DRIVERCLASSNAME); - if (value != null) { - dataSource.getPoolProperties().setDriverClassName(value); - } - - value = properties.getProperty(PROP_MAXACTIVE); - if (value != null) { - dataSource.getPoolProperties().setMaxActive(Integer.parseInt(value)); - } - - value = properties.getProperty(PROP_MAXIDLE); - if (value != null) { - dataSource.getPoolProperties().setMaxIdle(Integer.parseInt(value)); - } - - value = properties.getProperty(PROP_MINIDLE); - if (value != null) { - dataSource.getPoolProperties().setMinIdle(Integer.parseInt(value)); - } - - value = properties.getProperty(PROP_INITIALSIZE); - if (value != null) { - dataSource.getPoolProperties().setInitialSize(Integer.parseInt(value)); - } - - value = properties.getProperty(PROP_MAXWAIT); - if (value != null) { - dataSource.getPoolProperties().setMaxWait(Integer.parseInt(value)); - } - - value = properties.getProperty(PROP_TESTONBORROW); - if (value != null) { - dataSource.getPoolProperties().setTestOnBorrow(Boolean.valueOf(value).booleanValue()); - } - - value = properties.getProperty(PROP_TESTONRETURN); - if (value != null) { - dataSource.getPoolProperties().setTestOnReturn(Boolean.valueOf(value).booleanValue()); - } - - value = properties.getProperty(PROP_TESTONCONNECT); - if (value != null) { - dataSource.getPoolProperties().setTestOnConnect(Boolean.valueOf(value).booleanValue()); - } - - value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS); - if (value != null) { - dataSource.getPoolProperties().setTimeBetweenEvictionRunsMillis(Integer.parseInt(value)); - } - - value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN); - if (value != null) { - dataSource.getPoolProperties().setNumTestsPerEvictionRun(Integer.parseInt(value)); - } - - value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS); - if (value != null) { - dataSource.getPoolProperties().setMinEvictableIdleTimeMillis(Integer.parseInt(value)); - } - - value = properties.getProperty(PROP_TESTWHILEIDLE); - if (value != null) { - dataSource.getPoolProperties().setTestWhileIdle(Boolean.valueOf(value).booleanValue()); - } - - value = properties.getProperty(PROP_PASSWORD); - if (value != null) { - dataSource.getPoolProperties().setPassword(value); - } - - value = properties.getProperty(PROP_URL); - if (value != null) { - dataSource.getPoolProperties().setUrl(value); - } - - value = properties.getProperty(PROP_USERNAME); - if (value != null) { - dataSource.getPoolProperties().setUsername(value); - } - - value = properties.getProperty(PROP_VALIDATIONQUERY); - if (value != null) { - dataSource.getPoolProperties().setValidationQuery(value); - } - - value = properties.getProperty(PROP_VALIDATIONINTERVAL); - if (value != null) { - dataSource.getPoolProperties().setValidationInterval(Long.parseLong(value)); - } - - value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED); - if (value != null) { - dataSource.getPoolProperties(). - setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue()); - } - - value = properties.getProperty(PROP_REMOVEABANDONED); - if (value != null) { - dataSource.getPoolProperties().setRemoveAbandoned(Boolean.valueOf(value).booleanValue()); - } - - value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT); - if (value != null) { - dataSource.getPoolProperties().setRemoveAbandonedTimeout(Integer.parseInt(value)); - } - - value = properties.getProperty(PROP_LOGABANDONED); - if (value != null) { - dataSource.getPoolProperties().setLogAbandoned(Boolean.valueOf(value).booleanValue()); - } - - value = properties.getProperty(PROP_POOLPREPAREDSTATEMENTS); - if (value != null) { - log.warn(PROP_POOLPREPAREDSTATEMENTS + " is not a valid setting, it will have no effect."); - } - - value = properties.getProperty(PROP_MAXOPENPREPAREDSTATEMENTS); - if (value != null) { - log.warn(PROP_MAXOPENPREPAREDSTATEMENTS + " is not a valid setting, it will have no effect."); - } - - value = properties.getProperty(PROP_CONNECTIONPROPERTIES); - if (value != null) { - Properties p = getProperties(value); - dataSource.getPoolProperties().setDbProperties(p); - } else { - dataSource.getPoolProperties().setDbProperties(new Properties()); - } - - dataSource.getPoolProperties().getDbProperties().setProperty("user",dataSource.getPoolProperties().getUsername()); - dataSource.getPoolProperties().getDbProperties().setProperty("password",dataSource.getPoolProperties().getPassword()); - - value = properties.getProperty(PROP_INITSQL); - if (value != null) { - dataSource.getPoolProperties().setInitSQL(value); - } - - value = properties.getProperty(PROP_INTERCEPTORS); - if (value != null) { - dataSource.getPoolProperties().setJdbcInterceptors(value); - } - - value = properties.getProperty(PROP_JMX_ENABLED); - if (value != null) { - dataSource.getPoolProperties().setJmxEnabled(Boolean.parseBoolean(value)); - } - - // Return the configured DataSource instance - DataSource ds = getDataSource(dataSource); - return ds; - } - - public static DataSource getDataSource(org.apache.tomcat.jdbc.pool.DataSourceProxy dataSource) { - DataSourceHandler handler = new DataSourceHandler(dataSource); - DataSource ds = (DataSource)Proxy.newProxyInstance(DataSourceFactory.class.getClassLoader(), new Class[] {javax.sql.DataSource.class}, handler); - return ds; - } - - /** - *

Parse properties from the string. Format of the string must be [propertyName=property;]*

- * @param propText - * @return Properties - * @throws Exception - */ - static protected Properties getProperties(String propText) throws Exception { - Properties p = new Properties(); - if (propText != null) { - p.load(new ByteArrayInputStream(propText.replace(';', '\n'). - getBytes())); - } - return p; - } - - protected static class DataSourceHandler implements InvocationHandler { - protected org.apache.tomcat.jdbc.pool.DataSourceProxy datasource = null; - protected static HashMap methods = new HashMap(); - public DataSourceHandler(org.apache.tomcat.jdbc.pool.DataSourceProxy ds) { - this.datasource = ds; - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Method m = methods.get(method); - if (m==null) { - m = datasource.getClass().getMethod(method.getName(), method.getParameterTypes()); - methods.put(method, m); - } - return m.invoke(datasource, args); - } - - } -} diff --git a/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java b/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java deleted file mode 100644 index 878585c2f..000000000 --- a/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * 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.tomcat.jdbc.pool; - -import java.io.PrintWriter; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Iterator; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; - -/** - * - *

Title: Uber Pool

- * - *

Description: A simple, yet efficient and powerful connection pool

- * - *

Copyright: Copyright (c) 2008 Filip Hanik

- * - *

- * - * @author Filip Hanik - * @version 1.0 - */ - -public class DataSourceProxy { - protected static Log log = LogFactory.getLog(DataSourceProxy.class); - - protected Driver driver; - protected PoolProperties poolProperties = new PoolProperties(); - - public DataSourceProxy() { - } - - - public boolean isWrapperFor(Class iface) throws SQLException { - // we are not a wrapper of anything - return false; - } - - - public T unwrap(Class iface) throws SQLException { - //we can't unwrap anything - return null; - } - - /** - * {@inheritDoc} - */ - public Connection getConnection(String username, String password) throws SQLException { - return getConnection(); - } - - public PoolProperties getPoolProperties() { - return poolProperties; - } - - /** - * Sets up the connection pool, by creating a pooling driver. - * @return Driver - * @throws SQLException - */ - public synchronized Driver createDriver() throws SQLException { - if (driver != null) { - return driver; - } else { - driver = new org.apache.tomcat.jdbc.pool.Driver(getPoolProperties()); - return driver; - } - } - - /** - * {@inheritDoc} - */ - - public Connection getConnection() throws SQLException { - if (driver == null) - driver = createDriver(); - return driver.connect(poolProperties.getPoolName(), null); - } - - /** - * {@inheritDoc} - */ - public PooledConnection getPooledConnection() throws SQLException { - return (PooledConnection) getConnection(); - } - - /** - * {@inheritDoc} - */ - public PooledConnection getPooledConnection(String username, - String password) throws SQLException { - return (PooledConnection) getConnection(); - } - - /** - * {@inheritDoc} - */ - public PrintWriter getLogWriter() throws SQLException { - return null; - } - - /** - * {@inheritDoc} - */ - public void setLogWriter(PrintWriter out) throws SQLException { - } - - /** - * {@inheritDoc} - */ - public int getLoginTimeout() { - if (poolProperties == null) { - return 0; - } else { - return poolProperties.getMaxWait() / 1000; - } - } - - /** - * {@inheritDoc} - */ - public void setLoginTimeout(int i) { - if (poolProperties == null) { - return; - } else { - poolProperties.setMaxWait(1000 * i); - } - - } - - - public void close() { - close(false); - } - public void close(boolean all) { - try { - if (driver != null) { - Driver d = driver; - driver = null; - d.closePool(poolProperties.getPoolName(), all); - } - }catch (Exception x) { - x.printStackTrace(); - } - } - - protected void finalize() throws Throwable { - //terminate the pool? - close(true); - } - - public int getPoolSize() throws SQLException{ - if (driver == null) - driver = createDriver(); - return driver.getPool(getPoolProperties().getPoolName()).getSize(); - } - - public String toString() { - return super.toString()+"{"+getPoolProperties()+"}"; - } - -/*-----------------------------------------------------------------------*/ -// PROPERTIES WHEN NOT USED WITH FACTORY -/*------------------------------------------------------------------------*/ - public void setPoolProperties(PoolProperties poolProperties) { - this.poolProperties = poolProperties; - } - - public void setDriverClassName(String driverClassName) { - this.poolProperties.setDriverClassName(driverClassName); - } - - public void setInitialSize(int initialSize) { - this.poolProperties.setInitialSize(initialSize); - } - - public void setInitSQL(String initSQL) { - this.poolProperties.setInitSQL(initSQL); - } - - public void setLogAbandoned(boolean logAbandoned) { - this.poolProperties.setLogAbandoned(logAbandoned); - } - - public void setMaxActive(int maxActive) { - this.poolProperties.setMaxIdle(maxActive); - } - - public void setMaxIdle(int maxIdle) { - this.poolProperties.setMaxIdle(maxIdle); - } - - public void setMaxWait(int maxWait) { - this.poolProperties.setMaxWait(maxWait); - } - - public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { - this.poolProperties.setMinEvictableIdleTimeMillis( - minEvictableIdleTimeMillis); - } - - public void setMinIdle(int minIdle) { - this.setMinIdle(minIdle); - } - - public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { - this.poolProperties.setNumTestsPerEvictionRun(numTestsPerEvictionRun); - } - - public void setPassword(String password) { - this.poolProperties.setPassword(password); - this.poolProperties.getDbProperties().setProperty("password",this.poolProperties.getPassword()); - } - - public void setRemoveAbandoned(boolean removeAbandoned) { - this.poolProperties.setRemoveAbandoned(removeAbandoned); - } - - public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) { - this.poolProperties.setRemoveAbandonedTimeout(removeAbandonedTimeout); - } - - public void setTestOnBorrow(boolean testOnBorrow) { - this.poolProperties.setTestOnBorrow(testOnBorrow); - } - - public void setTestOnConnect(boolean testOnConnect) { - this.poolProperties.setTestOnConnect(testOnConnect); - } - - public void setTestOnReturn(boolean testOnReturn) { - this.poolProperties.setTestOnReturn(testOnReturn); - } - - public void setTestWhileIdle(boolean testWhileIdle) { - this.poolProperties.setTestWhileIdle(testWhileIdle); - } - - public void setTimeBetweenEvictionRunsMillis(int - timeBetweenEvictionRunsMillis) { - this.poolProperties.setTimeBetweenEvictionRunsMillis( - timeBetweenEvictionRunsMillis); - } - - public void setUrl(String url) { - this.poolProperties.setUrl(url); - } - - public void setUsername(String username) { - this.poolProperties.setUsername(username); - this.poolProperties.getDbProperties().setProperty("user",getPoolProperties().getUsername()); - } - - public void setValidationInterval(long validationInterval) { - this.poolProperties.setValidationInterval(validationInterval); - } - - public void setValidationQuery(String validationQuery) { - this.poolProperties.setValidationQuery(validationQuery); - } - - public void setJdbcInterceptors(String interceptors) { - this.getPoolProperties().setJdbcInterceptors(interceptors); - } - - public void setJmxEnabled(boolean enabled) { - this.getPoolProperties().setJmxEnabled(enabled); - } - - public void setConnectionProperties(String properties) { - try { - java.util.Properties prop = DataSourceFactory.getProperties(properties); - Iterator i = prop.keySet().iterator(); - while (i.hasNext()) { - String key = (String)i.next(); - String value = prop.getProperty(key); - getPoolProperties().getDbProperties().setProperty(key, value); - } - - }catch (Exception x) { - log.error("Unable to parse connection properties.", x); - throw new RuntimeException(x); - } - } - - -} diff --git a/java/org/apache/tomcat/jdbc/pool/Driver.java b/java/org/apache/tomcat/jdbc/pool/Driver.java deleted file mode 100644 index 9e03825ba..000000000 --- a/java/org/apache/tomcat/jdbc/pool/Driver.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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.tomcat.jdbc.pool; - - -import java.sql.Connection; -import java.sql.DriverPropertyInfo; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Properties; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -/** - * @author Filip Hanik - * @version 1.0 - */ -public class Driver implements java.sql.Driver { - - protected static Log log = LogFactory.getLog(Driver.class); - - protected static HashMap pooltable = new HashMap(11); - - public Driver() throws SQLException { - } - - public Driver(PoolProperties properties) throws SQLException { - init(properties); - } //Driver - - public void init(PoolProperties properties) throws SQLException { - if (pooltable.get(properties.getPoolName()) != null) - throw new SQLException("Pool identified by:" + properties.getPoolName() + " already exists."); - ConnectionPool pool = new ConnectionPool(properties); - pooltable.put(properties.getPoolName(), pool); - } - - public void closePool(String url, boolean all) throws SQLException { - ConnectionPool pool = (ConnectionPool) pooltable.get(url); - if (pool == null) { - throw new SQLException("No connection pool established for URL:" + url); - } else { - pool.close(all); - } - pooltable.remove(url); - } - - /** - * {@inheritDoc} - */ - public Connection connect(String url, Properties info) throws SQLException { - ConnectionPool pool = (ConnectionPool) pooltable.get(url); - if (pool == null) { - throw new SQLException("No connection pool established for URL:" + url); - } else { - try { - return pool.getConnection(); - } catch (SQLException forward) { - throw forward; - } catch (Exception e) { - throw new SQLException("Unknow pool exception:" + ConnectionPool.getStackTrace(e)); - } //catch - } //end if - } //connect - - /** - * {@inheritDoc} - */ - public boolean acceptsURL(String url) throws SQLException { - /* check if the driver has a connection pool with that name */ - return (pooltable.get(url) != null ? true : false); - } //acceptsUrl - - /** - * {@inheritDoc} - */ - public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws - SQLException { - return new DriverPropertyInfo[0]; - } //getPropertyInfo - - /** - * {@inheritDoc} - */ - public int getMajorVersion() { - return 1; - } - - /** - * {@inheritDoc} - */ - public int getMinorVersion() { - return 0; - } - - /** - * {@inheritDoc} - */ - public boolean jdbcCompliant() { - return true; - } - - public ConnectionPool getPool(String url) throws SQLException { - return (ConnectionPool) pooltable.get(url); - } - -} //class diff --git a/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java b/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java deleted file mode 100644 index 67d1086b2..000000000 --- a/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.tomcat.jdbc.pool; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; - -/** - * @author Filip Hanik - * @version 1.0 - */ -public abstract class JdbcInterceptor implements InvocationHandler { - public static final String CLOSE_VAL = "close"; - - private JdbcInterceptor next = null; - - public JdbcInterceptor() { - } - - /** - * {@inheritDoc} - */ - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (getNext()!=null) return getNext().invoke(this,method,args); - else throw new NullPointerException(); - } - - public JdbcInterceptor getNext() { - return next; - } - - public void setNext(JdbcInterceptor next) { - this.next = next; - } - - public abstract void reset(ConnectionPool parent, PooledConnection con); -} diff --git a/java/org/apache/tomcat/jdbc/pool/PoolProperties.java b/java/org/apache/tomcat/jdbc/pool/PoolProperties.java deleted file mode 100644 index 6f94d3694..000000000 --- a/java/org/apache/tomcat/jdbc/pool/PoolProperties.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * 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.tomcat.jdbc.pool; - - -import java.lang.reflect.Method; -import java.util.Properties; -/** - * @author Filip Hanik - * - */ -public class PoolProperties { - protected static volatile int poolCounter = 1; - protected Properties dbProperties = new Properties(); - protected String url = null; - protected String driverClassName = null; - protected Boolean defaultAutoCommit = null; - protected Boolean defaultReadOnly = null; - protected int defaultTransactionIsolation = DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION; - protected String defaultCatalog = null; - protected String connectionProperties; - protected int initialSize = 10; - protected int maxActive = 100; - protected int maxIdle = maxActive; - protected int minIdle = initialSize; - protected int maxWait = 30000; - protected String validationQuery; - protected boolean testOnBorrow = false; - protected boolean testOnReturn = false; - protected boolean testWhileIdle = false; - protected int timeBetweenEvictionRunsMillis = 5000; - protected int numTestsPerEvictionRun; - protected int minEvictableIdleTimeMillis = 60000; - protected boolean accessToUnderlyingConnectionAllowed; - protected boolean removeAbandoned = false; - protected int removeAbandonedTimeout = 60; - protected boolean logAbandoned = false; - protected int loginTimeout = 10000; - protected String name = "Filip Connection Pool["+(poolCounter++)+"]"; - protected String password; - protected String username; - protected long validationInterval = 30000; - protected boolean jmxEnabled = true; - protected String initSQL; - protected boolean testOnConnect =false; - private String jdbcInterceptors=null; - - public boolean isAccessToUnderlyingConnectionAllowed() { - return accessToUnderlyingConnectionAllowed; - } - - public String getConnectionProperties() { - return connectionProperties; - } - - public Properties getDbProperties() { - return dbProperties; - } - - public boolean isDefaultAutoCommit() { - return defaultAutoCommit; - } - - public String getDefaultCatalog() { - return defaultCatalog; - } - - public boolean isDefaultReadOnly() { - return defaultReadOnly; - } - - public int getDefaultTransactionIsolation() { - return defaultTransactionIsolation; - } - - public String getDriverClassName() { - return driverClassName; - } - - public int getInitialSize() { - return initialSize; - } - - public boolean isLogAbandoned() { - return logAbandoned; - } - - public int getLoginTimeout() { - return loginTimeout; - } - - public int getMaxActive() { - return maxActive; - } - - public int getMaxIdle() { - return maxIdle; - } - - public int getMaxWait() { - return maxWait; - } - - public int getMinEvictableIdleTimeMillis() { - return minEvictableIdleTimeMillis; - } - - public int getMinIdle() { - return minIdle; - } - - public String getName() { - return name; - } - - public int getNumTestsPerEvictionRun() { - return numTestsPerEvictionRun; - } - - public String getPassword() { - return password; - } - - public String getPoolName() { - return getName(); - } - - public boolean isRemoveAbandoned() { - return removeAbandoned; - } - - public int getRemoveAbandonedTimeout() { - return removeAbandonedTimeout; - } - - public boolean isTestOnBorrow() { - return testOnBorrow; - } - - public boolean isTestOnReturn() { - return testOnReturn; - } - - public boolean isTestWhileIdle() { - return testWhileIdle; - } - - public int getTimeBetweenEvictionRunsMillis() { - return timeBetweenEvictionRunsMillis; - } - - public String getUrl() { - return url; - } - - public String getUsername() { - return username; - } - - public String getValidationQuery() { - return validationQuery; - } - - public long getValidationInterval() { - return validationInterval; - } - - public String getInitSQL() { - return initSQL; - } - - public boolean isTestOnConnect() { - return testOnConnect; - } - - public String getJdbcInterceptors() { - return jdbcInterceptors; - } - - public String[] getJdbcInterceptorsAsArray() { - if (jdbcInterceptors==null) return new String[0]; - else { - return jdbcInterceptors.split(";"); - } - } - - public void setAccessToUnderlyingConnectionAllowed(boolean - accessToUnderlyingConnectionAllowed) { - this.accessToUnderlyingConnectionAllowed = - accessToUnderlyingConnectionAllowed; - } - - public void setConnectionProperties(String connectionProperties) { - this.connectionProperties = connectionProperties; - } - - public void setDbProperties(Properties dbProperties) { - this.dbProperties = dbProperties; - } - - public void setDefaultAutoCommit(Boolean defaultAutoCommit) { - this.defaultAutoCommit = defaultAutoCommit; - } - - public void setDefaultCatalog(String defaultCatalog) { - this.defaultCatalog = defaultCatalog; - } - - public void setDefaultReadOnly(Boolean defaultReadOnly) { - this.defaultReadOnly = defaultReadOnly; - } - - public void setDefaultTransactionIsolation(int defaultTransactionIsolation) { - this.defaultTransactionIsolation = defaultTransactionIsolation; - } - - public void setDriverClassName(String driverClassName) { - this.driverClassName = driverClassName; - } - - public void setInitialSize(int initialSize) { - this.initialSize = initialSize; - } - - public void setLogAbandoned(boolean logAbandoned) { - this.logAbandoned = logAbandoned; - } - - public void setLoginTimeout(int loginTimeout) { - this.loginTimeout = loginTimeout; - } - - public void setMaxActive(int maxActive) { - this.maxActive = maxActive; - } - - public void setMaxIdle(int maxIdle) { - this.maxIdle = maxIdle; - } - - public void setMaxWait(int maxWait) { - this.maxWait = maxWait; - } - - public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { - this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; - } - - public void setMinIdle(int minIdle) { - this.minIdle = minIdle; - } - - public void setName(String name) { - this.name = name; - } - - public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { - this.numTestsPerEvictionRun = numTestsPerEvictionRun; - } - - public void setPassword(String password) { - this.password = password; - } - - public void setRemoveAbandoned(boolean removeAbandoned) { - this.removeAbandoned = removeAbandoned; - } - - public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) { - this.removeAbandonedTimeout = removeAbandonedTimeout; - } - - public void setTestOnBorrow(boolean testOnBorrow) { - this.testOnBorrow = testOnBorrow; - } - - public void setTestWhileIdle(boolean testWhileIdle) { - this.testWhileIdle = testWhileIdle; - } - - public void setTestOnReturn(boolean testOnReturn) { - this.testOnReturn = testOnReturn; - } - - public void setTimeBetweenEvictionRunsMillis(int - timeBetweenEvictionRunsMillis) { - this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; - } - - public void setUrl(String url) { - this.url = url; - } - - public void setUsername(String username) { - this.username = username; - } - - public void setValidationInterval(long validationInterval) { - this.validationInterval = validationInterval; - } - - public void setValidationQuery(String validationQuery) { - this.validationQuery = validationQuery; - } - - public void setInitSQL(String initSQL) { - this.initSQL = initSQL; - } - - public void setTestOnConnect(boolean testOnConnect) { - this.testOnConnect = testOnConnect; - } - - public void setJdbcInterceptors(String jdbcInterceptors) { - this.jdbcInterceptors = jdbcInterceptors; - } - - public String toString() { - StringBuffer buf = new StringBuffer("ConnectionPool["); - try { - String[] fields = DataSourceFactory.ALL_PROPERTIES; - for (int i=0; i0; - result = result && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0); - result = result && (isTestWhileIdle() && getValidationQuery()!=null); - return result; - } -} diff --git a/java/org/apache/tomcat/jdbc/pool/PooledConnection.java b/java/org/apache/tomcat/jdbc/pool/PooledConnection.java deleted file mode 100644 index 79983912a..000000000 --- a/java/org/apache/tomcat/jdbc/pool/PooledConnection.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * 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.tomcat.jdbc.pool; - - -import java.lang.ref.WeakReference; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * @author Filip Hanik - * @version 1.0 - */ -public class PooledConnection { - - public static final int VALIDATE_BORROW = 1; - public static final int VALIDATE_RETURN = 2; - public static final int VALIDATE_IDLE = 3; - public static final int VALIDATE_INIT = 4; - - protected static Log log = LogFactory.getLog(PooledConnection.class); - protected static volatile int counter = 1; - - protected PoolProperties poolProperties; - protected java.sql.Connection connection; - protected String abandonTrace = null; - protected long timestamp; - protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false); - protected boolean discarded = false; - protected long lastValidated = System.currentTimeMillis(); - protected int instanceCount = 0; - protected ConnectionPool parent; - - protected WeakReference handler = null; - - public PooledConnection(PoolProperties prop, ConnectionPool parent) throws SQLException { - instanceCount = counter++; - poolProperties = prop; - this.parent = parent; - } - - protected void connect() throws SQLException { - if (connection != null) { - try { - this.disconnect(); - } catch (Exception x) { - log.error("Unable to disconnect previous connection.", x); - } //catch - } //end if - java.sql.Driver driver = null; - try { - driver = (java.sql.Driver) Class.forName(poolProperties.getDriverClassName(), - true, PooledConnection.class.getClassLoader()).newInstance(); - } catch (java.lang.Exception cn) { - log.error("Unable to instantiate JDBC driver.", cn); - throw new SQLException(cn.getMessage()); - } - String driverURL = poolProperties.getUrl(); - String usr = poolProperties.getUsername(); - String pwd = poolProperties.getPassword(); - poolProperties.getDbProperties().setProperty("user", usr); - poolProperties.getDbProperties().setProperty("password", pwd); - connection = driver.connect(driverURL, poolProperties.getDbProperties()); - //set up the default state - if (poolProperties.getDefaultReadOnly()!=null) connection.setReadOnly(poolProperties.getDefaultReadOnly().booleanValue()); - if (poolProperties.getDefaultAutoCommit()!=null) connection.setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue()); - if (poolProperties.getDefaultCatalog()!=null) connection.setCatalog(poolProperties.getDefaultCatalog()); - if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation()); - - this.discarded = false; - } - - protected void reconnect() throws SQLException { - this.disconnect(); - this.connect(); - } //reconnect - - protected synchronized void disconnect() throws SQLException { - if (isDiscarded()) { - return; - } - setDiscarded(true); - if (connection != null) { - connection.close(); - } - connection = null; - parent.finalize(this); - } - - -//============================================================================ -// com.filip.util.IPoolObject methods -//============================================================================ - - public long getAbandonTimeout() { - if (poolProperties.getRemoveAbandonedTimeout() <= 0) { - return Long.MAX_VALUE; - } else { - return poolProperties.getRemoveAbandonedTimeout()*1000; - } //end if - } - - public boolean abandon() { - try { - disconnect(); - } catch (SQLException x) { - log.error("", x); - } //catch - return false; - } - - protected boolean doValidate(int action) { - if (action == PooledConnection.VALIDATE_BORROW && - poolProperties.isTestOnBorrow()) - return true; - else if (action == PooledConnection.VALIDATE_RETURN && - poolProperties.isTestOnReturn()) - return true; - else if (action == PooledConnection.VALIDATE_IDLE && - poolProperties.isTestWhileIdle()) - return true; - else if (action == PooledConnection.VALIDATE_INIT && - poolProperties.isTestOnConnect()) - return true; - else if (action == PooledConnection.VALIDATE_INIT && - poolProperties.getInitSQL()!=null) - return true; - else - return false; - } - - /**Returns true if the object is still valid. if not - * the pool will call the getExpiredAction() and follow up with one - * of the four expired methods - */ - public boolean validate(int validateAction) { - return validate(validateAction,null); - } - - public boolean validate(int validateAction,String sql) { - if (!doValidate(validateAction)) { - //no validation required, no init sql and props not set - return true; - } - - String query = (VALIDATE_INIT==validateAction && (poolProperties.getInitSQL()!=null))?poolProperties.getInitSQL():sql; - - if (query==null) query = poolProperties.getValidationQuery(); - - if (query == null) { - //no validation possible - return true; - } - long now = System.currentTimeMillis(); - if (this.poolProperties.getValidationInterval() > 0 && - (now - this.lastValidated) < - this.poolProperties.getValidationInterval()) { - return true; - } - try { - Statement stmt = connection.createStatement(); - boolean exec = stmt.execute(query); - stmt.close(); - this.lastValidated = now; - return true; - } catch (Exception ignore) { - if (log.isDebugEnabled()) - log.debug("Unable to validate object:",ignore); - } - return false; - } //validate - - /** - * The time limit for how long the object - * can remain unused before it is released - */ - public long getReleaseTime() { - return this.poolProperties.getMinEvictableIdleTimeMillis(); - } - - /** - * This method is called if (Now - timeCheckedIn > getReleaseTime()) - */ - public void release() { - try { - disconnect(); - } catch (SQLException x) { - //TODO - } - - } - - /** - * The pool will set the stack trace when it is check out and - * checked in - */ - - public void setStackTrace(String trace) { - abandonTrace = trace; - } - - public String getStackTrace() { - return abandonTrace; - } - - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - - public void setDiscarded(boolean discarded) { - if (this.discarded && !discarded) throw new IllegalStateException("Unable to change the state once the connection has been discarded"); - this.discarded = discarded; - } - - public void setLastValidated(long lastValidated) { - this.lastValidated = lastValidated; - } - - public void setPoolProperties(PoolProperties poolProperties) { - this.poolProperties = poolProperties; - } - - public long getTimestamp() { - return timestamp; - } - - public boolean isDiscarded() { - return discarded; - } - - public long getLastValidated() { - return lastValidated; - } - - public PoolProperties getPoolProperties() { - return poolProperties; - } - - public void lock() { - if (this.poolProperties.isPoolSweeperEnabled()) { - //optimized, only use a lock when there is concurrency - lock.writeLock().lock(); - } - } - - public void unlock() { - if (this.poolProperties.isPoolSweeperEnabled()) { - //optimized, only use a lock when there is concurrency - lock.writeLock().unlock(); - } - } - - public java.sql.Connection getConnection() { - return this.connection; - } - - public JdbcInterceptor getHandler() { - return (handler!=null)?handler.get():null; - } - - public void setHandler(JdbcInterceptor handler) { - if (handler==null) { - if (this.handler!=null) this.handler.clear(); - } else if (this.handler==null) { - this.handler = new WeakReference(handler); - } else if (this.handler.get()==null) { - this.handler.clear(); - this.handler = new WeakReference(handler); - } else if (this.handler.get()!=handler) { - this.handler.clear(); - this.handler = new WeakReference(handler); - } - } - -} diff --git a/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java b/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java deleted file mode 100644 index 9a66536bb..000000000 --- a/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.tomcat.jdbc.pool; - -import java.lang.reflect.Method; -import java.sql.Connection; -import java.sql.SQLException; -/** - * @author Filip Hanik - */ -public class ProxyConnection extends JdbcInterceptor { - - protected PooledConnection connection = null; - - protected ConnectionPool pool = null; - - public PooledConnection getConnection() { - return connection; - } - - public void setConnection(PooledConnection connection) { - this.connection = connection; - } - - public ConnectionPool getPool() { - return pool; - } - - public void setPool(ConnectionPool pool) { - this.pool = pool; - } - - protected ProxyConnection(ConnectionPool parent, PooledConnection con) throws SQLException { - pool = parent; - connection = con; - } - - public void reset(ConnectionPool parent, PooledConnection con) { - this.pool = parent; - this.connection = con; - } - - public boolean isWrapperFor(Class iface) throws SQLException { - return (iface.isInstance(connection.getConnection())); - } - - - public Object unwrap(Class iface) throws SQLException { - if (isWrapperFor(iface)) { - return connection.getConnection(); - } else { - throw new SQLException("Not a wrapper of "+iface.getName()); - } - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (isClosed()) throw new SQLException("Connection has already been closed."); - if (CLOSE_VAL==method.getName()) { - PooledConnection poolc = this.connection; - this.connection = null; - pool.returnConnection(poolc); - return null; - } - return method.invoke(connection.getConnection(),args); - } - - public boolean isClosed() { - return connection==null || connection.isDiscarded(); - } - - public PooledConnection getDelegateConnection() { - return connection; - } - - public ConnectionPool getParentPool() { - return pool; - } - -} diff --git a/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java b/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java deleted file mode 100644 index b30ae01fd..000000000 --- a/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.tomcat.jdbc.pool.interceptor; - -import java.lang.reflect.Method; - -import org.apache.tomcat.jdbc.pool.ConnectionPool; -import org.apache.tomcat.jdbc.pool.DataSourceFactory; -import org.apache.tomcat.jdbc.pool.JdbcInterceptor; -import org.apache.tomcat.jdbc.pool.PooledConnection; - -/** - * Interceptor that keep track of connection state to avoid roundtrips to the database - * @author fhanik - * - */ - -public class ConnectionState extends JdbcInterceptor { - - protected final String[] readState = {"getAutoCommit","getTransactionIsolation","isReadOnly"}; - protected final String[] writeState = {"setAutoCommit","setTransactionIsolation","setReadOnly"}; - - protected Boolean autoCommit = null; - protected Integer transactionIsolation = null; - protected Boolean readOnly = null; - - public void reset(ConnectionPool parent, PooledConnection con) { - autoCommit = null; - transactionIsolation = null; - readOnly = null; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - String name = method.getName(); - boolean read = false; - int index = -1; - for (int i=0; (!read) && i10) { - StringBuffer out = new StringBuffer("\n\tType:"); - out.append(parent.getClass().getName()); - out.append("\n\tCreate/Prepare args:"); - for (int i=0; this.args!=null && i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java new file mode 100644 index 000000000..1b594f32c --- /dev/null +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java @@ -0,0 +1,715 @@ +/* + * 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.tomcat.jdbc.pool; + +import java.lang.management.ManagementFactory; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +import org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean; + +import java.util.concurrent.atomic.AtomicInteger; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; + +/** + * @author Filip Hanik + * @version 1.0 + */ + +public class ConnectionPool { + + //logger + protected static Log log = LogFactory.getLog(ConnectionPool.class); + + //=============================================================================== + // INSTANCE/QUICK ACCESS VARIABLE + //=============================================================================== + + /** + * All the information about the connection pool + */ + protected PoolProperties poolProperties; + + /** + * Contains all the connections that are in use + */ + protected BlockingQueue busy; + + /** + * Contains all the idle connections + */ + protected BlockingQueue idle; + + /** + * The thread that is responsible for checking abandoned and idle threads + */ + protected PoolCleaner poolCleaner; + + /** + * Pool closed flag + */ + protected boolean closed = false; + + /** + * Size of the pool + */ + protected AtomicInteger size = new AtomicInteger(0); + + /** + * Since newProxyInstance performs the same operation, over and over + * again, it is much more optimized if we simply store the constructor ourselves. + */ + protected Constructor proxyClassConstructor; + + + //=============================================================================== + // PUBLIC METHODS + //=============================================================================== + + /** + * Instantiate a connection pool. This will create connections if initialSize is larger than 0 + * @param prop PoolProperties - all the properties for this connection pool + * @throws SQLException + */ + public ConnectionPool(PoolProperties prop) throws SQLException { + //setup quick access variables and pools + init(prop); + } + + /** + * Borrows a connection from the pool + * @return Connection - a java.sql.Connection reflection proxy, wrapping the underlying object. + * @throws SQLException + */ + public Connection getConnection() throws SQLException { + //check out a connection + PooledConnection con = (PooledConnection)borrowConnection(); + JdbcInterceptor handler = con.getHandler(); + if (handler==null) { + //build the proxy handler + handler = new ProxyConnection(this,con); + //set up the interceptor chain + String[] proxies = getPoolProperties().getJdbcInterceptorsAsArray(); + for (int i=proxies.length-1; i>=0; i--) { + try { + JdbcInterceptor interceptor = + (JdbcInterceptor) Class.forName(proxies[i], true, + Thread.currentThread().getContextClassLoader()).newInstance(); + interceptor.setNext(handler); + handler = interceptor; + }catch(Exception x) { + SQLException sx = new SQLException("Unable to instantiate interceptor chain."); + sx.initCause(x); + throw sx; + } + } + //cache handler for the next iteration + con.setHandler(handler); + } else { + JdbcInterceptor next = handler; + //we have a cached handler, reset it + while (next!=null) { + next.reset(this, con); + next = next.getNext(); + } + } + + try { + //cache the constructor + if (proxyClassConstructor == null ) { + Class proxyClass = Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class}); + proxyClassConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class }); + } + //create the proxy + //TODO possible optimization, keep track if this connection was returned properly, and don't generate a new facade + Connection connection = (Connection)proxyClassConstructor.newInstance(new Object[] { handler }); + //return the connection + return connection; + }catch (Exception x) { + throw new SQLException(); + } + } + + /** + * Returns the name of this pool + * @return String + */ + public String getName() { + return getPoolProperties().getPoolName(); + } + + /** + * Returns the pool properties associated with this connection pool + * @return PoolProperties + */ + public PoolProperties getPoolProperties() { + return this.poolProperties; + } + + /** + * Returns the total size of this pool, this includes both busy and idle connections + * @return int + */ + public int getSize() { + return idle.size()+busy.size(); + } + + /** + * Returns the number of connections that are in use + * @return int + */ + public int getActive() { + return busy.size(); + } + + public int getIdle() { + return idle.size(); + } + + /** + * Returns true if {@link #close close} has been called, and the connection pool is unusable + * @return boolean + */ + public boolean isClosed() { + return this.closed; + } + + @Override + protected void finalize() throws Throwable { + close(true); + } + + /** + * Closes the pool and all disconnects all idle connections + * Active connections will be closed upon the {@link java.sql.Connection#close close} method is called + * on the underlying connection instead of being returned to the pool + * @param force - true to even close the active connections + */ + protected void close(boolean force) { + //are we already closed + if (this.closed) return; + //prevent other threads from entering + this.closed = true; + //stop background thread + if (poolCleaner!=null) { + poolCleaner.stopRunning(); + } + + /* release all idle connections */ + BlockingQueue pool = (idle.size()>0)?idle:(force?busy:idle); + while (pool.size()>0) { + try { + //retrieve the next connection + PooledConnection con = pool.poll(1000, TimeUnit.MILLISECONDS); + //close it and retrieve the next one, if one is available + while (con != null) { + //close the connection + if (pool==idle) + release(con); + else + abandon(con); + con = pool.poll(1000, TimeUnit.MILLISECONDS); + } //while + } catch (InterruptedException ex) { + Thread.currentThread().interrupted(); + } + if (pool.size()==0 && force && pool!=busy) pool = busy; + } + size.set(0); + if (this.getPoolProperties().isJmxEnabled()) stopJmx(); + } //closePool + + + //=============================================================================== + // PROTECTED METHODS + //=============================================================================== + /** + * Initialize the connection pool - called from the constructor + * @param properties PoolProperties - properties used to initialize the pool with + * @throws SQLException + */ + protected void init (PoolProperties properties) throws SQLException { + poolProperties = properties; + //make space for 10 extra in case we flow over a bit + busy = new ArrayBlockingQueue(properties.getMaxActive(),false); + //make space for 10 extra in case we flow over a bit + idle = new ArrayBlockingQueue(properties.getMaxActive(),false); + + //if the evictor thread is supposed to run, start it now + if (properties.isPoolSweeperEnabled()) { + poolCleaner = new PoolCleaner("[Pool-Cleaner]:" + properties.getName(), this, properties.getTimeBetweenEvictionRunsMillis()); + poolCleaner.start(); + } //end if + + if (properties.getMaxActive()properties.getMaxActive()) { + log.warn("minIdle is larger than maxActive, setting minIdle to: "+properties.getMaxActive()); + properties.setMinIdle(properties.getMaxActive()); + } + if (properties.getMaxIdle()>properties.getMaxActive()) { + log.warn("maxIdle is larger than maxActive, setting maxIdle to: "+properties.getMaxActive()); + properties.setMaxIdle(properties.getMaxActive()); + } + if (properties.getMaxIdle()= maxWait) { + throw new SQLException( + "Pool empty. Unable to fetch a connection in " + (maxWait / 1000) + + " seconds, none available["+busy.size()+" in use]."); + } else { + //no timeout, lets try again + continue; + } + } + } //while + } + + protected PooledConnection createConnection(long now, PooledConnection con) { + //no connections where available we'll create one + boolean error = false; + try { + //connect and validate the connection + con = create(); + con.lock(); + if (!busy.offer(con)) { + log.debug("Connection doesn't fit into busy array, connection will not be traceable."); + } + con.connect(); + if (con.validate(PooledConnection.VALIDATE_INIT)) { + //no need to lock a new one, its not contented + con.setTimestamp(now); + if (getPoolProperties().isLogAbandoned()) { + con.setStackTrace(getThreadDump()); + } + return con; + } //end if + } catch (Exception e) { + error = true; + log.error("Unable to create a new JDBC connection.", e); + } finally { + if (error ) { + release(con); + busy.remove(con); + } + con.unlock(); + }//catch + return null; + } + + protected PooledConnection borrowConnection(long now, PooledConnection con) { + //we have a connection, lets set it up + boolean setToNull = false; + try { + con.lock(); + if (con.isDiscarded()) { + //connection has already been disconnected + setToNull = true; + } else if (con.validate(PooledConnection.VALIDATE_BORROW)) { + //set the timestamp + con.setTimestamp(now); + if (getPoolProperties().isLogAbandoned()) { + //set the stack trace for this pool + con.setStackTrace(getThreadDump()); + } + if (!busy.offer(con)) { + log.debug("Connection doesn't fit into busy array, connection will not be traceable."); + } + return con; + } else { + /*if the object wasn't validated, we may as well remove it*/ + release(con); + setToNull = true; + } //end if + } finally { + con.unlock(); + if (setToNull) { + con = null; + } + } + return con; + } + + /** + * Returns a connection to the pool + * @param con PooledConnection + */ + protected void returnConnection(PooledConnection con) { + if (isClosed()) { + //if the connection pool is closed + //close the connection instead of returning it + release(con); + return; + } //end if + + if (con != null) { + try { + con.lock(); + + if (busy.remove(con)) { + if ((!con.isDiscarded()) && (!isClosed()) && + con.validate(PooledConnection.VALIDATE_RETURN)) { + con.setStackTrace(null); + con.setTimestamp(System.currentTimeMillis()); + if (!idle.offer(con)) { + if (log.isDebugEnabled()) { + log.debug("Connection ["+con+"] will be closed and not returned to the pool, idle.offer failed."); + } + release(con); + } + } else { + if (log.isDebugEnabled()) { + log.debug("Connection ["+con+"] will be closed and not returned to the pool."); + } + release(con); + } //end if + } else { + if (log.isDebugEnabled()) { + log.debug("Connection ["+con+"] will be closed and not returned to the pool, busy.remove failed."); + } + release(con); + } + } finally { + con.unlock(); + } + } //end if + } //checkIn + + public void checkAbandoned() { + try { + long now = System.currentTimeMillis(); + Iterator locked = busy.iterator(); + while (locked.hasNext()) { + PooledConnection con = locked.next(); + boolean setToNull = false; + try { + con.lock(); + //the con has been returned to the pool + //ignore it + if (idle.contains(con)) + continue; + long time = con.getTimestamp(); + if ((now - time) > con.getAbandonTimeout()) { + busy.remove(con); + abandon(con); + release(con); + setToNull = true; + } else { + //do nothing + } //end if + } finally { + con.unlock(); + if (setToNull) + con = null; + } + } //while + } catch (ConcurrentModificationException e) { + log.debug("checkAbandoned failed." ,e); + } catch (Exception e) { + log.warn("checkAbandoned failed, it will be retried.",e); + } + } + + public void checkIdle() { + try { + long now = System.currentTimeMillis(); + Iterator unlocked = idle.iterator(); + while ( (idle.size()>=getPoolProperties().getMinIdle()) && unlocked.hasNext()) { + PooledConnection con = unlocked.next(); + boolean setToNull = false; + try { + con.lock(); + //the con been taken out, we can't clean it up + if (busy.contains(con)) + continue; + long time = con.getTimestamp(); + if (((now - time) > con.getReleaseTime()) && (getSize()>getPoolProperties().getMinIdle())) { + release(con); + idle.remove(con); + setToNull = true; + } else { + //do nothing + } //end if + } finally { + con.unlock(); + if (setToNull) + con = null; + } + } //while + } catch (ConcurrentModificationException e) { + log.debug("checkIdle failed." ,e); + } catch (Exception e) { + log.warn("checkIdle failed, it will be retried.",e); + } + + } + + public void testAllIdle() { + try { + Iterator unlocked = idle.iterator(); + while (unlocked.hasNext()) { + PooledConnection con = unlocked.next(); + try { + con.lock(); + //the con been taken out, we can't clean it up + if (busy.contains(con)) + continue; + if (!con.validate(PooledConnection.VALIDATE_IDLE)) { + idle.remove(con); + con.release(); + } + } finally { + con.unlock(); + } + } //while + } catch (ConcurrentModificationException e) { + log.debug("testAllIdle failed." ,e); + } catch (Exception e) { + log.warn("testAllIdle failed, it will be retried.",e); + } + + } + + + protected static String getThreadDump() { + Exception x = new Exception(); + x.fillInStackTrace(); + return getStackTrace(x); + } + + protected static String getStackTrace(Exception x) { + if (x == null) { + return null; + } else { + java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream(); + java.io.PrintStream writer = new java.io.PrintStream(bout); + x.printStackTrace(writer); + String result = bout.toString(); + return result; + } //end if + } + + + protected PooledConnection create() throws java.lang.Exception { + PooledConnection con = new PooledConnection(getPoolProperties(), this); + return con; + } + + protected void finalize(PooledConnection con) { + size.addAndGet(-1); + } + + public void startJmx() { + try { + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName name = new ObjectName("org.apache.tomcat.jdbc.pool.jmx:type=ConnectionPool,name="+getName()); + mbs.registerMBean(new org.apache.tomcat.jdbc.pool.jmx.ConnectionPool(this), name); + } catch (Exception x) { + log.warn("Unable to start JMX integration for connection pool. Instance["+getName()+"] can't be monitored.",x); + } + } + + public void stopJmx() { + try { + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName name = new ObjectName("org.apache.tomcat.jdbc.pool.jmx:type=ConnectionPool,name="+getName()); + mbs.unregisterMBean(name); + }catch (Exception x) { + log.warn("Unable to stop JMX integration for connection pool. Instance["+getName()+"].",x); + } + } + + + protected class PoolCleaner extends Thread { + protected ConnectionPool pool; + protected long sleepTime; + protected boolean run = true; + PoolCleaner(String name, ConnectionPool pool, long sleepTime) { + super(name); + this.setDaemon(true); + this.pool = pool; + this.sleepTime = sleepTime; + if (sleepTime <= 0) { + pool.log.warn("Database connection pool evicter thread interval is set to 0, defaulting to 30 seconds"); + this.sleepTime = 1000 * 30; + } else if (sleepTime < 1000) { + pool.log.warn("Database connection pool evicter thread interval is set to lower than 1 second."); + } + } + + public void run() { + while (run) { + try { + sleep(sleepTime); + } catch (InterruptedException e) { + // ignore it + Thread.currentThread().interrupted(); + continue; + } //catch + + if (pool.isClosed()) { + if (pool.getSize() <= 0) { + run = false; + } + } else { + try { + if (pool.getPoolProperties().isRemoveAbandoned()) + pool.checkAbandoned(); + if (pool.getPoolProperties().getMaxIdle()JNDI object factory that creates an instance of + * BasicDataSource that has been configured based on the + * RefAddr values of the specified Reference, + * which must match the names and data types of the + * BasicDataSource bean properties.

+ *
+ * Properties available for configuration:
+ * Commons DBCP properties
+ *
    + *
  1. initSQL - A query that gets executed once, right after the connection is established.
  2. + *
  3. testOnConnect - run validationQuery after connection has been established.
  4. + *
  5. validationInterval - avoid excess validation, only run validation at most at this frequency - time in milliseconds.
  6. + *
  7. jdbcInterceptors - a semicolon separated list of classnames extending {@link JdbcInterceptor} class.
  8. + *
  9. jmxEnabled - true of false, whether to register the pool with JMX.
  10. + *
+ * @author Craig R. McClanahan + * @author Dirk Verbeeck + * @author Filip Hanik + */ +public class DataSourceFactory implements ObjectFactory { + protected static Log log = LogFactory.getLog(DataSourceFactory.class); + + protected final static String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit"; + protected final static String PROP_DEFAULTREADONLY = "defaultReadOnly"; + protected final static String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation"; + protected final static String PROP_DEFAULTCATALOG = "defaultCatalog"; + + protected final static String PROP_DRIVERCLASSNAME = "driverClassName"; + protected final static String PROP_PASSWORD = "password"; + protected final static String PROP_URL = "url"; + protected final static String PROP_USERNAME = "username"; + + protected final static String PROP_MAXACTIVE = "maxActive"; + protected final static String PROP_MAXIDLE = "maxIdle"; + protected final static String PROP_MINIDLE = "minIdle"; + protected final static String PROP_INITIALSIZE = "initialSize"; + protected final static String PROP_MAXWAIT = "maxWait"; + + protected final static String PROP_TESTONBORROW = "testOnBorrow"; + protected final static String PROP_TESTONRETURN = "testOnReturn"; + protected final static String PROP_TESTWHILEIDLE = "testWhileIdle"; + protected final static String PROP_TESTONCONNECT = "testOnConnect"; + protected final static String PROP_VALIDATIONQUERY = "validationQuery"; + + protected final static String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis"; + protected final static String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun"; + protected final static String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis"; + + protected final static String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed"; + + protected final static String PROP_REMOVEABANDONED = "removeAbandoned"; + protected final static String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout"; + protected final static String PROP_LOGABANDONED = "logAbandoned"; + + protected final static String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements"; + protected final static String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements"; + protected final static String PROP_CONNECTIONPROPERTIES = "connectionProperties"; + + protected final static String PROP_INITSQL = "initSQL"; + protected final static String PROP_INTERCEPTORS = "jdbcInterceptors"; + protected final static String PROP_VALIDATIONINTERVAL = "validationInterval"; + protected final static String PROP_JMX_ENABLED = "jmxEnabled"; + + public static final int UNKNOWN_TRANSACTIONISOLATION = -1; + + + protected final static String[] ALL_PROPERTIES = { + PROP_DEFAULTAUTOCOMMIT, + PROP_DEFAULTREADONLY, + PROP_DEFAULTTRANSACTIONISOLATION, + PROP_DEFAULTCATALOG, + PROP_DRIVERCLASSNAME, + PROP_MAXACTIVE, + PROP_MAXIDLE, + PROP_MINIDLE, + PROP_INITIALSIZE, + PROP_MAXWAIT, + PROP_TESTONBORROW, + PROP_TESTONRETURN, + PROP_TIMEBETWEENEVICTIONRUNSMILLIS, + PROP_NUMTESTSPEREVICTIONRUN, + PROP_MINEVICTABLEIDLETIMEMILLIS, + PROP_TESTWHILEIDLE, + PROP_TESTONCONNECT, + PROP_PASSWORD, + PROP_URL, + PROP_USERNAME, + PROP_VALIDATIONQUERY, + PROP_VALIDATIONINTERVAL, + PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED, + PROP_REMOVEABANDONED, + PROP_REMOVEABANDONEDTIMEOUT, + PROP_LOGABANDONED, + PROP_POOLPREPAREDSTATEMENTS, + PROP_MAXOPENPREPAREDSTATEMENTS, + PROP_CONNECTIONPROPERTIES, + PROP_INITSQL, + PROP_INTERCEPTORS, + PROP_JMX_ENABLED + }; + + // -------------------------------------------------- ObjectFactory Methods + + /** + *

Create and return a new BasicDataSource instance. If no + * instance can be created, return null instead.

+ * + * @param obj The possibly null object containing location or + * reference information that can be used in creating an object + * @param name The name of this object relative to nameCtx + * @param nameCtx The context relative to which the name + * parameter is specified, or null if name + * is relative to the default initial context + * @param environment The possibly null environment that is used in + * creating this object + * + * @exception Exception if an exception occurs creating the instance + */ + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) throws Exception { + + // We only know how to deal with javax.naming.References + // that specify a class name of "javax.sql.DataSource" + if ((obj == null) || !(obj instanceof Reference)) { + return null; + } + Reference ref = (Reference) obj; + if (!"javax.sql.DataSource".equals(ref.getClassName())) { + return null; + } + + Properties properties = new Properties(); + for (int i = 0; i < ALL_PROPERTIES.length; i++) { + String propertyName = ALL_PROPERTIES[i]; + RefAddr ra = ref.get(propertyName); + if (ra != null) { + String propertyValue = ra.getContent().toString(); + properties.setProperty(propertyName, propertyValue); + } + } + + return createDataSource(properties); + } + + /** + * Creates and configures a {@link BasicDataSource} instance based on the + * given properties. + * + * @param properties the datasource configuration properties + * @throws Exception if an error occurs creating the data source + */ + public static DataSource createDataSource(Properties properties) throws Exception { + org.apache.tomcat.jdbc.pool.DataSourceProxy dataSource = new org.apache.tomcat.jdbc.pool.DataSourceProxy(); + + String value = null; + + value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT); + if (value != null) { + dataSource.getPoolProperties().setDefaultAutoCommit(Boolean.valueOf(value)); + } + + value = properties.getProperty(PROP_DEFAULTREADONLY); + if (value != null) { + dataSource.getPoolProperties().setDefaultReadOnly(Boolean.valueOf(value)); + } + + value = properties.getProperty(PROP_DEFAULTTRANSACTIONISOLATION); + if (value != null) { + int level = UNKNOWN_TRANSACTIONISOLATION; + if ("NONE".equalsIgnoreCase(value)) { + level = Connection.TRANSACTION_NONE; + } else if ("READ_COMMITTED".equalsIgnoreCase(value)) { + level = Connection.TRANSACTION_READ_COMMITTED; + } else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) { + level = Connection.TRANSACTION_READ_UNCOMMITTED; + } else if ("REPEATABLE_READ".equalsIgnoreCase(value)) { + level = Connection.TRANSACTION_REPEATABLE_READ; + } else if ("SERIALIZABLE".equalsIgnoreCase(value)) { + level = Connection.TRANSACTION_SERIALIZABLE; + } else { + try { + level = Integer.parseInt(value); + } catch (NumberFormatException e) { + System.err.println("Could not parse defaultTransactionIsolation: " + value); + System.err.println("WARNING: defaultTransactionIsolation not set"); + System.err.println("using default value of database driver"); + level = UNKNOWN_TRANSACTIONISOLATION; + } + } + dataSource.getPoolProperties().setDefaultTransactionIsolation(level); + } + + value = properties.getProperty(PROP_DEFAULTCATALOG); + if (value != null) { + dataSource.getPoolProperties().setDefaultCatalog(value); + } + + value = properties.getProperty(PROP_DRIVERCLASSNAME); + if (value != null) { + dataSource.getPoolProperties().setDriverClassName(value); + } + + value = properties.getProperty(PROP_MAXACTIVE); + if (value != null) { + dataSource.getPoolProperties().setMaxActive(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_MAXIDLE); + if (value != null) { + dataSource.getPoolProperties().setMaxIdle(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_MINIDLE); + if (value != null) { + dataSource.getPoolProperties().setMinIdle(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_INITIALSIZE); + if (value != null) { + dataSource.getPoolProperties().setInitialSize(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_MAXWAIT); + if (value != null) { + dataSource.getPoolProperties().setMaxWait(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_TESTONBORROW); + if (value != null) { + dataSource.getPoolProperties().setTestOnBorrow(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_TESTONRETURN); + if (value != null) { + dataSource.getPoolProperties().setTestOnReturn(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_TESTONCONNECT); + if (value != null) { + dataSource.getPoolProperties().setTestOnConnect(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS); + if (value != null) { + dataSource.getPoolProperties().setTimeBetweenEvictionRunsMillis(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN); + if (value != null) { + dataSource.getPoolProperties().setNumTestsPerEvictionRun(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS); + if (value != null) { + dataSource.getPoolProperties().setMinEvictableIdleTimeMillis(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_TESTWHILEIDLE); + if (value != null) { + dataSource.getPoolProperties().setTestWhileIdle(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_PASSWORD); + if (value != null) { + dataSource.getPoolProperties().setPassword(value); + } + + value = properties.getProperty(PROP_URL); + if (value != null) { + dataSource.getPoolProperties().setUrl(value); + } + + value = properties.getProperty(PROP_USERNAME); + if (value != null) { + dataSource.getPoolProperties().setUsername(value); + } + + value = properties.getProperty(PROP_VALIDATIONQUERY); + if (value != null) { + dataSource.getPoolProperties().setValidationQuery(value); + } + + value = properties.getProperty(PROP_VALIDATIONINTERVAL); + if (value != null) { + dataSource.getPoolProperties().setValidationInterval(Long.parseLong(value)); + } + + value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED); + if (value != null) { + dataSource.getPoolProperties(). + setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_REMOVEABANDONED); + if (value != null) { + dataSource.getPoolProperties().setRemoveAbandoned(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT); + if (value != null) { + dataSource.getPoolProperties().setRemoveAbandonedTimeout(Integer.parseInt(value)); + } + + value = properties.getProperty(PROP_LOGABANDONED); + if (value != null) { + dataSource.getPoolProperties().setLogAbandoned(Boolean.valueOf(value).booleanValue()); + } + + value = properties.getProperty(PROP_POOLPREPAREDSTATEMENTS); + if (value != null) { + log.warn(PROP_POOLPREPAREDSTATEMENTS + " is not a valid setting, it will have no effect."); + } + + value = properties.getProperty(PROP_MAXOPENPREPAREDSTATEMENTS); + if (value != null) { + log.warn(PROP_MAXOPENPREPAREDSTATEMENTS + " is not a valid setting, it will have no effect."); + } + + value = properties.getProperty(PROP_CONNECTIONPROPERTIES); + if (value != null) { + Properties p = getProperties(value); + dataSource.getPoolProperties().setDbProperties(p); + } else { + dataSource.getPoolProperties().setDbProperties(new Properties()); + } + + dataSource.getPoolProperties().getDbProperties().setProperty("user",dataSource.getPoolProperties().getUsername()); + dataSource.getPoolProperties().getDbProperties().setProperty("password",dataSource.getPoolProperties().getPassword()); + + value = properties.getProperty(PROP_INITSQL); + if (value != null) { + dataSource.getPoolProperties().setInitSQL(value); + } + + value = properties.getProperty(PROP_INTERCEPTORS); + if (value != null) { + dataSource.getPoolProperties().setJdbcInterceptors(value); + } + + value = properties.getProperty(PROP_JMX_ENABLED); + if (value != null) { + dataSource.getPoolProperties().setJmxEnabled(Boolean.parseBoolean(value)); + } + + // Return the configured DataSource instance + DataSource ds = getDataSource(dataSource); + return ds; + } + + public static DataSource getDataSource(org.apache.tomcat.jdbc.pool.DataSourceProxy dataSource) { + DataSourceHandler handler = new DataSourceHandler(dataSource); + DataSource ds = (DataSource)Proxy.newProxyInstance(DataSourceFactory.class.getClassLoader(), new Class[] {javax.sql.DataSource.class}, handler); + return ds; + } + + /** + *

Parse properties from the string. Format of the string must be [propertyName=property;]*

+ * @param propText + * @return Properties + * @throws Exception + */ + static protected Properties getProperties(String propText) throws Exception { + Properties p = new Properties(); + if (propText != null) { + p.load(new ByteArrayInputStream(propText.replace(';', '\n'). + getBytes())); + } + return p; + } + + protected static class DataSourceHandler implements InvocationHandler { + protected org.apache.tomcat.jdbc.pool.DataSourceProxy datasource = null; + protected static HashMap methods = new HashMap(); + public DataSourceHandler(org.apache.tomcat.jdbc.pool.DataSourceProxy ds) { + this.datasource = ds; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + Method m = methods.get(method); + if (m==null) { + m = datasource.getClass().getMethod(method.getName(), method.getParameterTypes()); + methods.put(method, m); + } + return m.invoke(datasource, args); + } + + } +} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java new file mode 100644 index 000000000..878585c2f --- /dev/null +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java @@ -0,0 +1,304 @@ +/* + * 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.tomcat.jdbc.pool; + +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Iterator; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +/** + * + *

Title: Uber Pool

+ * + *

Description: A simple, yet efficient and powerful connection pool

+ * + *

Copyright: Copyright (c) 2008 Filip Hanik

+ * + *

+ * + * @author Filip Hanik + * @version 1.0 + */ + +public class DataSourceProxy { + protected static Log log = LogFactory.getLog(DataSourceProxy.class); + + protected Driver driver; + protected PoolProperties poolProperties = new PoolProperties(); + + public DataSourceProxy() { + } + + + public boolean isWrapperFor(Class iface) throws SQLException { + // we are not a wrapper of anything + return false; + } + + + public T unwrap(Class iface) throws SQLException { + //we can't unwrap anything + return null; + } + + /** + * {@inheritDoc} + */ + public Connection getConnection(String username, String password) throws SQLException { + return getConnection(); + } + + public PoolProperties getPoolProperties() { + return poolProperties; + } + + /** + * Sets up the connection pool, by creating a pooling driver. + * @return Driver + * @throws SQLException + */ + public synchronized Driver createDriver() throws SQLException { + if (driver != null) { + return driver; + } else { + driver = new org.apache.tomcat.jdbc.pool.Driver(getPoolProperties()); + return driver; + } + } + + /** + * {@inheritDoc} + */ + + public Connection getConnection() throws SQLException { + if (driver == null) + driver = createDriver(); + return driver.connect(poolProperties.getPoolName(), null); + } + + /** + * {@inheritDoc} + */ + public PooledConnection getPooledConnection() throws SQLException { + return (PooledConnection) getConnection(); + } + + /** + * {@inheritDoc} + */ + public PooledConnection getPooledConnection(String username, + String password) throws SQLException { + return (PooledConnection) getConnection(); + } + + /** + * {@inheritDoc} + */ + public PrintWriter getLogWriter() throws SQLException { + return null; + } + + /** + * {@inheritDoc} + */ + public void setLogWriter(PrintWriter out) throws SQLException { + } + + /** + * {@inheritDoc} + */ + public int getLoginTimeout() { + if (poolProperties == null) { + return 0; + } else { + return poolProperties.getMaxWait() / 1000; + } + } + + /** + * {@inheritDoc} + */ + public void setLoginTimeout(int i) { + if (poolProperties == null) { + return; + } else { + poolProperties.setMaxWait(1000 * i); + } + + } + + + public void close() { + close(false); + } + public void close(boolean all) { + try { + if (driver != null) { + Driver d = driver; + driver = null; + d.closePool(poolProperties.getPoolName(), all); + } + }catch (Exception x) { + x.printStackTrace(); + } + } + + protected void finalize() throws Throwable { + //terminate the pool? + close(true); + } + + public int getPoolSize() throws SQLException{ + if (driver == null) + driver = createDriver(); + return driver.getPool(getPoolProperties().getPoolName()).getSize(); + } + + public String toString() { + return super.toString()+"{"+getPoolProperties()+"}"; + } + +/*-----------------------------------------------------------------------*/ +// PROPERTIES WHEN NOT USED WITH FACTORY +/*------------------------------------------------------------------------*/ + public void setPoolProperties(PoolProperties poolProperties) { + this.poolProperties = poolProperties; + } + + public void setDriverClassName(String driverClassName) { + this.poolProperties.setDriverClassName(driverClassName); + } + + public void setInitialSize(int initialSize) { + this.poolProperties.setInitialSize(initialSize); + } + + public void setInitSQL(String initSQL) { + this.poolProperties.setInitSQL(initSQL); + } + + public void setLogAbandoned(boolean logAbandoned) { + this.poolProperties.setLogAbandoned(logAbandoned); + } + + public void setMaxActive(int maxActive) { + this.poolProperties.setMaxIdle(maxActive); + } + + public void setMaxIdle(int maxIdle) { + this.poolProperties.setMaxIdle(maxIdle); + } + + public void setMaxWait(int maxWait) { + this.poolProperties.setMaxWait(maxWait); + } + + public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { + this.poolProperties.setMinEvictableIdleTimeMillis( + minEvictableIdleTimeMillis); + } + + public void setMinIdle(int minIdle) { + this.setMinIdle(minIdle); + } + + public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { + this.poolProperties.setNumTestsPerEvictionRun(numTestsPerEvictionRun); + } + + public void setPassword(String password) { + this.poolProperties.setPassword(password); + this.poolProperties.getDbProperties().setProperty("password",this.poolProperties.getPassword()); + } + + public void setRemoveAbandoned(boolean removeAbandoned) { + this.poolProperties.setRemoveAbandoned(removeAbandoned); + } + + public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) { + this.poolProperties.setRemoveAbandonedTimeout(removeAbandonedTimeout); + } + + public void setTestOnBorrow(boolean testOnBorrow) { + this.poolProperties.setTestOnBorrow(testOnBorrow); + } + + public void setTestOnConnect(boolean testOnConnect) { + this.poolProperties.setTestOnConnect(testOnConnect); + } + + public void setTestOnReturn(boolean testOnReturn) { + this.poolProperties.setTestOnReturn(testOnReturn); + } + + public void setTestWhileIdle(boolean testWhileIdle) { + this.poolProperties.setTestWhileIdle(testWhileIdle); + } + + public void setTimeBetweenEvictionRunsMillis(int + timeBetweenEvictionRunsMillis) { + this.poolProperties.setTimeBetweenEvictionRunsMillis( + timeBetweenEvictionRunsMillis); + } + + public void setUrl(String url) { + this.poolProperties.setUrl(url); + } + + public void setUsername(String username) { + this.poolProperties.setUsername(username); + this.poolProperties.getDbProperties().setProperty("user",getPoolProperties().getUsername()); + } + + public void setValidationInterval(long validationInterval) { + this.poolProperties.setValidationInterval(validationInterval); + } + + public void setValidationQuery(String validationQuery) { + this.poolProperties.setValidationQuery(validationQuery); + } + + public void setJdbcInterceptors(String interceptors) { + this.getPoolProperties().setJdbcInterceptors(interceptors); + } + + public void setJmxEnabled(boolean enabled) { + this.getPoolProperties().setJmxEnabled(enabled); + } + + public void setConnectionProperties(String properties) { + try { + java.util.Properties prop = DataSourceFactory.getProperties(properties); + Iterator i = prop.keySet().iterator(); + while (i.hasNext()) { + String key = (String)i.next(); + String value = prop.getProperty(key); + getPoolProperties().getDbProperties().setProperty(key, value); + } + + }catch (Exception x) { + log.error("Unable to parse connection properties.", x); + throw new RuntimeException(x); + } + } + + +} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/Driver.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/Driver.java new file mode 100644 index 000000000..9e03825ba --- /dev/null +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/Driver.java @@ -0,0 +1,121 @@ +/* + * 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.tomcat.jdbc.pool; + + +import java.sql.Connection; +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Properties; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +/** + * @author Filip Hanik + * @version 1.0 + */ +public class Driver implements java.sql.Driver { + + protected static Log log = LogFactory.getLog(Driver.class); + + protected static HashMap pooltable = new HashMap(11); + + public Driver() throws SQLException { + } + + public Driver(PoolProperties properties) throws SQLException { + init(properties); + } //Driver + + public void init(PoolProperties properties) throws SQLException { + if (pooltable.get(properties.getPoolName()) != null) + throw new SQLException("Pool identified by:" + properties.getPoolName() + " already exists."); + ConnectionPool pool = new ConnectionPool(properties); + pooltable.put(properties.getPoolName(), pool); + } + + public void closePool(String url, boolean all) throws SQLException { + ConnectionPool pool = (ConnectionPool) pooltable.get(url); + if (pool == null) { + throw new SQLException("No connection pool established for URL:" + url); + } else { + pool.close(all); + } + pooltable.remove(url); + } + + /** + * {@inheritDoc} + */ + public Connection connect(String url, Properties info) throws SQLException { + ConnectionPool pool = (ConnectionPool) pooltable.get(url); + if (pool == null) { + throw new SQLException("No connection pool established for URL:" + url); + } else { + try { + return pool.getConnection(); + } catch (SQLException forward) { + throw forward; + } catch (Exception e) { + throw new SQLException("Unknow pool exception:" + ConnectionPool.getStackTrace(e)); + } //catch + } //end if + } //connect + + /** + * {@inheritDoc} + */ + public boolean acceptsURL(String url) throws SQLException { + /* check if the driver has a connection pool with that name */ + return (pooltable.get(url) != null ? true : false); + } //acceptsUrl + + /** + * {@inheritDoc} + */ + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws + SQLException { + return new DriverPropertyInfo[0]; + } //getPropertyInfo + + /** + * {@inheritDoc} + */ + public int getMajorVersion() { + return 1; + } + + /** + * {@inheritDoc} + */ + public int getMinorVersion() { + return 0; + } + + /** + * {@inheritDoc} + */ + public boolean jdbcCompliant() { + return true; + } + + public ConnectionPool getPool(String url) throws SQLException { + return (ConnectionPool) pooltable.get(url); + } + +} //class diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java new file mode 100644 index 000000000..67d1086b2 --- /dev/null +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java @@ -0,0 +1,51 @@ +/* + * 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.tomcat.jdbc.pool; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * @author Filip Hanik + * @version 1.0 + */ +public abstract class JdbcInterceptor implements InvocationHandler { + public static final String CLOSE_VAL = "close"; + + private JdbcInterceptor next = null; + + public JdbcInterceptor() { + } + + /** + * {@inheritDoc} + */ + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (getNext()!=null) return getNext().invoke(this,method,args); + else throw new NullPointerException(); + } + + public JdbcInterceptor getNext() { + return next; + } + + public void setNext(JdbcInterceptor next) { + this.next = next; + } + + public abstract void reset(ConnectionPool parent, PooledConnection con); +} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java new file mode 100644 index 000000000..6f94d3694 --- /dev/null +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java @@ -0,0 +1,388 @@ +/* + * 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.tomcat.jdbc.pool; + + +import java.lang.reflect.Method; +import java.util.Properties; +/** + * @author Filip Hanik + * + */ +public class PoolProperties { + protected static volatile int poolCounter = 1; + protected Properties dbProperties = new Properties(); + protected String url = null; + protected String driverClassName = null; + protected Boolean defaultAutoCommit = null; + protected Boolean defaultReadOnly = null; + protected int defaultTransactionIsolation = DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION; + protected String defaultCatalog = null; + protected String connectionProperties; + protected int initialSize = 10; + protected int maxActive = 100; + protected int maxIdle = maxActive; + protected int minIdle = initialSize; + protected int maxWait = 30000; + protected String validationQuery; + protected boolean testOnBorrow = false; + protected boolean testOnReturn = false; + protected boolean testWhileIdle = false; + protected int timeBetweenEvictionRunsMillis = 5000; + protected int numTestsPerEvictionRun; + protected int minEvictableIdleTimeMillis = 60000; + protected boolean accessToUnderlyingConnectionAllowed; + protected boolean removeAbandoned = false; + protected int removeAbandonedTimeout = 60; + protected boolean logAbandoned = false; + protected int loginTimeout = 10000; + protected String name = "Filip Connection Pool["+(poolCounter++)+"]"; + protected String password; + protected String username; + protected long validationInterval = 30000; + protected boolean jmxEnabled = true; + protected String initSQL; + protected boolean testOnConnect =false; + private String jdbcInterceptors=null; + + public boolean isAccessToUnderlyingConnectionAllowed() { + return accessToUnderlyingConnectionAllowed; + } + + public String getConnectionProperties() { + return connectionProperties; + } + + public Properties getDbProperties() { + return dbProperties; + } + + public boolean isDefaultAutoCommit() { + return defaultAutoCommit; + } + + public String getDefaultCatalog() { + return defaultCatalog; + } + + public boolean isDefaultReadOnly() { + return defaultReadOnly; + } + + public int getDefaultTransactionIsolation() { + return defaultTransactionIsolation; + } + + public String getDriverClassName() { + return driverClassName; + } + + public int getInitialSize() { + return initialSize; + } + + public boolean isLogAbandoned() { + return logAbandoned; + } + + public int getLoginTimeout() { + return loginTimeout; + } + + public int getMaxActive() { + return maxActive; + } + + public int getMaxIdle() { + return maxIdle; + } + + public int getMaxWait() { + return maxWait; + } + + public int getMinEvictableIdleTimeMillis() { + return minEvictableIdleTimeMillis; + } + + public int getMinIdle() { + return minIdle; + } + + public String getName() { + return name; + } + + public int getNumTestsPerEvictionRun() { + return numTestsPerEvictionRun; + } + + public String getPassword() { + return password; + } + + public String getPoolName() { + return getName(); + } + + public boolean isRemoveAbandoned() { + return removeAbandoned; + } + + public int getRemoveAbandonedTimeout() { + return removeAbandonedTimeout; + } + + public boolean isTestOnBorrow() { + return testOnBorrow; + } + + public boolean isTestOnReturn() { + return testOnReturn; + } + + public boolean isTestWhileIdle() { + return testWhileIdle; + } + + public int getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; + } + + public String getUrl() { + return url; + } + + public String getUsername() { + return username; + } + + public String getValidationQuery() { + return validationQuery; + } + + public long getValidationInterval() { + return validationInterval; + } + + public String getInitSQL() { + return initSQL; + } + + public boolean isTestOnConnect() { + return testOnConnect; + } + + public String getJdbcInterceptors() { + return jdbcInterceptors; + } + + public String[] getJdbcInterceptorsAsArray() { + if (jdbcInterceptors==null) return new String[0]; + else { + return jdbcInterceptors.split(";"); + } + } + + public void setAccessToUnderlyingConnectionAllowed(boolean + accessToUnderlyingConnectionAllowed) { + this.accessToUnderlyingConnectionAllowed = + accessToUnderlyingConnectionAllowed; + } + + public void setConnectionProperties(String connectionProperties) { + this.connectionProperties = connectionProperties; + } + + public void setDbProperties(Properties dbProperties) { + this.dbProperties = dbProperties; + } + + public void setDefaultAutoCommit(Boolean defaultAutoCommit) { + this.defaultAutoCommit = defaultAutoCommit; + } + + public void setDefaultCatalog(String defaultCatalog) { + this.defaultCatalog = defaultCatalog; + } + + public void setDefaultReadOnly(Boolean defaultReadOnly) { + this.defaultReadOnly = defaultReadOnly; + } + + public void setDefaultTransactionIsolation(int defaultTransactionIsolation) { + this.defaultTransactionIsolation = defaultTransactionIsolation; + } + + public void setDriverClassName(String driverClassName) { + this.driverClassName = driverClassName; + } + + public void setInitialSize(int initialSize) { + this.initialSize = initialSize; + } + + public void setLogAbandoned(boolean logAbandoned) { + this.logAbandoned = logAbandoned; + } + + public void setLoginTimeout(int loginTimeout) { + this.loginTimeout = loginTimeout; + } + + public void setMaxActive(int maxActive) { + this.maxActive = maxActive; + } + + public void setMaxIdle(int maxIdle) { + this.maxIdle = maxIdle; + } + + public void setMaxWait(int maxWait) { + this.maxWait = maxWait; + } + + public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + + public void setMinIdle(int minIdle) { + this.minIdle = minIdle; + } + + public void setName(String name) { + this.name = name; + } + + public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { + this.numTestsPerEvictionRun = numTestsPerEvictionRun; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setRemoveAbandoned(boolean removeAbandoned) { + this.removeAbandoned = removeAbandoned; + } + + public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) { + this.removeAbandonedTimeout = removeAbandonedTimeout; + } + + public void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + public void setTestWhileIdle(boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + + public void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + + public void setTimeBetweenEvictionRunsMillis(int + timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } + + public void setUrl(String url) { + this.url = url; + } + + public void setUsername(String username) { + this.username = username; + } + + public void setValidationInterval(long validationInterval) { + this.validationInterval = validationInterval; + } + + public void setValidationQuery(String validationQuery) { + this.validationQuery = validationQuery; + } + + public void setInitSQL(String initSQL) { + this.initSQL = initSQL; + } + + public void setTestOnConnect(boolean testOnConnect) { + this.testOnConnect = testOnConnect; + } + + public void setJdbcInterceptors(String jdbcInterceptors) { + this.jdbcInterceptors = jdbcInterceptors; + } + + public String toString() { + StringBuffer buf = new StringBuffer("ConnectionPool["); + try { + String[] fields = DataSourceFactory.ALL_PROPERTIES; + for (int i=0; i0; + result = result && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0); + result = result && (isTestWhileIdle() && getValidationQuery()!=null); + return result; + } +} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java new file mode 100644 index 000000000..79983912a --- /dev/null +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java @@ -0,0 +1,294 @@ +/* + * 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.tomcat.jdbc.pool; + + +import java.lang.ref.WeakReference; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Filip Hanik + * @version 1.0 + */ +public class PooledConnection { + + public static final int VALIDATE_BORROW = 1; + public static final int VALIDATE_RETURN = 2; + public static final int VALIDATE_IDLE = 3; + public static final int VALIDATE_INIT = 4; + + protected static Log log = LogFactory.getLog(PooledConnection.class); + protected static volatile int counter = 1; + + protected PoolProperties poolProperties; + protected java.sql.Connection connection; + protected String abandonTrace = null; + protected long timestamp; + protected ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false); + protected boolean discarded = false; + protected long lastValidated = System.currentTimeMillis(); + protected int instanceCount = 0; + protected ConnectionPool parent; + + protected WeakReference handler = null; + + public PooledConnection(PoolProperties prop, ConnectionPool parent) throws SQLException { + instanceCount = counter++; + poolProperties = prop; + this.parent = parent; + } + + protected void connect() throws SQLException { + if (connection != null) { + try { + this.disconnect(); + } catch (Exception x) { + log.error("Unable to disconnect previous connection.", x); + } //catch + } //end if + java.sql.Driver driver = null; + try { + driver = (java.sql.Driver) Class.forName(poolProperties.getDriverClassName(), + true, PooledConnection.class.getClassLoader()).newInstance(); + } catch (java.lang.Exception cn) { + log.error("Unable to instantiate JDBC driver.", cn); + throw new SQLException(cn.getMessage()); + } + String driverURL = poolProperties.getUrl(); + String usr = poolProperties.getUsername(); + String pwd = poolProperties.getPassword(); + poolProperties.getDbProperties().setProperty("user", usr); + poolProperties.getDbProperties().setProperty("password", pwd); + connection = driver.connect(driverURL, poolProperties.getDbProperties()); + //set up the default state + if (poolProperties.getDefaultReadOnly()!=null) connection.setReadOnly(poolProperties.getDefaultReadOnly().booleanValue()); + if (poolProperties.getDefaultAutoCommit()!=null) connection.setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue()); + if (poolProperties.getDefaultCatalog()!=null) connection.setCatalog(poolProperties.getDefaultCatalog()); + if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation()); + + this.discarded = false; + } + + protected void reconnect() throws SQLException { + this.disconnect(); + this.connect(); + } //reconnect + + protected synchronized void disconnect() throws SQLException { + if (isDiscarded()) { + return; + } + setDiscarded(true); + if (connection != null) { + connection.close(); + } + connection = null; + parent.finalize(this); + } + + +//============================================================================ +// com.filip.util.IPoolObject methods +//============================================================================ + + public long getAbandonTimeout() { + if (poolProperties.getRemoveAbandonedTimeout() <= 0) { + return Long.MAX_VALUE; + } else { + return poolProperties.getRemoveAbandonedTimeout()*1000; + } //end if + } + + public boolean abandon() { + try { + disconnect(); + } catch (SQLException x) { + log.error("", x); + } //catch + return false; + } + + protected boolean doValidate(int action) { + if (action == PooledConnection.VALIDATE_BORROW && + poolProperties.isTestOnBorrow()) + return true; + else if (action == PooledConnection.VALIDATE_RETURN && + poolProperties.isTestOnReturn()) + return true; + else if (action == PooledConnection.VALIDATE_IDLE && + poolProperties.isTestWhileIdle()) + return true; + else if (action == PooledConnection.VALIDATE_INIT && + poolProperties.isTestOnConnect()) + return true; + else if (action == PooledConnection.VALIDATE_INIT && + poolProperties.getInitSQL()!=null) + return true; + else + return false; + } + + /**Returns true if the object is still valid. if not + * the pool will call the getExpiredAction() and follow up with one + * of the four expired methods + */ + public boolean validate(int validateAction) { + return validate(validateAction,null); + } + + public boolean validate(int validateAction,String sql) { + if (!doValidate(validateAction)) { + //no validation required, no init sql and props not set + return true; + } + + String query = (VALIDATE_INIT==validateAction && (poolProperties.getInitSQL()!=null))?poolProperties.getInitSQL():sql; + + if (query==null) query = poolProperties.getValidationQuery(); + + if (query == null) { + //no validation possible + return true; + } + long now = System.currentTimeMillis(); + if (this.poolProperties.getValidationInterval() > 0 && + (now - this.lastValidated) < + this.poolProperties.getValidationInterval()) { + return true; + } + try { + Statement stmt = connection.createStatement(); + boolean exec = stmt.execute(query); + stmt.close(); + this.lastValidated = now; + return true; + } catch (Exception ignore) { + if (log.isDebugEnabled()) + log.debug("Unable to validate object:",ignore); + } + return false; + } //validate + + /** + * The time limit for how long the object + * can remain unused before it is released + */ + public long getReleaseTime() { + return this.poolProperties.getMinEvictableIdleTimeMillis(); + } + + /** + * This method is called if (Now - timeCheckedIn > getReleaseTime()) + */ + public void release() { + try { + disconnect(); + } catch (SQLException x) { + //TODO + } + + } + + /** + * The pool will set the stack trace when it is check out and + * checked in + */ + + public void setStackTrace(String trace) { + abandonTrace = trace; + } + + public String getStackTrace() { + return abandonTrace; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public void setDiscarded(boolean discarded) { + if (this.discarded && !discarded) throw new IllegalStateException("Unable to change the state once the connection has been discarded"); + this.discarded = discarded; + } + + public void setLastValidated(long lastValidated) { + this.lastValidated = lastValidated; + } + + public void setPoolProperties(PoolProperties poolProperties) { + this.poolProperties = poolProperties; + } + + public long getTimestamp() { + return timestamp; + } + + public boolean isDiscarded() { + return discarded; + } + + public long getLastValidated() { + return lastValidated; + } + + public PoolProperties getPoolProperties() { + return poolProperties; + } + + public void lock() { + if (this.poolProperties.isPoolSweeperEnabled()) { + //optimized, only use a lock when there is concurrency + lock.writeLock().lock(); + } + } + + public void unlock() { + if (this.poolProperties.isPoolSweeperEnabled()) { + //optimized, only use a lock when there is concurrency + lock.writeLock().unlock(); + } + } + + public java.sql.Connection getConnection() { + return this.connection; + } + + public JdbcInterceptor getHandler() { + return (handler!=null)?handler.get():null; + } + + public void setHandler(JdbcInterceptor handler) { + if (handler==null) { + if (this.handler!=null) this.handler.clear(); + } else if (this.handler==null) { + this.handler = new WeakReference(handler); + } else if (this.handler.get()==null) { + this.handler.clear(); + this.handler = new WeakReference(handler); + } else if (this.handler.get()!=handler) { + this.handler.clear(); + this.handler = new WeakReference(handler); + } + } + +} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java new file mode 100644 index 000000000..9a66536bb --- /dev/null +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java @@ -0,0 +1,93 @@ +/* + * 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.tomcat.jdbc.pool; + +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.SQLException; +/** + * @author Filip Hanik + */ +public class ProxyConnection extends JdbcInterceptor { + + protected PooledConnection connection = null; + + protected ConnectionPool pool = null; + + public PooledConnection getConnection() { + return connection; + } + + public void setConnection(PooledConnection connection) { + this.connection = connection; + } + + public ConnectionPool getPool() { + return pool; + } + + public void setPool(ConnectionPool pool) { + this.pool = pool; + } + + protected ProxyConnection(ConnectionPool parent, PooledConnection con) throws SQLException { + pool = parent; + connection = con; + } + + public void reset(ConnectionPool parent, PooledConnection con) { + this.pool = parent; + this.connection = con; + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return (iface.isInstance(connection.getConnection())); + } + + + public Object unwrap(Class iface) throws SQLException { + if (isWrapperFor(iface)) { + return connection.getConnection(); + } else { + throw new SQLException("Not a wrapper of "+iface.getName()); + } + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (isClosed()) throw new SQLException("Connection has already been closed."); + if (CLOSE_VAL==method.getName()) { + PooledConnection poolc = this.connection; + this.connection = null; + pool.returnConnection(poolc); + return null; + } + return method.invoke(connection.getConnection(),args); + } + + public boolean isClosed() { + return connection==null || connection.isDiscarded(); + } + + public PooledConnection getDelegateConnection() { + return connection; + } + + public ConnectionPool getParentPool() { + return pool; + } + +} diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java new file mode 100644 index 000000000..b30ae01fd --- /dev/null +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java @@ -0,0 +1,84 @@ +/* + * 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.tomcat.jdbc.pool.interceptor; + +import java.lang.reflect.Method; + +import org.apache.tomcat.jdbc.pool.ConnectionPool; +import org.apache.tomcat.jdbc.pool.DataSourceFactory; +import org.apache.tomcat.jdbc.pool.JdbcInterceptor; +import org.apache.tomcat.jdbc.pool.PooledConnection; + +/** + * Interceptor that keep track of connection state to avoid roundtrips to the database + * @author fhanik + * + */ + +public class ConnectionState extends JdbcInterceptor { + + protected final String[] readState = {"getAutoCommit","getTransactionIsolation","isReadOnly"}; + protected final String[] writeState = {"setAutoCommit","setTransactionIsolation","setReadOnly"}; + + protected Boolean autoCommit = null; + protected Integer transactionIsolation = null; + protected Boolean readOnly = null; + + public void reset(ConnectionPool parent, PooledConnection con) { + autoCommit = null; + transactionIsolation = null; + readOnly = null; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String name = method.getName(); + boolean read = false; + int index = -1; + for (int i=0; (!read) && i10) { + StringBuffer out = new StringBuffer("\n\tType:"); + out.append(parent.getClass().getName()); + out.append("\n\tCreate/Prepare args:"); + for (int i=0; this.args!=null && i