tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fha...@apache.org
Subject svn commit: r707275 [1/2] - in /tomcat/trunk: ./ java/org/apache/tomcat/jdbc/ java/org/apache/tomcat/jdbc/pool/ java/org/apache/tomcat/jdbc/pool/interceptor/ java/org/apache/tomcat/jdbc/pool/jmx/ test/org/apache/tomcat/ test/org/apache/tomcat/jdbc/ tes...
Date Thu, 23 Oct 2008 05:14:51 GMT
Author: fhanik
Date: Wed Oct 22 22:14:50 2008
New Revision: 707275

URL: http://svn.apache.org/viewvc?rev=707275&view=rev
Log:
simple connection pool contribution - currently built using
ant -f extras.xml conpool
until we have a way to release it as a module, coming soon

Added:
    tomcat/trunk/java/org/apache/tomcat/jdbc/
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSource.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/Driver.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
    tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java
    tomcat/trunk/test/org/apache/tomcat/
    tomcat/trunk/test/org/apache/tomcat/jdbc/
    tomcat/trunk/test/org/apache/tomcat/jdbc/test/
    tomcat/trunk/test/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java
    tomcat/trunk/test/org/apache/tomcat/jdbc/test/DefaultProperties.java
    tomcat/trunk/test/org/apache/tomcat/jdbc/test/DefaultTestCase.java
    tomcat/trunk/test/org/apache/tomcat/jdbc/test/TestGCClose.java
    tomcat/trunk/test/org/apache/tomcat/jdbc/test/TestTimeout.java
    tomcat/trunk/webapps/docs/config/jdbc-pool.xml
Modified:
    tomcat/trunk/build.xml
    tomcat/trunk/extras.xml

Modified: tomcat/trunk/build.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/build.xml?rev=707275&r1=707274&r2=707275&view=diff
==============================================================================
--- tomcat/trunk/build.xml (original)
+++ tomcat/trunk/build.xml Wed Oct 22 22:14:50 2008
@@ -121,6 +121,7 @@
       <exclude name="org/apache/naming/factory/webservices/**" />
       <exclude name="org/apache/tomcat/bayeux/**" />
       <exclude name="org/apache/cometd/**" />
+      <exclude name="org/apache/tomcat/jdbc/**" />
     </javac>
     <tstamp>
       <format property="TODAY" pattern="MMM d yyyy" locale="en"/>

Modified: tomcat/trunk/extras.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/extras.xml?rev=707275&r1=707274&r2=707275&view=diff
==============================================================================
--- tomcat/trunk/extras.xml (original)
+++ tomcat/trunk/extras.xml Wed Oct 22 22:14:50 2008
@@ -82,6 +82,8 @@
   <property name="cometd.war" value="${tomcat.extras}/cometd.war"/>
   <property name="tomcat-bayeux-samples.jar" value="${tomcat.extras}/tomcat-bayeux-samples.jar"/>
 
+  <property name="tomcat-jdbc.jar" value="${tomcat.extras}/tomcat-jdbc.jar"/>
+
   <property name="catalina-jmx-remote.jar" value="${tomcat.extras}/catalina-jmx-remote.jar"/>
 	
   <!-- Classpath -->
@@ -331,6 +333,33 @@
     </echo>
   </target>
 
