tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fha...@apache.org
Subject svn commit: r707275 [2/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
Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/PooledConnection.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/PooledConnection.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/PooledConnection.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/PooledConnection.java Wed Oct 22 22:14:50 2008
@@ -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<JdbcInterceptor> 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<JdbcInterceptor>(handler);
+        } else if (this.handler.get()==null) {
+            this.handler.clear();
+            this.handler = new WeakReference<JdbcInterceptor>(handler);
+        } else if (this.handler.get()!=handler) {
+            this.handler.clear();
+            this.handler = new WeakReference<JdbcInterceptor>(handler);
+        }
+    }
+
+}

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

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/ConnectionState.java Wed Oct 22 22:14:50 2008
@@ -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) && i<readState.length; i++) {
+            read = name==readState[i];
+            if (read) index = i;
+        }
+        boolean write = false;
+        for (int i=0; (!write) && (!read) && i<writeState.length; i++) {
+            write = name==writeState[i];
+            if (write) index = i;
+        }
+        Object result = null;
+        if (read) {
+            switch (index) {
+                case 0:{result = autoCommit; break;}
+                case 1:{result = transactionIsolation; break;}
+                case 2:{result = readOnly; break;}
+                default: result = null;
+            }
+            //return cached result, if we have it
+            if (result!=null) return result;
+        }
+
+        result = super.invoke(proxy, method, args);
+        if (read || write) {
+            switch (index) {
+                case 0:{autoCommit = (Boolean) (read?result:args[0]); break;}
+                case 1:{transactionIsolation = (Integer)(read?result:args[0]); break;}
+                case 2:{readOnly = (Boolean)(read?result:args[0]); break;}
+            }
+        }
+        return result;
+    }
+
+}

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReport.java Wed Oct 22 22:14:50 2008
@@ -0,0 +1,107 @@
+/*
+ * 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.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.CallableStatement;
+import java.sql.SQLException;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+import org.apache.tomcat.jdbc.pool.PooledConnection;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class SlowQueryReport extends JdbcInterceptor {
+    protected final String[] statements = {"createStatement","prepareStatement","prepareCall"};
+    protected final String[] executes = {"execute","executeQuery","executeUpdate","executeBatch"};
+
+    public SlowQueryReport() {
+        super();
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        boolean process = false;
+        process = process(statements, method, process);
+        if (process) {
+            Object statement = super.invoke(proxy,method,args);
+            CallableStatement measuredStatement =
+                (CallableStatement)Proxy.newProxyInstance(SlowQueryReport.class.getClassLoader(),
+                    new Class[] {java.sql.CallableStatement.class,
+                                 java.sql.PreparedStatement.class,
+                                 java.sql.Statement.class},
+                    new StatementProxy(statement, args));
+
+            return measuredStatement;
+        } else {
+            return super.invoke(proxy,method,args);
+        }
+    }
+
+    protected boolean process(String[] names, Method method, boolean process) {
+        for (int i=0; (!process) && i<names.length; i++) {
+            process = (method.getName()==names[i]);
+        }
+        return process;
+    }
+
+    protected class StatementProxy implements InvocationHandler {
+        protected Object parent;
+        protected Object[] args;
+        public StatementProxy(Object parent, Object[] args) {
+            this.parent = parent;
+            this.args = args;
+        }
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if (this.parent == null ) throw new SQLException("Statement has been closed.");
+            boolean process = false;
+            process = process(executes, method, process);
+            long start = (process)?System.currentTimeMillis():0;
+            //execute the query
+            Object result =  method.invoke(parent,args);
+            long delta = (process)?(System.currentTimeMillis()-start):0;
+            if (delta>10) {
+                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<this.args.length;i++) {
+                    out.append(this.args[i]!=null?this.args[i]:"null");
+                    out.append("; ");
+                }
+                out.append("\n\tExecute args:");
+                for (int i=0; args!=null && i<args.length;i++) {
+                    out.append(args[i]!=null?args[i]:"null");
+                    out.append("; ");
+                }
+                System.out.println("Slow query:"+out+"\nTime to execute:"+(delta)+" ms.");
+            }
+            if (JdbcInterceptor.CLOSE_VAL==method.getName()) {
+                this.parent = null;
+                this.args = null;
+            }
+            return result;
+        }
+    }
+
+    public void reset(ConnectionPool parent, PooledConnection con) {
+
+    }
+}

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java Wed Oct 22 22:14:50 2008
@@ -0,0 +1,171 @@
+/* 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.jmx;
+/**
+ * @author Filip Hanik
+ */
+import java.util.Properties;
+
+import javax.management.DynamicMBean;
+
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+
+public class ConnectionPool implements ConnectionPoolMBean  {
+    protected org.apache.tomcat.jdbc.pool.ConnectionPool pool = null;
+
+    public ConnectionPool(org.apache.tomcat.jdbc.pool.ConnectionPool pool) {
+        this.pool = pool;
+    }
+
+    public org.apache.tomcat.jdbc.pool.ConnectionPool getPool() {
+        return pool;
+    }
+
+    //=================================================================
+    //       POOL STATS
+    //=================================================================
+
+    public int getSize() {
+        return pool.getSize();
+    }
+
+    public int getIdle() {
+        return pool.getIdle();
+    }
+
+    public int getActive() {
+        return pool.getActive();
+    }
+    
+    public boolean isPoolSweeperEnabled() {
+        return pool.getPoolProperties().isPoolSweeperEnabled();
+    }
+
+    //=================================================================
+    //       POOL OPERATIONS
+    //=================================================================
+    public void checkIdle() {
+        pool.checkIdle();
+    }
+
+    public void checkAbandoned() {
+        pool.checkAbandoned();
+    }
+
+    public void testIdle() {
+        pool.testAllIdle();
+    }
+    //=================================================================
+    //       POOL PROPERTIES
+    //=================================================================
+    public Properties getDbProperties() {
+        return pool.getPoolProperties().getDbProperties();
+    }
+    public String getUrl() {
+        return pool.getPoolProperties().getUrl();
+    }
+    public String getDriverClassName() {
+        return pool.getPoolProperties().getDriverClassName();
+    }
+    public boolean isDefaultAutoCommit() {
+        return pool.getPoolProperties().isDefaultAutoCommit();
+    }
+    public boolean isDefaultReadOnly() {
+        return pool.getPoolProperties().isDefaultReadOnly();
+    }
+    public int getDefaultTransactionIsolation() {
+        return pool.getPoolProperties().getDefaultTransactionIsolation();
+    }
+    public String getConnectionProperties() {
+        return pool.getPoolProperties().getConnectionProperties();
+    }
+    public String getDefaultCatalog() {
+        return pool.getPoolProperties().getDefaultCatalog();
+    }
+    public int getInitialSize() {
+        return pool.getPoolProperties().getInitialSize();
+    }
+    public int getMaxActive() {
+        return pool.getPoolProperties().getMaxActive();
+    }
+    public int getMaxIdle() {
+        return pool.getPoolProperties().getMaxIdle();
+    }
+    public int getMinIdle() {
+        return pool.getPoolProperties().getMinIdle();
+    }
+    public int getMaxWait() {
+        return pool.getPoolProperties().getMaxWait();
+    }
+    public String getValidationQuery() {
+        return pool.getPoolProperties().getValidationQuery();
+    }
+    public boolean isTestOnBorrow() {
+        return pool.getPoolProperties().isTestOnBorrow();
+    }
+    public boolean isTestOnReturn() {
+        return pool.getPoolProperties().isTestOnReturn();
+    }
+    public boolean isTestWhileIdle() {
+        return pool.getPoolProperties().isTestWhileIdle();
+    }
+    public int getTimeBetweenEvictionRunsMillis() {
+        return pool.getPoolProperties().getTimeBetweenEvictionRunsMillis();
+    }
+    public int getNumTestsPerEvictionRun() {
+        return pool.getPoolProperties().getNumTestsPerEvictionRun();
+    }
+    public int getMinEvictableIdleTimeMillis() {
+        return pool.getPoolProperties().getMinEvictableIdleTimeMillis();
+    }
+    public boolean isAccessToUnderlyingConnectionAllowed() {
+        return pool.getPoolProperties().isAccessToUnderlyingConnectionAllowed();
+    }
+    public boolean isRemoveAbandoned() {
+        return pool.getPoolProperties().isRemoveAbandoned();
+    }
+    public int getRemoveAbandonedTimeout() {
+        return pool.getPoolProperties().getRemoveAbandonedTimeout();
+    }
+    public boolean isLogAbandoned() {
+        return pool.getPoolProperties().isLogAbandoned();
+    }
+    public int getLoginTimeout() {
+        return pool.getPoolProperties().getLoginTimeout();
+    }
+    public String getName() {
+        return pool.getPoolProperties().getName();
+    }
+    public String getPassword() {
+        return pool.getPoolProperties().getPassword();
+    }
+    public String getUsername() {
+        return pool.getPoolProperties().getUsername();
+    }
+    public long getValidationInterval() {
+        return pool.getPoolProperties().getValidationInterval();
+    }
+    public String getInitSQL() {
+        return pool.getPoolProperties().getInitSQL();
+    }
+    public boolean isTestOnConnect() {
+        return pool.getPoolProperties().isTestOnConnect();
+    }
+    public String getJdbcInterceptors() {
+        return pool.getPoolProperties().getJdbcInterceptors();
+    }
+
+}