+  <target name="conpool">
+    <mkdir dir="${tomcat.extras}"/>
+    <path id="tomcat.jdbc.classpath">
+      <pathelement path="${tomcat.classpath}"/>
+    </path>
+
+    <!-- compile org.apache.tomcat.jdbc-->
+    <javac srcdir="java" destdir="${tomcat.classes}"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           optimize="${compile.optimize}">
+      <classpath refid="tomcat.jdbc.classpath"/>
+      <include name="org/apache/tomcat/jdbc/**" />
+    </javac>
+    
+    <!-- Cometd API JAR File -->
+    <jar jarfile="${tomcat-jdbc.jar}">
+      <fileset dir="${tomcat.classes}">
+        <include name="org/apache/tomcat/jdbc/**" />
+      </fileset>
+    </jar>
+    <!-- create checksums -->
+    <checksum file="${tomcat-jdbc.jar}" forceOverwrite="yes" fileext=".md5" />
+  </target>
+
+
   <target name="jmx-remote" >
     <!-- Create the JAR file -->
     <jar jarfile="${catalina-jmx-remote.jar}">

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java Wed Oct 22 22:14:50 2008
@@ -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<PooledConnection> busy;
+
+    /**
+     * Contains all the idle connections
+     */
+    protected BlockingQueue<PooledConnection> 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<PooledConnection> 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<PooledConnection>(properties.getMaxActive(),false);
+        //make space for 10 extra in case we flow over a bit
+        idle = new ArrayBlockingQueue<PooledConnection>(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.getInitialSize()) {
+            log.warn("initialSize is larger than maxActive, setting initialSize to: "+properties.getMaxActive());
+            properties.setInitialSize(properties.getMaxActive());
+        }
+        if (properties.getMinIdle()>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()<properties.getMinIdle()) {
+            log.warn("maxIdle is smaller than minIdle, setting maxIdle to: "+properties.getMinIdle());
+            properties.setMaxIdle(properties.getMinIdle());
+        }
+
+
+        //initialize the pool with its initial set of members
+        PooledConnection[] initialPool = new PooledConnection[poolProperties.getInitialSize()];
+        try {
+            for (int i = 0; i < initialPool.length; i++) {
+                initialPool[i] = this.borrowConnection();
+            } //for
+
+        } catch (SQLException x) {
+            close(true);
+            throw x;
+        } finally {
+            //return the members as idle to the pool
+            for (int i = 0; i < initialPool.length; i++) {
+                if (initialPool[i] != null) {
+                    try {this.returnConnection(initialPool[i]);}catch(Exception x){}
+                } //end if
+            } //for
+        } //catch
+        if (this.getPoolProperties().isJmxEnabled()) startJmx();
+        closed = false;
+    }
+
+
+//===============================================================================
+//         CONNECTION POOLING IMPL
+//===============================================================================
+
+    /**
+     * thread safe way to abandon a connection
+     * signals a connection to be abandoned.
+     * this will disconnect the connection, and log the stack trace if logAbanded=true
+     * @param con PooledConnection
+     */
+    protected void abandon(PooledConnection con) {
+        if (con == null)
+            return;
+        try {
+            con.lock();
+            if (getPoolProperties().isLogAbandoned()) {
+                log.warn("Connection has been abandoned" + con + ":" +con.getStackTrace());
+            }
+            con.abandon();
+        } finally {
+            con.unlock();
+        }
+    }
+
+    /**
+     * thread safe way to release a connection
+     * @param con PooledConnection
+     */
+    protected void release(PooledConnection con) {
+        if (con == null)
+            return;
+        try {
+            con.lock();
+            con.release();
+        } finally {
+            con.unlock();
+        }
+    }
+
+    /**
+     * Thread safe way to retrieve a connection from the pool
+     * @return PooledConnection
+     * @throws SQLException
+     */
+    protected PooledConnection borrowConnection() throws SQLException {
+
+        if (isClosed()) {
+            throw new SQLException("Connection pool closed.");
+        } //end if
+
+        //get the current time stamp
+        long now = System.currentTimeMillis();
+        //see if there is one available immediately
+        PooledConnection con = idle.poll();
+
+        while (true) {
+            if (con!=null) {
+                PooledConnection result = borrowConnection(now, con);
+                //validation might have failed, in which case null is returned
+                if (result!=null) return result;
+            }
+            if (size.get() < getPoolProperties().getMaxActive()) {
+                if (size.addAndGet(1) <= getPoolProperties().getMaxActive()) {
+                    return createConnection(now, con);
+                } else {
+                    size.addAndGet(-1); //restore the value, we didn't create a connection
+                }
+            } //end if
+
+            //calculate wait time for this iteration
+            long maxWait = (getPoolProperties().getMaxWait()<=0)?Long.MAX_VALUE:getPoolProperties().getMaxWait();
+            long timetowait = Math.max(1, maxWait - (System.currentTimeMillis() - now));
+            try {
+                //retrieve an existing connection
+                con = idle.poll(timetowait, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException ex) {
+                Thread.currentThread().interrupted();
+            }
+            //we didn't get a connection, lets see if we timed out
+            if (con == null) {
+                if ((System.currentTimeMillis() - now) >= 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<PooledConnection> 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<PooledConnection> 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<PooledConnection> 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()<pool.idle.size())
+                            pool.checkIdle();
+                        if (pool.getPoolProperties().isTestWhileIdle())
+                            pool.testAllIdle();
+                    } catch (Exception x) {
+                        pool.log.error("", x);
+                    } //catch
+                } //end if
+            } //while
+        } //run
+
+        public void stopRunning() {
+            run = false;
+            interrupt();
+        }
+    }
+}

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSource.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSource.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSource.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSource.java Wed Oct 22 22:14:50 2008
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+
+/**
+ * A DataSource that can be instantiated through IoC and implements the DataSource interface
+ * since the DataSourceProxy is used as a generic proxy
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class DataSource extends DataSourceProxy implements javax.sql.DataSource {
+
+}

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java Wed Oct 22 22:14:50 2008
@@ -0,0 +1,427 @@
+/*
+ * 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.ByteArrayInputStream;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.Connection;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+import javax.sql.DataSource;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * <p>JNDI object factory that creates an instance of
+ * <code>BasicDataSource</code> that has been configured based on the
+ * <code>RefAddr</code> values of the specified <code>Reference</code>,
+ * which must match the names and data types of the
+ * <code>BasicDataSource</code> bean properties.</p>
+ * <br/>
+ * Properties available for configuration:<br/>
+ * <a href="http://commons.apache.org/dbcp/configuration.html">Commons DBCP properties</a><br/>
+ *<ol>
+ *  <li>initSQL - A query that gets executed once, right after the connection is established.</li>
+ *  <li>testOnConnect - run validationQuery after connection has been established.</li>
+ *  <li>validationInterval - avoid excess validation, only run validation at most at this frequency - time in milliseconds.</li>
+ *  <li>jdbcInterceptors - a semicolon separated list of classnames extending {@link JdbcInterceptor} class.</li>
+ *  <li>jmxEnabled - true of false, whether to register the pool with JMX.</li>
+ *</ol>
+ * @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
+
+    /**
+     * <p>Create and return a new <code>BasicDataSource</code> instance.  If no
+     * instance can be created, return <code>null</code> instead.</p>
+     *
+     * @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 <code>nameCtx</code>
+     * @param nameCtx The context relative to which the <code>name</code>
+     *  parameter is specified, or <code>null</code> if <code>name</code>
+     *  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 <code>javax.naming.Reference</code>s
+        // 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;
+    }
+
+    /**
+     * <p>Parse properties from the string. Format of the string must be [propertyName=property;]*<p>
+     * @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<Method,Method> methods = new HashMap<Method,Method>();
+        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);
+        }
+
+    }
+}

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java Wed Oct 22 22:14:50 2008
@@ -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;
+
+/**
+ *
+ * <p>Title: Uber Pool</p>
+ *
+ * <p>Description: A simple, yet efficient and powerful connection pool</p>
+ *
+ * <p>Copyright: Copyright (c) 2008 Filip Hanik</p>
+ *
+ * <p> </p>
+ *
+ * @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> T unwrap(Class<T> 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);
+        }
+    }
+
+
+}

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/Driver.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/Driver.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/Driver.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/Driver.java Wed Oct 22 22:14:50 2008
@@ -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

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/JdbcInterceptor.java Wed Oct 22 22:14:50 2008
@@ -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);
+}

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/PoolProperties.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/PoolProperties.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/PoolProperties.java Wed Oct 22 22:14:50 2008
@@ -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; i<fields.length; i++) {
+                final String[] prefix = new String[] {"get","is"};
+                for (int j=0; j<prefix.length; j++) {
+
+                    String name = prefix[j] + fields[i].substring(0, 1).toUpperCase() +
+                                  fields[i].substring(1);
+                    Method m = null;
+                    try {
+                        m = getClass().getMethod(name);
+                    }catch (NoSuchMethodException nm) {
+                        continue;
+                    }
+                    buf.append(fields[i]);
+                    buf.append("=");
+                    buf.append(m.invoke(this, new Object[0]));
+                    buf.append("; ");
+                    break;
+                }
+            }
+        }catch (Exception x) {
+            //shouldn;t happen
+            x.printStackTrace();
+        }
+        return buf.toString();
+    }
+
+    public static int getPoolCounter() {
+        return poolCounter;
+    }
+
+    public boolean isJmxEnabled() {
+        return jmxEnabled;
+    }
+
+    public void setJmxEnabled(boolean jmxEnabled) {
+        this.jmxEnabled = jmxEnabled;
+    }
+
+    public Boolean getDefaultAutoCommit() {
+        return defaultAutoCommit;
+    }
+
+    public Boolean getDefaultReadOnly() {
+        return defaultReadOnly;
+    }
+    
+    public boolean isPoolSweeperEnabled() {
+        boolean result = getTimeBetweenEvictionRunsMillis()>0;
+        result = result && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0);
+        result = result && (isTestWhileIdle() && getValidationQuery()!=null);
+        return result;
+    }
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Mime
View raw message