Added: tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java Wed Oct 22 22:14:50 2008
@@ -0,0 +1,115 @@
+/* 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.jmx;
+
+import java.util.Properties;
+
+import javax.management.DynamicMBean;
+
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.JdbcInterceptor;
+
+public interface ConnectionPoolMBean  {
+
+    //=================================================================
+    //       POOL STATS
+    //=================================================================
+
+    public int getSize();
+
+    public int getIdle();
+
+    public int getActive();
+    
+    public boolean isPoolSweeperEnabled();
+
+    //=================================================================
+    //       POOL OPERATIONS
+    //=================================================================
+    public void checkIdle();
+
+    public void checkAbandoned();
+
+    public void testIdle();
+
+    //=================================================================
+    //       POOL PROPERTIES
+    //=================================================================
+    public Properties getDbProperties();
+
+    public String getUrl();
+
+    public String getDriverClassName();
+
+    public boolean isDefaultAutoCommit();
+
+    public boolean isDefaultReadOnly();
+
+    public int getDefaultTransactionIsolation();
+
+    public String getConnectionProperties();
+
+    public String getDefaultCatalog();
+
+    public int getInitialSize();
+
+    public int getMaxActive();
+
+    public int getMaxIdle();
+
+    public int getMinIdle();
+
+    public int getMaxWait();
+
+    public String getValidationQuery();
+
+    public boolean isTestOnBorrow();
+
+    public boolean isTestOnReturn();
+
+    public boolean isTestWhileIdle();
+
+    public int getTimeBetweenEvictionRunsMillis();
+
+    public int getNumTestsPerEvictionRun();
+
+    public int getMinEvictableIdleTimeMillis();
+
+    public boolean isAccessToUnderlyingConnectionAllowed();
+
+    public boolean isRemoveAbandoned();
+
+    public int getRemoveAbandonedTimeout();
+
+    public boolean isLogAbandoned();
+
+    public int getLoginTimeout();
+
+    public String getName();
+
+    public String getPassword();
+
+    public String getUsername();
+
+    public long getValidationInterval();
+
+    public String getInitSQL();
+
+    public boolean isTestOnConnect();
+
+    public String getJdbcInterceptors();
+
+}

Added: tomcat/trunk/test/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java (added)
+++ tomcat/trunk/test/org/apache/tomcat/jdbc/test/CheckOutThreadTest.java Wed Oct 22 22:14:50 2008
@@ -0,0 +1,254 @@
+/*
+ * 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.test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.sql.Connection;
+import java.sql.Statement;
+import java.sql.ResultSet;
+
+import javax.sql.DataSource;
+
+import org.apache.tomcat.jdbc.pool.DataSourceFactory;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class CheckOutThreadTest extends DefaultTestCase {
+    public CheckOutThreadTest(String name) {
+        super(name);
+    }
+
+    CountDownLatch latch = null;
+
+    public void testDBCPThreads10Connections10() throws Exception {
+        init();
+        this.datasource.getPoolProperties().setMaxActive(10);
+        this.threadcount = 10;
+        this.transferProperties();
+        this.tDatasource.getConnection().close();
+        latch = new CountDownLatch(threadcount);
+        long start = System.currentTimeMillis();
+        for (int i=0; i<threadcount; i++) {
+            TestThread t = new TestThread();
+            t.setName("tomcat-dbcp-"+i);
+            t.d = this.tDatasource;
+            t.start();
+        }
+        latch.await();
+        long delta = System.currentTimeMillis() - start;
+        System.out.println("[testDBCPThreads10Connections10]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+        tearDown();
+    }
+
+    public void testPoolThreads10Connections10() throws Exception {
+        init();
+        this.datasource.getPoolProperties().setMaxActive(10);
+        this.threadcount = 10;
+        this.transferProperties();
+        this.datasource.getConnection().close();
+        latch = new CountDownLatch(threadcount);
+        long start = System.currentTimeMillis();
+        for (int i=0; i<threadcount; i++) {
+            TestThread t = new TestThread();
+            t.setName("tomcat-pool-"+i);
+            t.d = DataSourceFactory.getDataSource(this.datasource);
+            t.start();
+        }
+        latch.await();
+        long delta = System.currentTimeMillis() - start;
+        System.out.println("[testPoolThreads10Connections10]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+        tearDown();
+    }
+
+    public void testDBCPThreads20Connections10() throws Exception {
+        init();
+        this.datasource.getPoolProperties().setMaxActive(10);
+        this.threadcount = 20;
+        this.transferProperties();
+        this.tDatasource.getConnection().close();
+        latch = new CountDownLatch(threadcount);
+        long start = System.currentTimeMillis();
+        for (int i=0; i<threadcount; i++) {
+            TestThread t = new TestThread();
+            t.setName("tomcat-dbcp-"+i);
+            t.d = this.tDatasource;
+            t.start();
+        }
+        latch.await();
+        long delta = System.currentTimeMillis() - start;
+        System.out.println("[testDBCPThreads20Connections10]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+        tearDown();
+    }
+
+    public void testPoolThreads20Connections10() throws Exception {
+        init();
+        this.datasource.getPoolProperties().setMaxActive(10);
+        this.threadcount = 20;
+        this.transferProperties();
+        this.datasource.getConnection().close();
+        latch = new CountDownLatch(threadcount);
+        long start = System.currentTimeMillis();
+        for (int i=0; i<threadcount; i++) {
+            TestThread t = new TestThread();
+            t.setName("tomcat-pool-"+i);
+            t.d = DataSourceFactory.getDataSource(this.datasource);
+            t.start();
+        }
+        latch.await();
+        long delta = System.currentTimeMillis() - start;
+        System.out.println("[testPoolThreads20Connections10]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+        tearDown();
+    }
+
+
+    
+    public void testDBCPThreads10Connections10Validate() throws Exception {
+        init();
+        this.datasource.getPoolProperties().setMaxActive(10);
+        this.datasource.getPoolProperties().setValidationQuery("SELECT 1");
+        this.datasource.getPoolProperties().setTestOnBorrow(true);
+        this.threadcount = 10;
+        this.transferProperties();
+        this.tDatasource.getConnection().close();
+        latch = new CountDownLatch(threadcount);
+        long start = System.currentTimeMillis();
+        for (int i=0; i<threadcount; i++) {
+            TestThread t = new TestThread();
+            t.setName("tomcat-dbcp-validate-"+i);
+            t.d = this.tDatasource;
+            t.start();
+        }
+        latch.await();
+        long delta = System.currentTimeMillis() - start;
+        System.out.println("[testDBCPThreads10Connections10Validate]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+        tearDown();
+    }
+
+    public void testPoolThreads10Connections10Validate() throws Exception {
+        init();
+        this.datasource.getPoolProperties().setMaxActive(10);
+        this.datasource.getPoolProperties().setValidationQuery("SELECT 1");
+        this.datasource.getPoolProperties().setTestOnBorrow(true);
+        this.threadcount = 10;
+        this.transferProperties();
+        this.datasource.getConnection().close();
+        latch = new CountDownLatch(threadcount);
+        long start = System.currentTimeMillis();
+        for (int i=0; i<threadcount; i++) {
+            TestThread t = new TestThread();
+            t.setName("tomcat-pool-validate-"+i);
+            t.d = DataSourceFactory.getDataSource(this.datasource);
+            t.start();
+        }
+        latch.await();
+        long delta = System.currentTimeMillis() - start;
+        System.out.println("[testPoolThreads10Connections10Validate]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+        tearDown();
+    }
+
+    public void testDBCPThreads20Connections10Validate() throws Exception {
+        init();
+        this.datasource.getPoolProperties().setMaxActive(10);
+        this.datasource.getPoolProperties().setValidationQuery("SELECT 1");
+        this.datasource.getPoolProperties().setTestOnBorrow(true);
+        this.threadcount = 20;
+        this.transferProperties();
+        this.tDatasource.getConnection().close();
+        latch = new CountDownLatch(threadcount);
+        long start = System.currentTimeMillis();
+        for (int i=0; i<threadcount; i++) {
+            TestThread t = new TestThread();
+            t.setName("tomcat-dbcp-validate-"+i);
+            t.d = this.tDatasource;
+            t.start();
+        }
+        latch.await();
+        long delta = System.currentTimeMillis() - start;
+        System.out.println("[testDBCPThreads20Connections10Validate]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+        tearDown();
+    }
+
+    public void testPoolThreads10Connections20Validate() throws Exception {
+        init();
+        this.datasource.getPoolProperties().setMaxActive(10);
+        this.datasource.getPoolProperties().setValidationQuery("SELECT 1");
+        this.datasource.getPoolProperties().setTestOnBorrow(true);
+        this.threadcount = 20;
+        this.transferProperties();
+        this.datasource.getConnection().close();
+        latch = new CountDownLatch(threadcount);
+        long start = System.currentTimeMillis();
+        for (int i=0; i<threadcount; i++) {
+            TestThread t = new TestThread();
+            t.setName("tomcat-pool-validate-"+i);
+            t.d = DataSourceFactory.getDataSource(this.datasource);
+            t.start();
+        }
+        latch.await();
+        long delta = System.currentTimeMillis() - start;
+        System.out.println("[testPoolThreads20Connections10Validate]Test complete:"+delta+" ms. Iterations:"+(threadcount*this.iterations));
+        tearDown();
+    }
+
+    
+    public class TestThread extends Thread {
+        protected DataSource d;
+        
+        public void run() {
+            long max = -1, totalmax=0, totalcmax=0, cmax = -1, nroffetch = 0, totalruntime = 0;
+            try {
+                for (int i = 0; i < CheckOutThreadTest.this.iterations; i++) {
+                    long start = System.nanoTime();
+                    Connection con = null;
+                    try {
+                        con = d.getConnection();
+                        long delta = System.nanoTime() - start;
+                        totalmax += delta;
+                        max = Math.max(delta, max);
+                        nroffetch++;
+                    } finally {
+                        long cstart = System.nanoTime();
+                        if (con!=null) try {con.close();}catch(Exception x) {x.printStackTrace();}
+                        long cdelta = System.nanoTime() - cstart;
+                        totalcmax += cdelta;
+                        cmax = Math.max(cdelta, cmax);
+                    }
+                    totalruntime+=(System.nanoTime()-start);
+                }
+
+            } catch (Exception x) {
+                x.printStackTrace();
+            } finally {
+                CheckOutThreadTest.this.latch.countDown();
+            }
+            if (System.getProperty("print-thread-stats")!=null) {
+                System.out.println("["+getName()+"] "+
+                    "\n\tMax time to retrieve connection:"+(((float)max)/1000f/1000f)+" ms."+
+                    "\n\tTotal time to retrieve connection:"+(((float)totalmax)/1000f/1000f)+" ms."+
+                    "\n\tAverage time to retrieve connection:"+(((float)totalmax)/1000f/1000f)/(float)nroffetch+" ms."+
+                    "\n\tMax time to close connection:"+(((float)cmax)/1000f/1000f)+" ms."+
+                    "\n\tTotal time to close connection:"+(((float)totalcmax)/1000f/1000f)+" ms."+
+                    "\n\tAverage time to close connection:"+(((float)totalcmax)/1000f/1000f)/(float)nroffetch+" ms."+
+                    "\n\tRun time:"+(((float)totalruntime)/1000f/1000f)+" ms."+
+                    "\n\tNr of fetch:"+nroffetch);
+            }
+        }
+    }
+}

Added: tomcat/trunk/test/org/apache/tomcat/jdbc/test/DefaultProperties.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/jdbc/test/DefaultProperties.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/jdbc/test/DefaultProperties.java (added)
+++ tomcat/trunk/test/org/apache/tomcat/jdbc/test/DefaultProperties.java Wed Oct 22 22:14:50 2008
@@ -0,0 +1,63 @@
+/*
+ * 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.test;
+
+import java.util.Properties;
+
+import org.apache.tomcat.jdbc.pool.DataSourceFactory;
+import org.apache.tomcat.jdbc.pool.PoolProperties;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class DefaultProperties extends PoolProperties {
+    public DefaultProperties() {
+        dbProperties = new Properties();
+        url = "jdbc:mysql://localhost:3306/mysql?autoReconnect=true";
+        driverClassName = "com.mysql.jdbc.Driver";
+        password = "password";
+        username = "root";
+        defaultAutoCommit = true;
+        defaultReadOnly = false;
+        defaultTransactionIsolation = DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION;
+        connectionProperties = null;
+        defaultCatalog = null;
+        initialSize = 10;
+        maxActive = 100;
+        maxIdle = initialSize;
+        minIdle = initialSize;
+        maxWait = 10000;
+        validationQuery = "SELECT 1";
+        testOnBorrow = true;
+        testOnReturn = false;
+        testWhileIdle = true;
+        timeBetweenEvictionRunsMillis = 5000;
+        numTestsPerEvictionRun = 0;
+        minEvictableIdleTimeMillis = 1000;
+        accessToUnderlyingConnectionAllowed = false;
+        removeAbandoned = true;
+        removeAbandonedTimeout = 5000;
+        logAbandoned = true;
+        loginTimeout = 0;
+        validationInterval = 0; //always validate
+        initSQL = null;
+        testOnConnect = false;;
+        dbProperties.setProperty("user",username);
+        dbProperties.setProperty("password",password);
+    }
+}

Added: tomcat/trunk/test/org/apache/tomcat/jdbc/test/DefaultTestCase.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/jdbc/test/DefaultTestCase.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/jdbc/test/DefaultTestCase.java (added)
+++ tomcat/trunk/test/org/apache/tomcat/jdbc/test/DefaultTestCase.java Wed Oct 22 22:14:50 2008
@@ -0,0 +1,158 @@
+/*
+ * 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.test;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+import org.apache.tomcat.dbcp.dbcp.BasicDataSource;
+import org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory;
+
+import junit.framework.TestCase;
+import org.apache.tomcat.jdbc.pool.PoolProperties;
+import org.apache.tomcat.jdbc.pool.DataSourceProxy;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class DefaultTestCase extends TestCase {
+    protected DataSourceProxy datasource;
+    protected BasicDataSource tDatasource;
+    protected int threadcount = 10;
+    protected int iterations = 100000;
+    public DefaultTestCase(String name) {
+        super(name);
+    }
+
+    protected void init() throws Exception {
+        PoolProperties p = new DefaultProperties();
+        p.setJmxEnabled(false);
+        p.setTestWhileIdle(false);
+        p.setTestOnBorrow(false);
+        p.setTestOnReturn(false);
+        p.setValidationInterval(30000);
+        p.setTimeBetweenEvictionRunsMillis(30000);
+        p.setMaxActive(threadcount);
+        p.setInitialSize(threadcount);
+        p.setMaxWait(10000);
+        p.setRemoveAbandonedTimeout(10000);
+        p.setMinEvictableIdleTimeMillis(10000);
+        p.setMinIdle(threadcount);
+        p.setLogAbandoned(false);
+        p.setRemoveAbandoned(false);
+        datasource = new org.apache.tomcat.jdbc.pool.DataSourceProxy();
+        datasource.setPoolProperties(p);
+    }
+
+    protected void transferProperties() {
+        try {
+            BasicDataSourceFactory factory = new BasicDataSourceFactory();
+            Properties p = new Properties();
+
+            for (int i=0; i<this.ALL_PROPERTIES.length; i++) {
+                String name = "get" + Character.toUpperCase(ALL_PROPERTIES[i].charAt(0)) + ALL_PROPERTIES[i].substring(1);
+                String bname = "is" + name.substring(3);
+                Method get = null;
+                try {
+                    get = PoolProperties.class.getMethod(name, new Class[0]);
+                }catch (NoSuchMethodException x) {
+                    try {
+                    get = PoolProperties.class.getMethod(bname, new Class[0]);
+                    }catch (NoSuchMethodException x2) {
+                        System.err.println(x2.getMessage());
+                    }
+                }
+                   if (get!=null) {
+                       Object value = get.invoke(datasource.getPoolProperties(), new Object[0]);
+                       if (value!=null) {
+                           p.setProperty(ALL_PROPERTIES[i], value.toString());
+                       }
+                }
+            }
+            tDatasource = (BasicDataSource)factory.createDataSource(p);
+        }catch (Exception x) {
+            x.printStackTrace();
+        }
+    }
+
+
+    protected void tearDown() throws Exception {
+        datasource = null;
+        tDatasource = null;
+        System.gc();
+    }
+
+    private final static String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
+    private final static String PROP_DEFAULTREADONLY = "defaultReadOnly";
+    private final static String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
+    private final static String PROP_DEFAULTCATALOG = "defaultCatalog";
+    private final static String PROP_DRIVERCLASSNAME = "driverClassName";
+    private final static String PROP_MAXACTIVE = "maxActive";
+    private final static String PROP_MAXIDLE = "maxIdle";
+    private final static String PROP_MINIDLE = "minIdle";
+    private final static String PROP_INITIALSIZE = "initialSize";
+    private final static String PROP_MAXWAIT = "maxWait";
+    private final static String PROP_TESTONBORROW = "testOnBorrow";
+    private final static String PROP_TESTONRETURN = "testOnReturn";
+    private final static String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";
+    private final static String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";
+    private final static String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";
+    private final static String PROP_TESTWHILEIDLE = "testWhileIdle";
+    private final static String PROP_PASSWORD = "password";
+    private final static String PROP_URL = "url";
+    private final static String PROP_USERNAME = "username";
+    private final static String PROP_VALIDATIONQUERY = "validationQuery";
+    private final static String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
+    private final static String PROP_REMOVEABANDONED = "removeAbandoned";
+    private final static String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";
+    private final static String PROP_LOGABANDONED = "logAbandoned";
+    private final static String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
+    private final static String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
+    private final static String PROP_CONNECTIONPROPERTIES = "connectionProperties";
+
+    private 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_PASSWORD,
+        PROP_URL,
+        PROP_USERNAME,
+        PROP_VALIDATIONQUERY,
+        PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED,
+        PROP_REMOVEABANDONED,
+        PROP_REMOVEABANDONEDTIMEOUT,
+        PROP_LOGABANDONED,
+        PROP_CONNECTIONPROPERTIES
+    };
+
+
+
+}

Added: tomcat/trunk/test/org/apache/tomcat/jdbc/test/TestGCClose.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/jdbc/test/TestGCClose.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/jdbc/test/TestGCClose.java (added)
+++ tomcat/trunk/test/org/apache/tomcat/jdbc/test/TestGCClose.java Wed Oct 22 22:14:50 2008
@@ -0,0 +1,35 @@
+/*
+ * 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.test;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class TestGCClose extends DefaultTestCase {
+    public TestGCClose(String name) {
+        super(name);
+    }
+    
+    public void testGCStop() throws Exception {
+        init();
+        datasource.getConnection();
+        System.out.println("Got a connection, but didn't return it");
+        tearDown();
+        Thread.sleep(10000);
+    }
+}

Added: tomcat/trunk/test/org/apache/tomcat/jdbc/test/TestTimeout.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/jdbc/test/TestTimeout.java?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/jdbc/test/TestTimeout.java (added)
+++ tomcat/trunk/test/org/apache/tomcat/jdbc/test/TestTimeout.java Wed Oct 22 22:14:50 2008
@@ -0,0 +1,92 @@
+/*
+ * 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.test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class TestTimeout extends DefaultTestCase {
+    public TestTimeout(String name) {
+        super(name);
+    }
+
+    AtomicInteger counter = new AtomicInteger(0);
+
+    public void testCheckoutTimeout() throws Exception {
+        try {
+            init();
+            this.datasource.getPoolProperties().setTestWhileIdle(true);
+            this.datasource.getPoolProperties().setTestOnBorrow(false);
+            this.datasource.getPoolProperties().setTestOnReturn(false);
+            this.datasource.getPoolProperties().setValidationInterval(30000);
+            this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(1000);
+            this.datasource.getPoolProperties().setMaxActive(20);
+            this.datasource.getPoolProperties().setMaxWait(3000);
+            this.datasource.getPoolProperties().setRemoveAbandonedTimeout(5000);
+            this.datasource.getPoolProperties().setMinEvictableIdleTimeMillis(5000);
+            this.datasource.getPoolProperties().setMinIdle(5);
+            this.datasource.getPoolProperties().setLogAbandoned(true);
+            System.out.println("About to test connection pool:"+datasource);
+            for (int i = 0; i < 21; i++) {
+                long now = System.currentTimeMillis();
+                this.datasource.getConnection();
+                long delta = System.currentTimeMillis()-now;
+                System.out.println("Got connection #"+i+" in "+delta+" ms.");
+            }
+        } catch ( Exception x ) {
+            x.printStackTrace();
+        }finally {
+            Thread.sleep(20000);
+            tearDown();
+        }
+    }
+
+    public void testRemoveAbandoned() throws Exception {
+        try {
+            init();
+            this.datasource.getPoolProperties().setTestWhileIdle(true);
+            this.datasource.getPoolProperties().setTestOnBorrow(false);
+            this.datasource.getPoolProperties().setTestOnReturn(false);
+            this.datasource.getPoolProperties().setValidationInterval(30000);
+            this.datasource.getPoolProperties().setTimeBetweenEvictionRunsMillis(1000);
+            this.datasource.getPoolProperties().setMaxActive(20);
+            this.datasource.getPoolProperties().setMaxWait(3000);
+            this.datasource.getPoolProperties().setRemoveAbandonedTimeout(5000);
+            this.datasource.getPoolProperties().setMinEvictableIdleTimeMillis(5000);
+            this.datasource.getPoolProperties().setMinIdle(5);
+            this.datasource.getPoolProperties().setRemoveAbandoned(true);
+            this.datasource.getPoolProperties().setLogAbandoned(true);
+            System.out.println("About to test connection pool:"+datasource);
+            for (int i = 0; i < threadcount; i++) {
+                long now = System.currentTimeMillis();
+                this.datasource.getConnection();
+                long delta = System.currentTimeMillis()-now;
+                System.out.println("Got connection #"+i+" in "+delta+" ms.");
+            }
+        } catch ( Exception x ) {
+            x.printStackTrace();
+        }finally {
+            Thread.sleep(20000);
+            tearDown();
+        }
+    }
+
+
+}

Added: tomcat/trunk/webapps/docs/config/jdbc-pool.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/jdbc-pool.xml?rev=707275&view=auto
==============================================================================
--- tomcat/trunk/webapps/docs/config/jdbc-pool.xml (added)
+++ tomcat/trunk/webapps/docs/config/jdbc-pool.xml Wed Oct 22 22:14:50 2008
@@ -0,0 +1,298 @@
+<?xml version="1.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.
+-->
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="http.html">
+
+  &project;
+
+  <properties>
+    <author email="fhanik@apache.org">Filip Hanik</author>
+    <title>The Tomcat JDBC Connection Pool</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>JDBC Connection Pool <code>org.apache.tomcat.jdbc.pool</code></strong> 
+  is a replacement or an alternative to the <a href="http://commons.apache.org/dbcp/">commons-dbcp</a>
+  connection pool.</p>
+
+  <p>So why do we need a new connection pool?</p>
+
+  <p>Here are a few of the reasons:
+    <ol>
+      <li>commons-dbcp is single threaded, in order to be thread safe commons-dbcp looks the entire pool, even during query validation</li>
+      <li>commons-dbcp is slow - as the number of logical CPUs grow, the performance suffers, the above point shows that there is not support for high concurrency</li>
+      <li>commons-dbcp is complex, over 60 classes. tomcat-jdbc-pool, is 8 classes, hence modifications for future requirement will require
+          much less changes.</li>
+      <li>commons-dbcp uses static interfaces. This means you can't compile it with JDK 1.6, or if you run on JDK 1.6/1.7 you will get 
+          NoSuchMethodException for all the methods not implemented, even if the driver supports.  </li>
+      <li>The commons-dbcp has become fairly stagnant. Sparse updates, releases, and new feature support.</li>
+      <li>It's not worth rewriting over 60 classes, when something as a connection pool can be accomplished with as a much simpler implementation.</li> 
+      <li>Tomcat jdbc pool is a Tomcat module, it depends on Tomcat JULI, a greatly simplified logging framework used in Tomcat</li>
+    </ol>
+  </p>
+
+  <p>Features added over other connection pool implementations
+    <ol>
+      <li>Support for highly concurrent environments and multi core/cpu systems</li>
+      <li>Dynamic implementation of interface, will support java.sql and javax.sql interfaces for 
+          your runtime environment (as long as your JDBC driver does the same), even when compiled with a lower JDK</li>
+      <li>Validation intervals - we don't have to validate every single time we use the connection, we can do this 
+          when we borrow or return the connection, just not more frequent than an interval we can configure.</li>
+      <li>Run-Once query, a configurable query that will be run only once, when the connection to the database is established.
+          Very useful to setup session settings, that you want to exist during the entire time the connection is established.</li>
+      <li>Ability to configure custom interceptors.
+          This allows you to write custom interceptors to enhance the functionality. You can use interceptors to gather query stats,
+          cache session states, reconnect the connection upon failures, retry queries, cache query results, and so on. 
+          Your options are endless and the interceptors are dynamic, not tied to a JDK version of a java.sql/javax.sql interface.</li>
+      <li>High performance - we will show some differences in performance later on</li>
+      <li>Extremely simple, due to the very simplified implementation, the line count and source file count are very low, compare with c3p0 
+          that has over 200 source files(last time we checked), Tomcat jdbc has a core of 8 files, the connection pool itself is about half 
+          that.</li>
+    </ol>
+  </p>
+
+
+</section>
+
+
+<section name="Attributes">
+  <p>To provide a very simple switch to and from commons-dbcp and tomcat-jdbc-pool,
+     Most attributes are the same and have the same meaning.</p>
+
+
+  <subsection name="JNDI Factory and Type">
+    <attributes>
+      <attribute name="factory" required="true">
+        <p>factory is required, and the value should be <code>org.apache.tomcat.jdbc.poo.DataSourceFactory</code></p>
+      </attribute>
+      <attribute name="type" required="true">
+        <p>Type should always be <code>javax.sql.DataSource</code></p>
+      </attribute>
+    </attributes>
+  </subsection>
+
+  <subsection name="Common Attributes">
+  <p>These attributes are shared between commons-dbcp and tomcat-jdbc-pool, in some cases default values are different.</p>
+  <attributes>
+ 
+    <attribute name="defaultAutoCommit" required="false">
+      <p>(boolean) The default auto-commit state of connections created by this pool. If not set, default is JDBC driver default (If not set then the setAutoCommit method will not be called.)</p>
+    </attribute>
+
+    <attribute name="defaultReadOnly" required="false">
+      <p>(boolean) The default read-only state of connections created by this pool. If not set then the setReadOnly method will not be called. (Some drivers don't support read only mode, ex: Informix)</p>
+    </attribute>
+
+    <attribute name="defaultTransactionIsolation" required="false">
+      <p>(String) The default TransactionIsolation state of connections created by this pool. One of the following: (see javadoc )<br/>
+         * NONE<br/>
+         * READ_COMMITTED<br/>
+         * READ_UNCOMMITTED<br/>
+         * REPEATABLE_READ<br/>
+         * SERIALIZABLE<br/>
+         If not set, the method will not be called and it defaults to the JDBC driver.
+      </p>
+    </attribute>
+
+    <attribute name="defaultCatalog" required="false">
+      <p>(String) The default catalog of connections created by this pool.</p>
+    </attribute>
+
+    <attribute name="driverClassName" required="true">
+      <p>(String) The fully qualified Java class name of the JDBC driver to be used. The driver has to be accessible
+         from the same classloader as tomcat-jdbc.jar 
+      </p>
+    </attribute>
+
+    <attribute name="username" required="true">
+      <p>(String) The connection username to be passed to our JDBC driver to establish a connection.
+         Note, at this point, <code>DataSource.getConnection(username,password)</code> is not using the credentials passed into the method.
+      </p>
+    </attribute>
+
+    <attribute name="password" required="true">
+      <p>(String) The connection password to be passed to our JDBC driver to establish a connection.
+         Note, at this point, <code>DataSource.getConnection(username,password)</code> is not using the credentials passed into the method.
+      </p>
+    </attribute>
+
+    <attribute name="maxActive" required="false">
+      <p>(int) The maximum number of active connections that can be allocated from this pool at the same time.
+         The default value is <code>100</code></p>
+    </attribute>
+
+    <attribute name="maxIdle" required="false">
+      <p>(int) The maximum number of connections that should be kept in the pool at all times. 
+         Default value is  <code>maxActive</code>:<code>100</code>
+         Idle connections are checked periodically (if enabled) and 
+         connections that been idle for longer than <code>minEvictableIdleTimeMillis</code> 
+         will be released. (also see <code>testWhileIdle</code>)</p>
+    </attribute>
+
+    <attribute name="minIdle" required="false">
+      <p>
+        (int) The minimum number of established connections that should be kept in the pool at all times.
+        The connection pool can shrink below this number if validation queries fail.
+        Default value is derived from <code>initialSize</code>:<code>10</code> (also see <code>testWhileIdle</code>)
+      </p>
+    </attribute>
+
+    <attribute name="initialSize" required="false">
+      <p>(int)The initial number of connections that are created when the pool is started.
+         Default value is <code>10</code></p>
+    </attribute>
+
+    <attribute name="maxWait" required="false">
+      <p>(long) The maximum number of milliseconds that the pool will wait (when there are no available connections) 
+         for a connection to be returned before throwing an exception. 
+         Default value is <code>30000</code> (30 seconds)</p>
+    </attribute>
+
+    <attribute name="testOnBorrow" required="false">
+      <p>(boolean) The indication of whether objects will be validated before being borrowed from the pool. 
+         If the object fails to validate, it will be dropped from the pool, and we will attempt to borrow another.
+         NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string.
+         Default value is <code>false</code>
+      </p>
+    </attribute>
+
+    <attribute name="testOnReturn" required="false">
+      <p>(boolean) The indication of whether objects will be validated before being returned to the pool.
+         NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string.
+         The default value is <code>false</code>.
+      </p>
+    </attribute>
+
+    <attribute name="testWhileIdle" required="false">
+      <p>(boolean) The indication of whether objects will be validated by the idle object evictor (if any). 
+         If an object fails to validate, it will be dropped from the pool.
+         NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string.
+         The default value is <code>false</code> and this property has to be set in order for the 
+         pool cleaner/test thread is to run (also see <code>timeBetweenEvictionRunsMillis</code>)
+      </p>
+    </attribute>
+
+    <attribute name="validationQuery" required="false">
+      <p>(String) The SQL query that will be used to validate connections from this pool before returning them to the caller. 
+         If specified, this query does not have to return any data, it just can't throw a SQLException.  
+         The default value is <code>null</code>.
+         Example values are <code>SELECT 1</code>(mysql), <code>select 1 from dual</code>(oracle), <code>SELECT 1</code>(MS Sql Server)
+      </p>
+    </attribute>
+    
+    <attribute name="timeBetweenEvictionRunsMillis" required="false">
+      <p>(long) The number of milliseconds to sleep between runs of the idle connection validation/cleaner thread. 
+         This value should not be set under 1 second. It dictates how often we check for idle, abandoned connections, and how often 
+         we validate idle connections.
+         The default value is <code>5000</code> (5 seconds).</p>
+    </attribute>
+
+    <attribute name="numTestsPerEvictionRun" required="false">
+      <p>(int) Property not used in tomcat-jdbc-pool.</p>
+    </attribute>
+
+    <attribute name="minEvictableIdleTimeMillis" required="false">
+      <p>(long) The minimum amount of time an object may sit idle in the pool before it is eligable for eviction. 
+         The default value is <code>60000</code> (60 seconds).</p>
+    </attribute>
+
+    <attribute name="accessToUnderlyingConnectionAllowed" required="false">
+      <p>(boolean) Property not used. Access can be achieved by calling <code>unwrap</code> on the pooled connection.
+         see <code>javax.sql.DataSource</code> interface, or call <code>getConnection</code> through reflection.</p>
+    </attribute>
+
+    <attribute name="removeAbandoned" required="false">
+      <p>(boolean) Flag to remove abandoned connections if they exceed the <code>removeAbandonedTimout</code>.
+         If set to true a connection is considered abandoned and eligible for removal if it has been in use 
+         longer than the <code>removeAbandonedTimeout</code> Setting this to true can recover db connections from 
+         applications that fail to close a connection. See also <code>logAbandoned</code>
+         The default value is <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="removeAbandonedTimeout" required="false">
+      <p>(long) Timeout in seconds before an abandoned(in use) connection can be removed. 
+         The default value is <code>60</code> (60 seconds). The value should be set to the longest running query your applications 
+         might have.</p>
+    </attribute>
+
+    <attribute name="logAbandoned" required="false">
+      <p>(boolean) Flag to log stack traces for application code which abandoned a Connection.
+         Logging of abandoned Connections adds overhead for every Connection borrow because a stack trace has to be generated.
+         The default value is <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="connectionProperties" required="false">
+      <p>(String) The connection properties that will be sent to our JDBC driver when establishing new connections.
+         Format of the string must be [propertyName=property;]*
+         NOTE - The "user" and "password" properties will be passed explicitly, so they do not need to be included here. 
+         The default value is <code>null</code>.</p>
+    </attribute>
+
+    <attribute name="poolPreparedStatements" required="false">
+      <p>(boolean) Property not used. The default value is <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="maxOpenPreparedStatements" required="false">
+      <p>(int) Property not used. The default value is <code>false</code>.</p>
+    </attribute>
+   
+
+
+  </attributes>
+
+  </subsection>
+
+  <subsection name="Tomcat JDBC Enhanced Attributes">
+
+  <attributes>
+
+    <attribute name="initSQL" required="false">
+      <p>(String) A custom query to be run when a connection is first created. 
+         The default value is <code>null</code>.</p>
+    </attribute>
+
+    <attribute name="jdbcInterceptors" required="false">
+      <p>(String) A semicolon separated list of classnames extending <code>org.apache.tomcat.jdbc.pool.JdbcInterceptor</code> class.
+         These interceptors will be inserted as an interceptor into the chain of operations on a <code>java.sql.Connection</code> object.
+         The default value is <code>null</code>.</p>
+    </attribute>
+
+    <attribute name="validationInterval" required="false">
+      <p>(long) avoid excess validation, only run validation at most at this frequency - time in milliseconds.
+         If a connection is due for validation, but has been validated previously within this interval, it will not be validated again. 
+         The default value is <code>30000</code> (30 seconds).</p>
+    </attribute>
+
+    <attribute name="jmxEnabled" required="false">
+      <p>(boolean) Register the pool with JMX or not. 
+         The default value is <code>true</code>.</p>
+    </attribute>
+  </attributes>  
+  </subsection>
+</section>
+
+
+</body>
+
+</document>



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


Mime
View raw message